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