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