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