]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
522db7ac2709ba7de48ca51b5487f8966bfdbe55
[cc65] / src / ca65 / macro.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  macro.c                                  */
4 /*                                                                           */
5 /*                    Macros for the ca65 macroassembler                     */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 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 "instr.h"
50 #include "istack.h"
51 #include "lineinfo.h"
52 #include "nexttok.h"
53 #include "pseudo.h"
54 #include "toklist.h"
55 #include "macro.h"
56
57
58
59 /*****************************************************************************/
60 /*                                 Forwards                                  */
61 /*****************************************************************************/
62
63
64
65 static unsigned HT_GenHash (const void* Key);
66 /* Generate the hash over a key. */
67
68 static const void* HT_GetKey (void* Entry);
69 /* Given a pointer to the user entry data, return a pointer to the key */
70
71 static HashNode* HT_GetHashNode (void* Entry);
72 /* Given a pointer to the user entry data, return a pointer to the hash node */
73
74 static int HT_Compare (const void* Key1, const void* Key2);
75 /* Compare two keys. The function must return a value less than zero if
76  * Key1 is smaller than Key2, zero if both are equal, and a value greater
77  * than zero if Key1 is greater then Key2.
78  */
79
80
81
82 /*****************************************************************************/
83 /*                                   Data                                    */
84 /*****************************************************************************/
85
86
87
88 /* Struct that describes an identifer (macro param, local list) */
89 typedef struct IdDesc IdDesc;
90 struct IdDesc {
91     IdDesc*         Next;       /* Linked list */
92     StrBuf          Id;         /* Identifier, dynamically allocated */
93 };
94
95
96
97 /* Struct that describes a macro definition */
98 typedef struct Macro Macro;
99 struct Macro {
100     HashNode        Node;       /* Hash list node */
101     Macro*          List;       /* List of all macros */
102     unsigned        LocalCount; /* Count of local symbols */
103     IdDesc*         Locals;     /* List of local symbols */
104     unsigned        ParamCount; /* Parameter count of macro */
105     IdDesc*         Params;     /* Identifiers of macro parameters */
106     unsigned        TokCount;   /* Number of tokens for this macro */
107     TokNode*        TokRoot;    /* Root of token list */
108     TokNode*        TokLast;    /* Pointer to last token in list */
109     StrBuf          Name;       /* Macro name, dynamically allocated */
110     unsigned        Expansions; /* Number of active macro expansions */
111     unsigned char   Style;      /* Macro style */
112     unsigned char   Incomplete; /* Macro is currently built */
113 };
114
115 /* Hash table functions */
116 static const HashFunctions HashFunc = {
117     HT_GenHash,
118     HT_GetKey,
119     HT_GetHashNode,
120     HT_Compare
121 };
122
123 /* Macro hash table */
124 static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
125
126 /* Structs that holds data for a macro expansion */
127 typedef struct MacExp MacExp;
128 struct MacExp {
129     MacExp*     Next;           /* Pointer to next expansion */
130     Macro*      M;              /* Which macro do we expand? */
131     unsigned    IfSP;           /* .IF stack pointer at start of expansion */
132     TokNode*    Exp;            /* Pointer to current token */
133     TokNode*    Final;          /* Pointer to final token */
134     unsigned    LocalStart;     /* Start of counter for local symbol names */
135     unsigned    ParamCount;     /* Number of actual parameters */
136     TokNode**   Params;         /* List of actual parameters */
137     TokNode*    ParamExp;       /* Node for expanding parameters */
138     int         LISlot;         /* Slot for additional line infos */
139 };
140
141 /* Maximum number of nested macro expansions */
142 #define MAX_MACEXPANSIONS       256U
143
144 /* Number of active macro expansions */
145 static unsigned MacExpansions = 0;
146
147 /* Flag if a macro expansion should get aborted */
148 static int DoMacAbort = 0;
149
150 /* Counter to create local names for symbols */
151 static unsigned LocalName = 0;
152
153 /* Define style macros disabled if != 0 */
154 static unsigned DisableDefines = 0;
155
156
157
158 /*****************************************************************************/
159 /*                           Hash table functions                            */
160 /*****************************************************************************/
161
162
163
164 static unsigned HT_GenHash (const void* Key)
165 /* Generate the hash over a key. */
166 {
167     return HashBuf (Key);
168 }
169
170
171
172 static const void* HT_GetKey (void* Entry)
173 /* Given a pointer to the user entry data, return a pointer to the index */
174 {
175     return &((Macro*) Entry)->Name;
176 }
177
178
179
180 static HashNode* HT_GetHashNode (void* Entry)
181 /* Given a pointer to the user entry data, return a pointer to the hash node */
182 {
183     return &((Macro*) Entry)->Node;
184 }
185
186
187
188 static int HT_Compare (const void* Key1, const void* Key2)
189 /* Compare two keys. The function must return a value less than zero if
190  * Key1 is smaller than Key2, zero if both are equal, and a value greater
191  * than zero if Key1 is greater then Key2.
192  */
193 {
194     return SB_Compare (Key1, Key2);
195 }
196
197
198
199 /*****************************************************************************/
200 /*                                   Code                                    */
201 /*****************************************************************************/
202
203
204
205 static IdDesc* NewIdDesc (const StrBuf* Id)
206 /* Create a new IdDesc, initialize and return it */
207 {
208     /* Allocate memory */
209     IdDesc* ID = xmalloc (sizeof (IdDesc));
210
211     /* Initialize the struct */
212     ID->Next = 0;
213     SB_Init (&ID->Id);
214     SB_Copy (&ID->Id, Id);
215
216     /* Return the new struct */
217     return ID;
218 }
219
220
221
222 static void FreeIdDesc (IdDesc* ID)
223 /* Free an IdDesc */
224 {
225     /* Free the name */
226     SB_Done (&ID->Id);
227
228     /* Free the structure itself */
229     xfree (ID);
230 }
231
232
233
234 static void FreeIdDescList (IdDesc* ID)
235 /* Free a complete list of IdDesc structures */
236 {
237     while (ID) {
238         IdDesc* This = ID;
239         ID = ID->Next;
240         FreeIdDesc (This);
241     }
242 }
243
244
245
246 static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
247 /* Generate a new macro entry, initialize and return it */
248 {
249     /* Allocate memory */
250     Macro* M = xmalloc (sizeof (Macro));
251
252     /* Initialize the macro struct */
253     InitHashNode (&M->Node, M);
254     M->LocalCount = 0;
255     M->Locals     = 0;
256     M->ParamCount = 0;
257     M->Params     = 0;
258     M->TokCount   = 0;
259     M->TokRoot    = 0;
260     M->TokLast    = 0;
261     SB_Init (&M->Name);
262     SB_Copy (&M->Name, Name);
263     M->Expansions = 0;
264     M->Style      = Style;
265     M->Incomplete = 1;
266
267     /* Insert the macro into the hash table */
268     HT_Insert (&MacroTab, &M->Node);
269
270     /* Return the new macro struct */
271     return M;
272 }
273
274
275
276 static void FreeMacro (Macro* M)
277 /* Free a macro entry which has already been removed from the macro table. */
278 {
279     TokNode* T;
280
281     /* Free locals */
282     FreeIdDescList (M->Locals);
283
284     /* Free identifiers of parameters */
285     FreeIdDescList (M->Params);
286
287     /* Free the token list for the macro */
288     while ((T = M->TokRoot) != 0) {
289         M->TokRoot = T->Next;
290         FreeTokNode (T);
291     }
292
293     /* Free the macro name */
294     SB_Done (&M->Name);
295
296     /* Free the macro structure itself */
297     xfree (M);
298 }
299
300
301
302 static MacExp* NewMacExp (Macro* M)
303 /* Create a new expansion structure for the given macro */
304 {
305     unsigned I;
306
307     /* Allocate memory */
308     MacExp* E = xmalloc (sizeof (MacExp));
309
310     /* Initialize the data */
311     E->M          = M;
312     E->IfSP       = GetIfStack ();
313     E->Exp        = M->TokRoot;
314     E->Final      = 0;
315     E->LocalStart = LocalName;
316     LocalName    += M->LocalCount;
317     E->ParamCount = 0;
318     E->Params     = xmalloc (M->ParamCount * sizeof (TokNode*));
319     for (I = 0; I < M->ParamCount; ++I) {
320         E->Params[I] = 0;
321     }
322     E->ParamExp   = 0;
323     E->LISlot     = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
324
325     /* Mark the macro as expanding */
326     ++M->Expansions;
327
328     /* One macro expansion more */
329     ++MacExpansions;
330
331     /* Return the new macro expansion */
332     return E;
333 }
334
335
336
337 static void FreeMacExp (MacExp* E)
338 /* Remove and free the current macro expansion */
339 {
340     unsigned I;
341
342     /* One macro expansion less */
343     --MacExpansions;
344
345     /* No longer expanding this macro */
346     --E->M->Expansions;
347
348     /* Free the parameter lists */
349     for (I = 0; I < E->ParamCount; ++I) {
350         /* Free one parameter list */
351         TokNode* N = E->Params[I];
352         while (N) {
353             TokNode* P = N->Next;
354             FreeTokNode (N);
355             N = P;
356         }
357     }
358     xfree (E->Params);
359
360     /* Free the additional line info slot */
361     FreeLineInfoSlot (E->LISlot);
362
363     /* Free the final token if we have one */
364     if (E->Final) {
365         FreeTokNode (E->Final);
366     }
367
368     /* Free the structure itself */
369     xfree (E);
370 }
371
372
373
374 static void MacSkipDef (unsigned Style)
375 /* Skip a macro definition */
376 {
377     if (Style == MAC_STYLE_CLASSIC) {
378         /* Skip tokens until we reach the final .endmacro */
379         while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
380             NextTok ();
381         }
382         if (CurTok.Tok != TOK_EOF) {
383             SkipUntilSep ();
384         } else {
385             Error ("`.ENDMACRO' expected");
386         }
387     } else {
388         /* Skip until end of line */
389         SkipUntilSep ();
390     }
391 }
392
393
394
395 void MacDef (unsigned Style)
396 /* Parse a macro definition */
397 {
398     Macro* M;
399     TokNode* N;
400     int HaveParams;
401
402     /* We expect a macro name here */
403     if (CurTok.Tok != TOK_IDENT) {
404         Error ("Identifier expected");
405         MacSkipDef (Style);
406         return;
407     } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
408         /* The identifier is a name of a 6502 instruction, which is not
409          * allowed if not explicitly enabled.
410          */
411         Error ("Cannot use an instruction as macro name");
412         MacSkipDef (Style);
413         return;
414     }
415
416     /* Did we already define that macro? */
417     if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
418         /* Macro is already defined */
419         Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
420         /* Skip tokens until we reach the final .endmacro */
421         MacSkipDef (Style);
422         return;
423     }
424
425     /* Define the macro */
426     M = NewMacro (&CurTok.SVal, Style);
427
428     /* Switch to raw token mode and skip the macro name */
429     EnterRawTokenMode ();
430     NextTok ();
431
432     /* If we have a DEFINE style macro, we may have parameters in braces,
433      * otherwise we may have parameters without braces.
434      */
435     if (Style == MAC_STYLE_CLASSIC) {
436         HaveParams = 1;
437     } else {
438         if (CurTok.Tok == TOK_LPAREN) {
439             HaveParams = 1;
440             NextTok ();
441         } else {
442             HaveParams = 0;
443         }
444     }
445
446     /* Parse the parameter list */
447     if (HaveParams) {
448
449         while (CurTok.Tok == TOK_IDENT) {
450
451             /* Create a struct holding the identifier */
452             IdDesc* I = NewIdDesc (&CurTok.SVal);
453
454             /* Insert the struct into the list, checking for duplicate idents */
455             if (M->ParamCount == 0) {
456                 M->Params = I;
457             } else {
458                 IdDesc* List = M->Params;
459                 while (1) {
460                     if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
461                         Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
462                     }
463                     if (List->Next == 0) {
464                         break;
465                     } else {
466                         List = List->Next;
467                     }
468                 }
469                 List->Next = I;
470             }
471             ++M->ParamCount;
472
473             /* Skip the name */
474             NextTok ();
475
476             /* Maybe there are more params... */
477             if (CurTok.Tok == TOK_COMMA) {
478                 NextTok ();
479             } else {
480                 break;
481             }
482         }
483     }
484
485     /* For class macros, we expect a separator token, for define style macros,
486      * we expect the closing paren.
487      */
488     if (Style == MAC_STYLE_CLASSIC) {
489         ConsumeSep ();
490     } else if (HaveParams) {
491         ConsumeRParen ();
492     }
493
494     /* Preparse the macro body. We will read the tokens until we reach end of
495      * file, or a .endmacro (or end of line for DEFINE style macros) and store
496      * them into an token list internal to the macro. For classic macros, there
497      * the .LOCAL command is detected and removed at this time.
498      */
499     while (1) {
500
501         /* Check for end of macro */
502         if (Style == MAC_STYLE_CLASSIC) {
503             /* In classic macros, only .endmacro is allowed */
504             if (CurTok.Tok == TOK_ENDMACRO) {
505                 /* Done */
506                 break;
507             }
508             /* May not have end of file in a macro definition */
509             if (CurTok.Tok == TOK_EOF) {
510                 Error ("`.ENDMACRO' expected");
511                 goto Done;
512             }
513         } else {
514             /* Accept a newline or end of file for new style macros */
515             if (TokIsSep (CurTok.Tok)) {
516                 break;
517             }
518         }
519
520         /* Check for a .LOCAL declaration */
521         if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
522
523             while (1) {
524
525                 IdDesc* I;
526
527                 /* Skip .local or comma */
528                 NextTok ();
529
530                 /* Need an identifer */
531                 if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
532                     Error ("Identifier expected");
533                     SkipUntilSep ();
534                     break;
535                 }
536
537                 /* Put the identifier into the locals list and skip it */
538                 I = NewIdDesc (&CurTok.SVal);
539                 I->Next = M->Locals;
540                 M->Locals = I;
541                 ++M->LocalCount;
542                 NextTok ();
543
544                 /* Check for end of list */
545                 if (CurTok.Tok != TOK_COMMA) {
546                     break;
547                 }
548
549             }
550
551             /* We need end of line after the locals */
552             ConsumeSep ();
553             continue;
554         }
555
556         /* Create a token node for the current token */
557         N = NewTokNode ();
558
559         /* If the token is an ident, check if it is a local parameter */
560         if (CurTok.Tok == TOK_IDENT) {
561             unsigned Count = 0;
562             IdDesc* I = M->Params;
563             while (I) {
564                 if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
565                     /* Local param name, replace it */
566                     N->T.Tok  = TOK_MACPARAM;
567                     N->T.IVal = Count;
568                     break;
569                 }
570                 ++Count;
571                 I = I->Next;
572             }
573         }
574
575         /* Insert the new token in the list */
576         if (M->TokCount == 0) {
577             /* First token */
578             M->TokRoot = M->TokLast = N;
579         } else {
580             /* We have already tokens */
581             M->TokLast->Next = N;
582             M->TokLast = N;
583         }
584         ++M->TokCount;
585
586         /* Read the next token */
587         NextTok ();
588     }
589
590     /* Skip the .endmacro for a classic macro */
591     if (Style == MAC_STYLE_CLASSIC) {
592         NextTok ();
593     }
594
595     /* Reset the Incomplete flag now that parsing is done */
596     M->Incomplete = 0;
597
598 Done:
599     /* Switch out of raw token mode */
600     LeaveRawTokenMode ();
601 }
602
603
604
605 void MacUndef (const StrBuf* Name, unsigned char Style)
606 /* Undefine the macro with the given name and style. A style mismatch is
607  * treated as if the macro didn't exist.
608  */
609 {
610     /* Search for the macro */
611     Macro* M = HT_FindEntry (&MacroTab, Name);
612
613     /* Don't let the user kid with us */
614     if (M == 0 || M->Style != Style) {
615         Error ("No such macro: %m%p", Name);
616         return;
617     }
618     if (M->Expansions > 0) {
619         Error ("Cannot delete a macro that is currently expanded");
620         return;
621     }
622
623     /* Remove the macro from the macro table */
624     HT_RemoveEntry (&MacroTab, M);
625
626     /* Free the macro structure */
627     FreeMacro (M);
628 }
629
630
631
632 static int MacExpand (void* Data)
633 /* If we're currently expanding a macro, set the the scanner token and
634  * attribute to the next value and return true. If we are not expanding
635  * a macro, return false.
636  */
637 {
638     /* Cast the Data pointer to the actual data structure */
639     MacExp* Mac = (MacExp*) Data;
640
641     /* Check if we should abort this macro */
642     if (DoMacAbort) {
643
644         /* Reset the flag */
645         DoMacAbort = 0;
646
647         /* Abort any open .IF statements in this macro expansion */
648         CleanupIfStack (Mac->IfSP);
649
650         /* Terminate macro expansion */
651         goto MacEnd;
652     }
653
654     /* We're expanding a macro. Check if we are expanding one of the
655      * macro parameters.
656      */
657 ExpandParam:
658     if (Mac->ParamExp) {
659
660         /* Ok, use token from parameter list, but don't use its line info */
661         TokSet (Mac->ParamExp, LI_SLOT_INV);
662
663         /* Set pointer to next token */
664         Mac->ParamExp = Mac->ParamExp->Next;
665
666         /* Done */
667         return 1;
668     }
669
670     /* We're not expanding macro parameters. Check if we have tokens left from
671      * the macro itself.
672      */
673     if (Mac->Exp) {
674
675         /* Use next macro token */
676         TokSet (Mac->Exp, Mac->LISlot);
677
678         /* Set pointer to next token */
679         Mac->Exp = Mac->Exp->Next;
680
681         /* Is it a request for actual parameter count? */
682         if (CurTok.Tok == TOK_PARAMCOUNT) {
683             CurTok.Tok  = TOK_INTCON;
684             CurTok.IVal = Mac->ParamCount;
685             return 1;
686         }
687
688         /* Is it the name of a macro parameter? */
689         if (CurTok.Tok == TOK_MACPARAM) {
690
691             /* Start to expand the parameter token list */
692             Mac->ParamExp = Mac->Params[CurTok.IVal];
693
694             /* Go back and expand the parameter */
695             goto ExpandParam;
696         }
697
698         /* If it's an identifier, it may in fact be a local symbol */
699         if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
700             Mac->M->LocalCount) {
701             /* Search for the local symbol in the list */
702             unsigned Index = 0;
703             IdDesc* I = Mac->M->Locals;
704             while (I) {
705                 if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
706                     /* This is in fact a local symbol, change the name. Be sure
707                      * to generate a local label name if the original name was
708                      * a local label, and also generate a name that cannot be
709                      * generated by a user.
710                      */
711                     if (SB_At (&I->Id, 0) == LocalStart) {
712                         /* Must generate a local symbol */
713                         SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
714                                    LocalStart, Mac->LocalStart + Index);
715                     } else {
716                         /* Global symbol */
717                         SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
718                                    Mac->LocalStart + Index);
719                     }
720                     break;
721                 }
722                 /* Next symbol */
723                 ++Index;
724                 I = I->Next;
725             }
726
727             /* Done */
728             return 1;
729         }
730
731         /* The token was successfully set */
732         return 1;
733     }
734
735     /* No more macro tokens. Do we have a final token? */
736     if (Mac->Final) {
737
738         /* Set the final token and remove it */
739         TokSet (Mac->Final, LI_SLOT_INV);
740         FreeTokNode (Mac->Final);
741         Mac->Final = 0;
742
743         /* Problem: When a .define style macro is expanded within the call
744          * of a classic one, the latter may be terminated and removed while
745          * the expansion of the .define style macro is still active. Because
746          * line info slots are "stacked", this runs into a CHECK FAILED. For
747          * now, we will fix that by removing the .define style macro expansion
748          * immediately, once the final token is placed. The better solution
749          * would probably be to not require AllocLineInfoSlot/FreeLineInfoSlot
750          * to be called in FIFO order, but this is a bigger change.
751          */
752         /* End of macro expansion and pop the input function */
753         FreeMacExp (Mac);
754         PopInput ();
755
756         /* The token was successfully set */
757         return 1;
758     }
759
760 MacEnd:
761     /* End of macro expansion */
762     FreeMacExp (Mac);
763
764     /* Pop the input function */
765     PopInput ();
766
767     /* No token available */
768     return 0;
769 }
770
771
772
773 static void StartExpClassic (MacExp* E)
774 /* Start expanding a classic macro */
775 {
776     token_t     Term;
777
778     /* Skip the macro name */
779     NextTok ();
780
781     /* Read the actual parameters */
782     while (!TokIsSep (CurTok.Tok)) {
783
784         TokNode* Last;
785
786         /* Check for maximum parameter count */
787         if (E->ParamCount >= E->M->ParamCount) {
788             ErrorSkip ("Too many macro parameters");
789             break;
790         }
791
792         /* The macro may optionally be enclosed in curly braces */
793         Term = GetTokListTerm (TOK_COMMA);
794
795         /* Read tokens for one parameter, accept empty params */
796         Last = 0;
797         while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
798
799             TokNode* T;
800
801             /* Check for end of file */
802             if (CurTok.Tok == TOK_EOF) {
803                 Error ("Unexpected end of file");
804                 FreeMacExp (E);
805                 return;
806             }
807
808             /* Get the next token in a node */
809             T = NewTokNode ();
810
811             /* Insert it into the list */
812             if (Last == 0) {
813                 E->Params [E->ParamCount] = T;
814             } else {
815                 Last->Next = T;
816             }
817             Last = T;
818
819             /* And skip it... */
820             NextTok ();
821         }
822
823         /* One parameter more */
824         ++E->ParamCount;
825
826         /* If the macro argument was enclosed in curly braces, end-of-line
827          * is an error. Skip the closing curly brace.
828          */
829         if (Term == TOK_RCURLY) {
830             if (CurTok.Tok == TOK_SEP) {
831                 Error ("End of line encountered within macro argument");
832                 break;
833             }
834             NextTok ();
835         }
836
837         /* Check for a comma */
838         if (CurTok.Tok == TOK_COMMA) {
839             NextTok ();
840         } else {
841             break;
842         }
843     }
844
845     /* We must be at end of line now, otherwise something is wrong */
846     ExpectSep ();
847
848     /* Insert a new token input function */
849     PushInput (MacExpand, E, ".MACRO");
850 }
851
852
853
854 static void StartExpDefine (MacExp* E)
855 /* Start expanding a DEFINE style macro */
856 {
857     /* A define style macro must be called with as many actual parameters
858      * as there are formal ones. Get the parameter count.
859      */
860     unsigned Count = E->M->ParamCount;
861
862     /* Skip the current token */
863     NextTok ();
864
865     /* Read the actual parameters */
866     while (Count--) {
867
868         TokNode*   Last;
869
870         /* The macro may optionally be enclosed in curly braces */
871         token_t Term = GetTokListTerm (TOK_COMMA);
872
873         /* Check if there is really a parameter */
874         if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
875             ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
876             FreeMacExp (E);
877             return;
878         }
879
880         /* Read tokens for one parameter */
881         Last = 0;
882         do {
883
884             TokNode* T;
885
886             /* Get the next token in a node */
887             T = NewTokNode ();
888
889             /* Insert it into the list */
890             if (Last == 0) {
891                 E->Params [E->ParamCount] = T;
892             } else {
893                 Last->Next = T;
894             }
895             Last = T;
896
897             /* And skip it... */
898             NextTok ();
899
900         } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
901
902         /* One parameter more */
903         ++E->ParamCount;
904
905         /* If the macro argument was enclosed in curly braces, end-of-line
906          * is an error. Skip the closing curly brace.
907          */
908         if (Term == TOK_RCURLY) {
909             if (TokIsSep (CurTok.Tok)) {
910                 Error ("End of line encountered within macro argument");
911                 break;
912             }
913             NextTok ();
914         }
915
916         /* Check for a comma */
917         if (Count > 0) {
918             if (CurTok.Tok == TOK_COMMA) {
919                 NextTok ();
920             } else {
921                 Error ("`,' expected");
922             }
923         }
924     }
925
926     /* Macro expansion will overwrite the current token. This is a problem
927      * for define style macros since these are called from the scanner level.
928      * To avoid it, remember the current token and re-insert it, once macro
929      * expansion is done.
930      */
931     E->Final = NewTokNode ();
932
933     /* Insert a new token input function */
934     PushInput (MacExpand, E, ".DEFINE");
935 }
936
937
938
939 void MacExpandStart (void)
940 /* Start expanding the macro in SVal */
941 {
942     MacExp* E;
943
944     /* Search for the macro */
945     Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
946     CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
947
948     /* We cannot expand an incomplete macro */
949     if (M->Incomplete) {
950         Error ("Cannot expand an incomplete macro");
951         return;
952     }
953
954     /* Don't allow too many nested macro expansions - otherwise it is possible
955      * to force an endless loop and assembler crash.
956      */
957     if (MacExpansions >= MAX_MACEXPANSIONS) {
958         Error ("Too many nested macro expansions");
959         return;
960     }
961
962     /* Create a structure holding expansion data */
963     E = NewMacExp (M);
964
965     /* Call the apropriate subroutine */
966     switch (M->Style) {
967         case MAC_STYLE_CLASSIC: StartExpClassic (E);    break;
968         case MAC_STYLE_DEFINE:  StartExpDefine (E);     break;
969         default:                Internal ("Invalid macro style: %d", M->Style);
970     }
971 }
972
973
974
975 void MacAbort (void)
976 /* Abort the current macro expansion */
977 {
978     /* Must have an expansion */
979     CHECK (MacExpansions > 0);
980
981     /* Set a flag so macro expansion will terminate on the next call */
982     DoMacAbort = 1;
983 }
984
985
986
987 int IsMacro (const StrBuf* Name)
988 /* Return true if the given name is the name of a macro */
989 {
990     return (HT_Find (&MacroTab, Name) != 0);
991 }
992
993
994
995 int IsDefine (const StrBuf* Name)
996 /* Return true if the given name is the name of a define style macro */
997 {
998     Macro* M;
999
1000     /* Never if disabled */
1001     if (DisableDefines) {
1002         return 0;
1003     }
1004
1005     /* Check if we have such a macro */
1006     M = HT_FindEntry (&MacroTab, Name);
1007     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
1008 }
1009
1010
1011
1012 int InMacExpansion (void)
1013 /* Return true if we're currently expanding a macro */
1014 {
1015     return (MacExpansions > 0);
1016 }
1017
1018
1019
1020 void DisableDefineStyleMacros (void)
1021 /* Disable define style macros until EnableDefineStyleMacros is called */
1022 {
1023     ++DisableDefines;
1024 }
1025
1026
1027
1028 void EnableDefineStyleMacros (void)
1029 /* Re-enable define style macros previously disabled with
1030  * DisableDefineStyleMacros.
1031  */
1032 {
1033     PRECONDITION (DisableDefines > 0);
1034     --DisableDefines;
1035 }
1036
1037
1038