]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
First implementation of .UNDEF for deleting a macro.
[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     unsigned    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* I = xmalloc (sizeof (IdDesc));
210
211     /* Initialize the struct */
212     I->Next = 0;
213     SB_Init (&I->Id);
214     SB_Copy (&I->Id, Id);
215
216     /* Return the new struct */
217     return I;
218 }
219
220
221
222 static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
223 /* Generate a new macro entry, initialize and return it */
224 {
225     /* Allocate memory */
226     Macro* M = xmalloc (sizeof (Macro));
227
228     /* Initialize the macro struct */
229     InitHashNode (&M->Node, M);
230     M->LocalCount = 0;
231     M->Locals     = 0;
232     M->ParamCount = 0;
233     M->Params     = 0;
234     M->TokCount   = 0;
235     M->TokRoot    = 0;
236     M->TokLast    = 0;
237     SB_Init (&M->Name);
238     SB_Copy (&M->Name, Name);
239     M->Expansions = 0;
240     M->Style      = Style;
241     M->Incomplete = 1;
242
243     /* Insert the macro into the hash table */
244     HT_Insert (&MacroTab, &M->Node);
245
246     /* Return the new macro struct */
247     return M;
248 }
249
250
251
252 static MacExp* NewMacExp (Macro* M)
253 /* Create a new expansion structure for the given macro */
254 {
255     unsigned I;
256
257     /* Allocate memory */
258     MacExp* E = xmalloc (sizeof (MacExp));
259
260     /* Initialize the data */
261     E->M          = M;
262     E->IfSP       = GetIfStack ();
263     E->Exp        = M->TokRoot;
264     E->Final      = 0;
265     E->LocalStart = LocalName;
266     LocalName    += M->LocalCount;
267     E->ParamCount = 0;
268     E->Params     = xmalloc (M->ParamCount * sizeof (TokNode*));
269     for (I = 0; I < M->ParamCount; ++I) {
270         E->Params[I] = 0;
271     }
272     E->ParamExp   = 0;
273     E->LISlot     = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
274
275     /* Mark the macro as expanding */
276     ++M->Expansions;
277
278     /* One macro expansion more */
279     ++MacExpansions;
280
281     /* Return the new macro expansion */
282     return E;
283 }
284
285
286
287 static void FreeMacExp (MacExp* E)
288 /* Remove and free the current macro expansion */
289 {
290     unsigned I;
291
292     /* One macro expansion less */
293     --MacExpansions;
294
295     /* No longer expanding this macro */
296     --E->M->Expansions;
297
298     /* Free the parameter lists */
299     for (I = 0; I < E->ParamCount; ++I) {
300         /* Free one parameter list */
301         TokNode* N = E->Params[I];
302         while (N) {
303             TokNode* P = N->Next;
304             FreeTokNode (N);
305             N = P;
306         }
307     }
308     xfree (E->Params);
309
310     /* Free the additional line info slot */
311     FreeLineInfoSlot (E->LISlot);
312
313     /* Free the final token if we have one */
314     if (E->Final) {
315         FreeTokNode (E->Final);
316     }
317
318     /* Free the structure itself */
319     xfree (E);
320 }
321
322
323
324 static void MacSkipDef (unsigned Style)
325 /* Skip a macro definition */
326 {
327     if (Style == MAC_STYLE_CLASSIC) {
328         /* Skip tokens until we reach the final .endmacro */
329         while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
330             NextTok ();
331         }
332         if (CurTok.Tok != TOK_EOF) {
333             SkipUntilSep ();
334         } else {
335             Error ("`.ENDMACRO' expected");
336         }
337     } else {
338         /* Skip until end of line */
339         SkipUntilSep ();
340     }
341 }
342
343
344
345 void MacDef (unsigned Style)
346 /* Parse a macro definition */
347 {
348     Macro* M;
349     TokNode* N;
350     int HaveParams;
351
352     /* We expect a macro name here */
353     if (CurTok.Tok != TOK_IDENT) {
354         Error ("Identifier expected");
355         MacSkipDef (Style);
356         return;
357     } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
358         /* The identifier is a name of a 6502 instruction, which is not
359          * allowed if not explicitly enabled.
360          */
361         Error ("Cannot use an instruction as macro name");
362         MacSkipDef (Style);
363         return;
364     }
365
366     /* Did we already define that macro? */
367     if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
368         /* Macro is already defined */
369         Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
370         /* Skip tokens until we reach the final .endmacro */
371         MacSkipDef (Style);
372         return;
373     }
374
375     /* Define the macro */
376     M = NewMacro (&CurTok.SVal, Style);
377
378     /* Switch to raw token mode and skip the macro name */
379     EnterRawTokenMode ();
380     NextTok ();
381
382     /* If we have a DEFINE style macro, we may have parameters in braces,
383      * otherwise we may have parameters without braces.
384      */
385     if (Style == MAC_STYLE_CLASSIC) {
386         HaveParams = 1;
387     } else {
388         if (CurTok.Tok == TOK_LPAREN) {
389             HaveParams = 1;
390             NextTok ();
391         } else {
392             HaveParams = 0;
393         }
394     }
395
396     /* Parse the parameter list */
397     if (HaveParams) {
398
399         while (CurTok.Tok == TOK_IDENT) {
400
401             /* Create a struct holding the identifier */
402             IdDesc* I = NewIdDesc (&CurTok.SVal);
403
404             /* Insert the struct into the list, checking for duplicate idents */
405             if (M->ParamCount == 0) {
406                 M->Params = I;
407             } else {
408                 IdDesc* List = M->Params;
409                 while (1) {
410                     if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
411                         Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
412                     }
413                     if (List->Next == 0) {
414                         break;
415                     } else {
416                         List = List->Next;
417                     }
418                 }
419                 List->Next = I;
420             }
421             ++M->ParamCount;
422
423             /* Skip the name */
424             NextTok ();
425
426             /* Maybe there are more params... */
427             if (CurTok.Tok == TOK_COMMA) {
428                 NextTok ();
429             } else {
430                 break;
431             }
432         }
433     }
434
435     /* For class macros, we expect a separator token, for define style macros,
436      * we expect the closing paren.
437      */
438     if (Style == MAC_STYLE_CLASSIC) {
439         ConsumeSep ();
440     } else if (HaveParams) {
441         ConsumeRParen ();
442     }
443
444     /* Preparse the macro body. We will read the tokens until we reach end of
445      * file, or a .endmacro (or end of line for DEFINE style macros) and store
446      * them into an token list internal to the macro. For classic macros, there
447      * the .LOCAL command is detected and removed at this time.
448      */
449     while (1) {
450
451         /* Check for end of macro */
452         if (Style == MAC_STYLE_CLASSIC) {
453             /* In classic macros, only .endmacro is allowed */
454             if (CurTok.Tok == TOK_ENDMACRO) {
455                 /* Done */
456                 break;
457             }
458             /* May not have end of file in a macro definition */
459             if (CurTok.Tok == TOK_EOF) {
460                 Error ("`.ENDMACRO' expected");
461                 goto Done;
462             }
463         } else {
464             /* Accept a newline or end of file for new style macros */
465             if (TokIsSep (CurTok.Tok)) {
466                 break;
467             }
468         }
469
470         /* Check for a .LOCAL declaration */
471         if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
472
473             while (1) {
474
475                 IdDesc* I;
476
477                 /* Skip .local or comma */
478                 NextTok ();
479
480                 /* Need an identifer */
481                 if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
482                     Error ("Identifier expected");
483                     SkipUntilSep ();
484                     break;
485                 }
486
487                 /* Put the identifier into the locals list and skip it */
488                 I = NewIdDesc (&CurTok.SVal);
489                 I->Next = M->Locals;
490                 M->Locals = I;
491                 ++M->LocalCount;
492                 NextTok ();
493
494                 /* Check for end of list */
495                 if (CurTok.Tok != TOK_COMMA) {
496                     break;
497                 }
498
499             }
500
501             /* We need end of line after the locals */
502             ConsumeSep ();
503             continue;
504         }
505
506         /* Create a token node for the current token */
507         N = NewTokNode ();
508
509         /* If the token is an ident, check if it is a local parameter */
510         if (CurTok.Tok == TOK_IDENT) {
511             unsigned Count = 0;
512             IdDesc* I = M->Params;
513             while (I) {
514                 if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
515                     /* Local param name, replace it */
516                     N->T.Tok  = TOK_MACPARAM;
517                     N->T.IVal = Count;
518                     break;
519                 }
520                 ++Count;
521                 I = I->Next;
522             }
523         }
524
525         /* Insert the new token in the list */
526         if (M->TokCount == 0) {
527             /* First token */
528             M->TokRoot = M->TokLast = N;
529         } else {
530             /* We have already tokens */
531             M->TokLast->Next = N;
532             M->TokLast = N;
533         }
534         ++M->TokCount;
535
536         /* Read the next token */
537         NextTok ();
538     }
539
540     /* Skip the .endmacro for a classic macro */
541     if (Style == MAC_STYLE_CLASSIC) {
542         NextTok ();
543     }
544
545     /* Reset the Incomplete flag now that parsing is done */
546     M->Incomplete = 0;
547
548 Done:
549     /* Switch out of raw token mode */
550     LeaveRawTokenMode ();
551 }
552
553
554
555 void MacUndef (const StrBuf* Name)
556 /* Undefine the macro with the given name. */
557 {
558     /* Search for the macro */
559     Macro* M = HT_FindEntry (&MacroTab, Name);
560
561     /* Don't let the user kid with us */
562     if (M == 0) {
563         Error ("No such macro: %m%p", Name);
564         return;
565     }
566     if (M->Expansions > 0) {
567         Error ("Cannot delete a macro that is currently expanded");
568         return;
569     }
570
571     /* Remove the macro from the macro table */
572     HT_RemoveEntry (&MacroTab, M);
573 }
574
575
576
577 static int MacExpand (void* Data)
578 /* If we're currently expanding a macro, set the the scanner token and
579  * attribute to the next value and return true. If we are not expanding
580  * a macro, return false.
581  */
582 {
583     /* Cast the Data pointer to the actual data structure */
584     MacExp* Mac = (MacExp*) Data;
585
586     /* Check if we should abort this macro */
587     if (DoMacAbort) {
588
589         /* Reset the flag */
590         DoMacAbort = 0;
591
592         /* Abort any open .IF statements in this macro expansion */
593         CleanupIfStack (Mac->IfSP);
594
595         /* Terminate macro expansion */
596         goto MacEnd;
597     }
598
599     /* We're expanding a macro. Check if we are expanding one of the
600      * macro parameters.
601      */
602     if (Mac->ParamExp) {
603
604         /* Ok, use token from parameter list */
605         TokSet (Mac->ParamExp, Mac->LISlot);
606
607         /* Set pointer to next token */
608         Mac->ParamExp = Mac->ParamExp->Next;
609
610         /* Done */
611         return 1;
612
613     }
614
615     /* We're not expanding macro parameters. Check if we have tokens left from
616      * the macro itself.
617      */
618     if (Mac->Exp) {
619
620         /* Use next macro token */
621         TokSet (Mac->Exp, Mac->LISlot);
622
623         /* Set pointer to next token */
624         Mac->Exp = Mac->Exp->Next;
625
626         /* Is it a request for actual parameter count? */
627         if (CurTok.Tok == TOK_PARAMCOUNT) {
628             CurTok.Tok  = TOK_INTCON;
629             CurTok.IVal = Mac->ParamCount;
630             return 1;
631         }
632
633         /* Is it the name of a macro parameter? */
634         if (CurTok.Tok == TOK_MACPARAM) {
635
636             /* Start to expand the parameter token list */
637             Mac->ParamExp = Mac->Params [CurTok.IVal];
638
639             /* Recursive call to expand the parameter */
640             return MacExpand (Mac);
641         }
642
643         /* If it's an identifier, it may in fact be a local symbol */
644         if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
645             Mac->M->LocalCount) {
646             /* Search for the local symbol in the list */
647             unsigned Index = 0;
648             IdDesc* I = Mac->M->Locals;
649             while (I) {
650                 if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
651                     /* This is in fact a local symbol, change the name. Be sure
652                      * to generate a local label name if the original name was
653                      * a local label, and also generate a name that cannot be
654                      * generated by a user.
655                      */
656                     if (SB_At (&I->Id, 0) == LocalStart) {
657                         /* Must generate a local symbol */
658                         SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
659                                    LocalStart, Mac->LocalStart + Index);
660                     } else {
661                         /* Global symbol */
662                         SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
663                                    Mac->LocalStart + Index);
664                     }
665                     break;
666                 }
667                 /* Next symbol */
668                 ++Index;
669                 I = I->Next;
670             }
671
672             /* Done */
673             return 1;
674         }
675
676         /* The token was successfully set */
677         return 1;
678
679     }
680
681     /* No more macro tokens. Do we have a final token? */
682     if (Mac->Final) {
683
684         /* Set the final token and remove it */
685         TokSet (Mac->Final, Mac->LISlot);
686         FreeTokNode (Mac->Final);
687         Mac->Final = 0;
688
689         /* The token was successfully set */
690         return 1;
691
692     }
693
694 MacEnd:
695     /* End of macro expansion */
696     FreeMacExp (Mac);
697
698     /* Pop the input function */
699     PopInput ();
700
701     /* No token available */
702     return 0;
703 }
704
705
706
707 static void StartExpClassic (MacExp* E)
708 /* Start expanding a classic macro */
709 {
710     token_t     Term;
711
712     /* Skip the macro name */
713     NextTok ();
714
715     /* Read the actual parameters */
716     while (!TokIsSep (CurTok.Tok)) {
717
718         TokNode* Last;
719
720         /* Check for maximum parameter count */
721         if (E->ParamCount >= E->M->ParamCount) {
722             ErrorSkip ("Too many macro parameters");
723             break;
724         }
725
726         /* The macro may optionally be enclosed in curly braces */
727         Term = GetTokListTerm (TOK_COMMA);
728
729         /* Read tokens for one parameter, accept empty params */
730         Last = 0;
731         while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
732
733             TokNode* T;
734
735             /* Check for end of file */
736             if (CurTok.Tok == TOK_EOF) {
737                 Error ("Unexpected end of file");
738                 FreeMacExp (E);
739                 return;
740             }
741
742             /* Get the next token in a node */
743             T = NewTokNode ();
744
745             /* Insert it into the list */
746             if (Last == 0) {
747                 E->Params [E->ParamCount] = T;
748             } else {
749                 Last->Next = T;
750             }
751             Last = T;
752
753             /* And skip it... */
754             NextTok ();
755         }
756
757         /* One parameter more */
758         ++E->ParamCount;
759
760         /* If the macro argument was enclosed in curly braces, end-of-line
761          * is an error. Skip the closing curly brace.
762          */
763         if (Term == TOK_RCURLY) {
764             if (CurTok.Tok == TOK_SEP) {
765                 Error ("End of line encountered within macro argument");
766                 break;
767             }
768             NextTok ();
769         }
770
771         /* Check for a comma */
772         if (CurTok.Tok == TOK_COMMA) {
773             NextTok ();
774         } else {
775             break;
776         }
777     }
778
779     /* We must be at end of line now, otherwise something is wrong */
780     ExpectSep ();
781
782     /* Insert a new token input function */
783     PushInput (MacExpand, E, ".MACRO");
784 }
785
786
787
788 static void StartExpDefine (MacExp* E)
789 /* Start expanding a DEFINE style macro */
790 {
791     /* A define style macro must be called with as many actual parameters
792      * as there are formal ones. Get the parameter count.
793      */
794     unsigned Count = E->M->ParamCount;
795
796     /* Skip the current token */
797     NextTok ();
798
799     /* Read the actual parameters */
800     while (Count--) {
801
802         TokNode*   Last;
803
804         /* The macro may optionally be enclosed in curly braces */
805         token_t Term = GetTokListTerm (TOK_COMMA);
806
807         /* Check if there is really a parameter */
808         if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
809             ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
810             FreeMacExp (E);
811             return;
812         }
813
814         /* Read tokens for one parameter */
815         Last = 0;
816         do {
817
818             TokNode* T;
819
820             /* Get the next token in a node */
821             T = NewTokNode ();
822
823             /* Insert it into the list */
824             if (Last == 0) {
825                 E->Params [E->ParamCount] = T;
826             } else {
827                 Last->Next = T;
828             }
829             Last = T;
830
831             /* And skip it... */
832             NextTok ();
833
834         } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
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 (TokIsSep (CurTok.Tok)) {
844                 Error ("End of line encountered within macro argument");
845                 break;
846             }
847             NextTok ();
848         }
849
850         /* Check for a comma */
851         if (Count > 0) {
852             if (CurTok.Tok == TOK_COMMA) {
853                 NextTok ();
854             } else {
855                 Error ("`,' expected");
856             }
857         }
858     }
859
860     /* Macro expansion will overwrite the current token. This is a problem
861      * for define style macros since these are called from the scanner level.
862      * To avoid it, remember the current token and re-insert it, once macro
863      * expansion is done.
864      */
865     E->Final = NewTokNode ();
866
867     /* Insert a new token input function */
868     PushInput (MacExpand, E, ".DEFINE");
869 }
870
871
872
873 void MacExpandStart (void)
874 /* Start expanding the macro in SVal */
875 {
876     MacExp* E;
877
878     /* Search for the macro */
879     Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
880     CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
881
882     /* We cannot expand an incomplete macro */
883     if (M->Incomplete) {
884         Error ("Cannot expand an incomplete macro");
885         return;
886     }
887
888     /* Don't allow too many nested macro expansions - otherwise it is possible
889      * to force an endless loop and assembler crash.
890      */
891     if (MacExpansions >= MAX_MACEXPANSIONS) {
892         Error ("Too many nested macro expansions");
893         return;
894     }
895
896     /* Create a structure holding expansion data */
897     E = NewMacExp (M);
898
899     /* Call the apropriate subroutine */
900     switch (M->Style) {
901         case MAC_STYLE_CLASSIC: StartExpClassic (E);    break;
902         case MAC_STYLE_DEFINE:  StartExpDefine (E);     break;
903         default:                Internal ("Invalid macro style: %d", M->Style);
904     }
905 }
906
907
908
909 void MacAbort (void)
910 /* Abort the current macro expansion */
911 {
912     /* Must have an expansion */
913     CHECK (MacExpansions > 0);
914
915     /* Set a flag so macro expansion will terminate on the next call */
916     DoMacAbort = 1;
917 }
918
919
920
921 int IsMacro (const StrBuf* Name)
922 /* Return true if the given name is the name of a macro */
923 {
924     return (HT_Find (&MacroTab, Name) != 0);
925 }
926
927
928
929 int IsDefine (const StrBuf* Name)
930 /* Return true if the given name is the name of a define style macro */
931 {   
932     Macro* M;
933
934     /* Never if disabled */
935     if (DisableDefines) {             
936         return 0;
937     }
938
939     /* Check if we have such a macro */
940     M = HT_FindEntry (&MacroTab, Name);
941     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
942 }
943
944
945
946 int InMacExpansion (void)
947 /* Return true if we're currently expanding a macro */
948 {
949     return (MacExpansions > 0);
950 }
951
952
953
954 void DisableDefineStyleMacros (void)
955 /* Disable define style macros until EnableDefineStyleMacros is called */
956 {
957     ++DisableDefines;
958 }
959
960
961
962 void EnableDefineStyleMacros (void)
963 /* Re-enable define style macros previously disabled with
964  * DisableDefineStyleMacros.
965  */
966 {
967     PRECONDITION (DisableDefines > 0);
968     --DisableDefines;
969 }
970
971
972