]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
This commit was generated by cvs2svn to compensate for changes in r2,
[cc65] / src / ca65 / macro.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  macro.c                                  */
4 /*                                                                           */
5 /*                    Macros for the ca65 macroassembler                     */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "../common/hashstr.h"
40
41 #include "mem.h"
42 #include "error.h"
43 #include "scanner.h"
44 #include "toknode.h"
45 #include "pseudo.h"
46 #include "macro.h"
47
48
49
50 /*****************************************************************************/
51 /*                                   Data                                    */
52 /*****************************************************************************/
53
54
55
56 /* Struct that describes an identifer (macro param, local list) */
57 typedef struct IdDesc_ IdDesc;
58 struct IdDesc_ {
59     IdDesc*         Next;       /* Linked list */
60     char            Id [1];     /* Identifier, dynamically allocated */
61 };
62
63
64
65 /* Struct that describes a macro definition */
66 typedef struct Macro_ Macro;
67 struct Macro_ {
68     Macro*          Next;       /* Next macro with same hash */
69     Macro*          List;       /* List of all macros */
70     unsigned        LocalCount; /* Count of local symbols */
71     IdDesc*         Locals;     /* List of local symbols */
72     unsigned        ParamCount; /* Parameter count of macro */
73     IdDesc*         Params;     /* Identifiers of macro parameters */
74     unsigned        TokCount;   /* Number of tokens for this macro */
75     TokNode*        TokRoot;    /* Root of token list */
76     TokNode*        TokLast;    /* Pointer to last token in list */
77     unsigned char   Style;      /* Macro style */
78     char            Name [1];   /* Macro name, dynamically allocated */
79 };
80
81 /* Macro hash table */
82 #define HASHTAB_SIZE            117
83 static Macro*   MacroTab [HASHTAB_SIZE];
84
85 /* Global macro data */
86 static Macro*   MacroRoot = 0;  /* List of all macros */
87
88 /* Structs that holds data for a macro expansion */
89 typedef struct MacExp_ MacExp;
90 struct MacExp_ {
91     MacExp*     Next;           /* Pointer to next expansion */
92     Macro*      M;              /* Which macro do we expand? */
93     TokNode*    Exp;            /* Pointer to current token */
94     TokNode*    Final;          /* Pointer to final token */
95     unsigned    LocalStart;     /* Start of counter for local symbol names */
96     unsigned    ParamCount;     /* Number of actual parameters */
97     TokNode**   Params;         /* List of actual parameters */
98     TokNode*    ParamExp;       /* Node for expanding parameters */
99 };
100
101 /* Data for macro expansions */
102 #define MAX_MACRO_EXPANSIONS    255
103 static unsigned MacroNesting    = 0;
104 static MacExp*  CurMac          = 0;
105 static unsigned LocalName       = 0;
106
107
108
109 /*****************************************************************************/
110 /*                                   Code                                    */
111 /*****************************************************************************/
112
113
114
115 static IdDesc* NewIdDesc (const char* Id)
116 /* Create a new IdDesc, initialize and return it */
117 {
118     /* Allocate memory */
119     unsigned Len = strlen (Id);
120     IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
121
122     /* Initialize the struct */
123     I->Next = 0;
124     memcpy (I->Id, Id, Len);
125     I->Id [Len] = '\0';
126
127     /* Return the new struct */
128     return I;
129 }
130
131
132
133 static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
134 /* Generate a new macro entry, initialize and return it */
135 {
136     /* Allocate memory */
137     unsigned Len = strlen (Name);
138     Macro* M = Xmalloc (sizeof (Macro) + Len);
139
140     /* Initialize the macro struct */
141     M->LocalCount = 0;
142     M->ParamCount = 0;
143     M->Params     = 0;
144     M->TokCount   = 0;
145     M->TokRoot    = 0;
146     M->TokLast    = 0;
147     M->Style      = Style;
148     memcpy (M->Name, Name, Len);
149     M->Name [Len] = '\0';
150
151     /* Insert the macro into the global macro list */
152     M->List = MacroRoot;
153     MacroRoot = M;
154
155     /* Insert the macro into the hash table */
156     M->Next = MacroTab [HashVal];
157     MacroTab [HashVal] = M;
158
159     /* Return the new macro struct */
160     return M;
161 }
162
163
164
165 static MacExp* NewMacExp (Macro* M)
166 /* Create a new expansion structure for the given macro */
167 {
168     unsigned I;
169
170     /* Allocate memory */
171     MacExp* E = Xmalloc (sizeof (MacExp));
172
173     /* Initialize the data */
174     E->M          = M;
175     E->Exp        = M->TokRoot;
176     E->Final      = 0;
177     E->LocalStart = LocalName;
178     LocalName    += M->LocalCount;
179     E->ParamCount = 0;
180     E->Params     = Xmalloc (M->ParamCount * sizeof (TokNode*));
181     E->ParamExp   = 0;
182     for (I = 0; I < M->ParamCount; ++I) {
183         E->Params [I] = 0;
184     }
185
186     /* And return it... */
187     return E;
188 }
189
190
191
192 static void MacInsertExp (MacExp* E)
193 /* Insert a macro expansion into the list */
194 {
195     E->Next = CurMac;
196     CurMac  = E;
197     ++MacroNesting;
198 }
199
200
201
202 static void FreeMacExp (void)
203 /* Remove and free the current macro expansion */
204 {
205     unsigned I;
206     MacExp* E;
207
208     /* Free the parameter list */
209     for (I = 0; I < CurMac->ParamCount; ++I) {
210         Xfree (CurMac->Params [I]);
211     }
212     Xfree (CurMac->Params);
213
214     /* Free the final token if we have one */
215     if (CurMac->Final) {
216         FreeTokNode (CurMac->Final);
217     }
218
219     /* Reset the list pointer */
220     E = CurMac;
221     CurMac = E->Next;
222     --MacroNesting;
223
224     /* Free the structure itself */
225     Xfree (E);
226 }
227
228
229
230 static void MacSkipDef (unsigned Style)
231 /* Skip a macro definition */
232 {
233     if (Style == MAC_STYLE_CLASSIC) {
234         /* Skip tokens until we reach the final .endmacro */
235         while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
236             NextTok ();
237         }
238         if (Tok != TOK_EOF) {
239             SkipUntilSep ();
240         } else {
241             Error (ERR_ENDMACRO_EXPECTED);
242         }
243     } else {
244         /* Skip until end of line */
245         SkipUntilSep ();
246     }
247 }
248
249
250
251 static Macro* MacFind (const char* Name, unsigned HashVal)
252 /* Search for a macro in the hash table */
253 {
254     /* Search for the identifier */
255     Macro* M = MacroTab [HashVal];
256     while (M) {
257         if (strcmp (Name, M->Name) == 0) {
258             return M;
259         }
260         M = M->Next;
261     }
262     return 0;
263 }
264
265
266
267 void MacDef (unsigned Style)
268 /* Parse a macro definition */
269 {
270     Macro* M;
271     TokNode* T;
272     unsigned HashVal;
273     int HaveParams;
274
275     /* We expect a macro name here */
276     if (Tok != TOK_IDENT) {
277         Error (ERR_IDENT_EXPECTED);
278         MacSkipDef (Style);
279         return;
280     }
281
282     /* Generate the hash value */
283     HashVal = HashStr (SVal) % HASHTAB_SIZE;
284
285     /* Did we already define that macro? */
286     if (MacFind (SVal, HashVal) != 0) {
287         /* Macro is already defined */
288         Error (ERR_SYM_ALREADY_DEFINED, SVal);
289         /* Skip tokens until we reach the final .endmacro */
290         MacSkipDef (Style);
291         return;
292     }
293
294     /* Define the macro */
295     M = NewMacro (SVal, HashVal, Style);
296     NextTok ();
297
298     /* If we have a DEFINE style macro, we may have parameters in braces,
299      * otherwise we may have parameters without braces.
300      */
301     if (Style == MAC_STYLE_CLASSIC) {
302         HaveParams = 1;
303     } else {
304         if (Tok == TOK_LPAREN) {
305             HaveParams = 1;
306             NextTok ();
307         } else {
308             HaveParams = 0;
309         }
310     }
311
312     /* Parse the parameter list */
313     if (HaveParams) {
314
315         while (Tok == TOK_IDENT) {
316
317             /* Create a struct holding the identifier */
318             IdDesc* I = NewIdDesc (SVal);
319
320             /* Insert the struct into the list, checking for duplicate idents */
321             if (M->ParamCount == 0) {
322                 M->Params = I;
323             } else {
324                 IdDesc* List = M->Params;
325                 while (1) {
326                     if (strcmp (List->Id, SVal) == 0) {
327                         Error (ERR_SYM_ALREADY_DEFINED, SVal);
328                     }
329                     if (List->Next == 0) {
330                         break;
331                     } else {
332                         List = List->Next;
333                     }
334                 }
335                 List->Next = I;
336             }
337             ++M->ParamCount;
338
339             /* Skip the name */
340             NextTok ();
341
342             /* Maybe there are more params... */
343             if (Tok == TOK_COMMA) {
344                 NextTok ();
345             } else {
346                 break;
347             }
348         }
349     }
350
351     /* For class macros, we expect a separator token, for define style macros,
352      * we expect the closing paren.
353      */
354     if (Style == MAC_STYLE_CLASSIC) {
355         ConsumeSep ();
356     } else if (HaveParams) {
357         ConsumeRParen ();
358     }
359
360     /* Preparse the macro body. We will read the tokens until we reach end of
361      * file, or a .endmacro (or end of line for DEFINE style macros) and store
362      * them into an token list internal to the macro. For classic macros, there
363      * the .LOCAL command is detected and removed at this time.
364      */
365     while (1) {
366
367         /* Check for end of macro */
368         if (Style == MAC_STYLE_CLASSIC) {
369             /* In classic macros, only .endmacro is allowed */
370             if (Tok == TOK_ENDMACRO) {
371                 /* Done */
372                 break;
373             }
374             /* May not have end of file in a macro definition */
375             if (Tok == TOK_EOF) {
376                 Error (ERR_ENDMACRO_EXPECTED);
377                 return;
378             }
379         } else {
380             /* Accept a newline or end of file for new style macros */
381             if (Tok == TOK_SEP || Tok == TOK_EOF) {
382                 break;
383             }
384         }
385
386         /* Check for a .LOCAL declaration */
387         if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
388
389             while (1) {
390
391                 IdDesc* I;
392
393                 /* Skip .local or comma */
394                 NextTok ();
395
396                 /* Need an identifer */
397                 if (Tok != TOK_IDENT) {
398                     Error (ERR_IDENT_EXPECTED);
399                     SkipUntilSep ();
400                     break;
401                 }
402
403                 /* Put the identifier into the locals list and skip it */
404                 I = NewIdDesc (SVal);
405                 I->Next = M->Locals;
406                 M->Locals = I;
407                 ++M->LocalCount;
408                 NextTok ();
409
410                 /* Check for end of list */
411                 if (Tok != TOK_COMMA) {
412                     break;
413                 }
414
415             }
416
417             /* We need end of line after the locals */
418             ConsumeSep ();
419             continue;
420         }
421
422         /* Create a token node for the current token */
423         T = NewTokNode ();
424
425         /* If the token is an ident, check if it is a local parameter */
426         if (Tok == TOK_IDENT) {
427             unsigned Count = 0;
428             IdDesc* I = M->Params;
429             while (I) {
430                 if (strcmp (I->Id, SVal) == 0) {
431                     /* Local param name, replace it */
432                     T->Tok  = TOK_MACPARAM;
433                     T->IVal = Count;
434                     break;
435                 }
436                 ++Count;
437                 I = I->Next;
438             }
439         }
440
441         /* Insert the new token in the list */
442         if (M->TokCount == 0) {
443             /* First token */
444             M->TokRoot = M->TokLast = T;
445         } else {
446             /* We have already tokens */
447             M->TokLast->Next = T;
448             M->TokLast = T;
449         }
450         ++M->TokCount;
451
452         /* Read the next token */
453         NextTok ();
454     }
455
456     /* Skip the .endmacro for a classic macro */
457     if (Style == MAC_STYLE_CLASSIC) {
458         NextTok ();
459     }
460 }
461
462
463
464 static void StartExpClassic (Macro* M)
465 /* Start expanding the classic macro M */
466 {
467     MacExp* E;
468
469     /* Skip the macro name */
470     NextTok ();
471
472     /* Create a structure holding expansion data */
473     E = NewMacExp (M);
474
475     /* Read the actual parameters */
476     while (Tok != TOK_SEP && Tok != TOK_EOF) {
477
478         TokNode* Last;
479
480         /* Check for maximum parameter count */
481         if (E->ParamCount >= M->ParamCount) {
482             Error (ERR_TOO_MANY_PARAMS);
483             SkipUntilSep ();
484             break;
485         }
486
487         /* Read tokens for one parameter, accept empty params */
488         Last = 0;
489         while (Tok != TOK_COMMA && Tok != TOK_SEP) {
490
491             TokNode* T;
492
493             /* Check for end of file */
494             if (Tok == TOK_EOF) {
495                 Error (ERR_SYNTAX);
496                 return;
497             }
498
499             /* Get the next token in a node */
500             T = NewTokNode ();
501
502             /* Insert it into the list */
503             if (Last == 0) {
504                 E->Params [E->ParamCount] = T;
505             } else {
506                 Last->Next = T;
507             }
508             Last = T;
509
510             /* And skip it... */
511             NextTok ();
512         }
513
514         /* One parameter more */
515         ++E->ParamCount;
516
517         /* Check for a comma */
518         if (Tok == TOK_COMMA) {
519             NextTok ();
520         } else {
521             break;
522         }
523     }
524
525     /* Insert the newly created structure into the expansion list */
526     MacInsertExp (E);
527 }
528
529
530
531 static void StartExpDefine (Macro* M)
532 /* Start expanding a DEFINE style macro */
533 {
534     /* Create a structure holding expansion data */
535     MacExp* E = NewMacExp (M);
536
537     /* A define style macro must be called with as many actual parameters
538      * as there are formal ones. Get the parameter count.
539      */
540     unsigned Count = M->ParamCount;
541
542     /* Skip the current token */
543     NextTok ();
544
545     /* Read the actual parameters */
546     while (Count--) {
547
548         TokNode* Last;
549
550         /* Check if there is really a parameter */
551         if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
552             Error (ERR_MACRO_PARAM_EXPECTED);
553             SkipUntilSep ();
554             return;
555         }
556
557         /* Read tokens for one parameter */
558         Last = 0;
559         do {
560
561             TokNode* T;
562
563             /* Get the next token in a node */
564             T = NewTokNode ();
565
566             /* Insert it into the list */
567             if (Last == 0) {
568                 E->Params [E->ParamCount] = T;
569             } else {
570                 Last->Next = T;
571             }
572             Last = T;
573
574             /* And skip it... */
575             NextTok ();
576
577         } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
578
579         /* One parameter more */
580         ++E->ParamCount;
581
582         /* Check for a comma */
583         if (Count > 0) {
584             if (Tok == TOK_COMMA) {
585                 NextTok ();
586             } else {
587                 Error (ERR_COMMA_EXPECTED);
588             }
589         }
590     }
591
592     /* Macro expansion will overwrite the current token. This is a problem
593      * for define style macros since these are called from the scanner level.
594      * To avoid it, remember the current token and re-insert it if macro
595      * expansion is done.
596      */
597     E->Final = NewTokNode ();
598
599     /* Insert the newly created structure into the expansion list */
600     MacInsertExp (E);
601 }
602
603
604
605 void MacExpandStart (void)
606 /* Start expanding the macro in SVal */
607 {
608     Macro* M;
609
610     /* Beware of runoff macros */
611     if (MacroNesting == MAX_MACRO_EXPANSIONS) {
612         Fatal (FAT_MACRO_NESTING);
613     }
614
615     /* Search for the macro */
616     M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
617     CHECK (M != 0);
618
619     /* Call the apropriate subroutine */
620     switch (M->Style) {
621         case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
622         case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
623         default:                Internal ("Invalid macro style: %d", M->Style);
624     }
625 }
626
627
628
629 int MacExpand (void)
630 /* If we're currently expanding a macro, set the the scanner token and
631  * attribute to the next value and return true. If we are not expanding
632  * a macro, return false.
633  */
634 {
635     if (MacroNesting == 0) {
636         /* Not expanding a macro */
637         return 0;
638     }
639
640     /* We're expanding a macro. Check if we are expanding one of the
641      * macro parameters.
642      */
643     if (CurMac->ParamExp) {
644
645         /* Ok, use token from parameter list */
646         TokSet (CurMac->ParamExp);
647
648         /* Set pointer to next token */
649         CurMac->ParamExp = CurMac->ParamExp->Next;
650
651         /* Done */
652         return 1;
653
654     } else if (CurMac->Exp) {
655
656         /* We're not expanding a parameter, use next macro token */
657         TokSet (CurMac->Exp);
658
659         /* Set pointer to next token */
660         CurMac->Exp = CurMac->Exp->Next;
661
662         /* Is it a request for actual parameter count? */
663         if (Tok == TOK_PARAMCOUNT) {
664             Tok  = TOK_INTCON;
665             IVal = CurMac->ParamCount;
666             return 1;
667         }
668
669         /* Is it an .exitmacro command? */
670         if (Tok == TOK_EXITMACRO) {
671             /* Forced exit from macro expansion */
672             FreeMacExp ();
673             return MacExpand ();
674         }
675
676         /* Is it the name of a macro parameter? */
677         if (Tok == TOK_MACPARAM) {
678
679             /* Start to expand the parameter token list */
680             CurMac->ParamExp = CurMac->Params [IVal];
681
682             /* Recursive call to expand the parameter */
683             return MacExpand ();
684         }
685
686         /* If it's an identifier, it may in fact be a local symbol */
687         if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
688             /* Search for the local symbol in the list */
689             unsigned Index = 0;
690             IdDesc* I = CurMac->M->Locals;
691             while (I) {
692                 if (strcmp (SVal, I->Id) == 0) {
693                     /* This is in fact a local symbol, change the name */
694                     sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
695                     break;
696                 }
697                 /* Next symbol */
698                 ++Index;
699                 I = I->Next;
700             }
701
702             /* Done */
703             return 1;
704         }
705
706         /* The token was successfully set */
707         return 1;
708
709     } else if (CurMac->Final) {
710
711         /* Set the final token and remove it */
712         TokSet (CurMac->Final);
713         FreeTokNode (CurMac->Final);
714         CurMac->Final = 0;
715
716         /* The token was successfully set */
717         return 1;
718
719     } else {
720
721         /* End of macro expansion */
722         FreeMacExp ();
723         return MacExpand ();
724
725     }
726 }
727
728
729
730 void MacAbort (void)
731 /* Abort the current macro expansion */
732 {
733     /* Must have an expansion */
734     CHECK (CurMac != 0);
735
736     /* Free current structure */
737     FreeMacExp ();
738 }
739
740
741
742 int IsMacro (const char* Name)
743 /* Return true if the given name is the name of a macro */
744 {
745     return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
746 }
747
748
749
750 int IsDefine (const char* Name)
751 /* Return true if the given name is the name of a define style macro */
752 {
753     Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
754     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
755 }
756
757
758
759 int InMacExpansion (void)
760 /* Return true if we're currently expanding a macro */
761 {
762     return MacroNesting != 0;
763 }
764
765
766
767
768
769