]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
Finished implemenation of commands to delete macros. Added the new commands to
[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* 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     if (Mac->ParamExp) {
658
659         /* Ok, use token from parameter list */
660         TokSet (Mac->ParamExp, Mac->LISlot);
661
662         /* Set pointer to next token */
663         Mac->ParamExp = Mac->ParamExp->Next;
664
665         /* Done */
666         return 1;
667
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             /* Recursive call to expand the parameter */
695             return MacExpand (Mac);
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
736     /* No more macro tokens. Do we have a final token? */
737     if (Mac->Final) {
738
739         /* Set the final token and remove it */
740         TokSet (Mac->Final, Mac->LISlot);
741         FreeTokNode (Mac->Final);
742         Mac->Final = 0;
743
744         /* The token was successfully set */
745         return 1;
746
747     }
748
749 MacEnd:
750     /* End of macro expansion */
751     FreeMacExp (Mac);
752
753     /* Pop the input function */
754     PopInput ();
755
756     /* No token available */
757     return 0;
758 }
759
760
761
762 static void StartExpClassic (MacExp* E)
763 /* Start expanding a classic macro */
764 {
765     token_t     Term;
766
767     /* Skip the macro name */
768     NextTok ();
769
770     /* Read the actual parameters */
771     while (!TokIsSep (CurTok.Tok)) {
772
773         TokNode* Last;
774
775         /* Check for maximum parameter count */
776         if (E->ParamCount >= E->M->ParamCount) {
777             ErrorSkip ("Too many macro parameters");
778             break;
779         }
780
781         /* The macro may optionally be enclosed in curly braces */
782         Term = GetTokListTerm (TOK_COMMA);
783
784         /* Read tokens for one parameter, accept empty params */
785         Last = 0;
786         while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
787
788             TokNode* T;
789
790             /* Check for end of file */
791             if (CurTok.Tok == TOK_EOF) {
792                 Error ("Unexpected end of file");
793                 FreeMacExp (E);
794                 return;
795             }
796
797             /* Get the next token in a node */
798             T = NewTokNode ();
799
800             /* Insert it into the list */
801             if (Last == 0) {
802                 E->Params [E->ParamCount] = T;
803             } else {
804                 Last->Next = T;
805             }
806             Last = T;
807
808             /* And skip it... */
809             NextTok ();
810         }
811
812         /* One parameter more */
813         ++E->ParamCount;
814
815         /* If the macro argument was enclosed in curly braces, end-of-line
816          * is an error. Skip the closing curly brace.
817          */
818         if (Term == TOK_RCURLY) {
819             if (CurTok.Tok == TOK_SEP) {
820                 Error ("End of line encountered within macro argument");
821                 break;
822             }
823             NextTok ();
824         }
825
826         /* Check for a comma */
827         if (CurTok.Tok == TOK_COMMA) {
828             NextTok ();
829         } else {
830             break;
831         }
832     }
833
834     /* We must be at end of line now, otherwise something is wrong */
835     ExpectSep ();
836
837     /* Insert a new token input function */
838     PushInput (MacExpand, E, ".MACRO");
839 }
840
841
842
843 static void StartExpDefine (MacExp* E)
844 /* Start expanding a DEFINE style macro */
845 {
846     /* A define style macro must be called with as many actual parameters
847      * as there are formal ones. Get the parameter count.
848      */
849     unsigned Count = E->M->ParamCount;
850
851     /* Skip the current token */
852     NextTok ();
853
854     /* Read the actual parameters */
855     while (Count--) {
856
857         TokNode*   Last;
858
859         /* The macro may optionally be enclosed in curly braces */
860         token_t Term = GetTokListTerm (TOK_COMMA);
861
862         /* Check if there is really a parameter */
863         if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
864             ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
865             FreeMacExp (E);
866             return;
867         }
868
869         /* Read tokens for one parameter */
870         Last = 0;
871         do {
872
873             TokNode* T;
874
875             /* Get the next token in a node */
876             T = NewTokNode ();
877
878             /* Insert it into the list */
879             if (Last == 0) {
880                 E->Params [E->ParamCount] = T;
881             } else {
882                 Last->Next = T;
883             }
884             Last = T;
885
886             /* And skip it... */
887             NextTok ();
888
889         } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
890
891         /* One parameter more */
892         ++E->ParamCount;
893
894         /* If the macro argument was enclosed in curly braces, end-of-line
895          * is an error. Skip the closing curly brace.
896          */
897         if (Term == TOK_RCURLY) {
898             if (TokIsSep (CurTok.Tok)) {
899                 Error ("End of line encountered within macro argument");
900                 break;
901             }
902             NextTok ();
903         }
904
905         /* Check for a comma */
906         if (Count > 0) {
907             if (CurTok.Tok == TOK_COMMA) {
908                 NextTok ();
909             } else {
910                 Error ("`,' expected");
911             }
912         }
913     }
914
915     /* Macro expansion will overwrite the current token. This is a problem
916      * for define style macros since these are called from the scanner level.
917      * To avoid it, remember the current token and re-insert it, once macro
918      * expansion is done.
919      */
920     E->Final = NewTokNode ();
921
922     /* Insert a new token input function */
923     PushInput (MacExpand, E, ".DEFINE");
924 }
925
926
927
928 void MacExpandStart (void)
929 /* Start expanding the macro in SVal */
930 {
931     MacExp* E;
932
933     /* Search for the macro */
934     Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
935     CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
936
937     /* We cannot expand an incomplete macro */
938     if (M->Incomplete) {
939         Error ("Cannot expand an incomplete macro");
940         return;
941     }
942
943     /* Don't allow too many nested macro expansions - otherwise it is possible
944      * to force an endless loop and assembler crash.
945      */
946     if (MacExpansions >= MAX_MACEXPANSIONS) {
947         Error ("Too many nested macro expansions");
948         return;
949     }
950
951     /* Create a structure holding expansion data */
952     E = NewMacExp (M);
953
954     /* Call the apropriate subroutine */
955     switch (M->Style) {
956         case MAC_STYLE_CLASSIC: StartExpClassic (E);    break;
957         case MAC_STYLE_DEFINE:  StartExpDefine (E);     break;
958         default:                Internal ("Invalid macro style: %d", M->Style);
959     }
960 }
961
962
963
964 void MacAbort (void)
965 /* Abort the current macro expansion */
966 {
967     /* Must have an expansion */
968     CHECK (MacExpansions > 0);
969
970     /* Set a flag so macro expansion will terminate on the next call */
971     DoMacAbort = 1;
972 }
973
974
975
976 int IsMacro (const StrBuf* Name)
977 /* Return true if the given name is the name of a macro */
978 {
979     return (HT_Find (&MacroTab, Name) != 0);
980 }
981
982
983
984 int IsDefine (const StrBuf* Name)
985 /* Return true if the given name is the name of a define style macro */
986 {
987     Macro* M;
988
989     /* Never if disabled */
990     if (DisableDefines) {
991         return 0;
992     }
993
994     /* Check if we have such a macro */
995     M = HT_FindEntry (&MacroTab, Name);
996     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
997 }
998
999
1000
1001 int InMacExpansion (void)
1002 /* Return true if we're currently expanding a macro */
1003 {
1004     return (MacExpansions > 0);
1005 }
1006
1007
1008
1009 void DisableDefineStyleMacros (void)
1010 /* Disable define style macros until EnableDefineStyleMacros is called */
1011 {
1012     ++DisableDefines;
1013 }
1014
1015
1016
1017 void EnableDefineStyleMacros (void)
1018 /* Re-enable define style macros previously disabled with
1019  * DisableDefineStyleMacros.
1020  */
1021 {
1022     PRECONDITION (DisableDefines > 0);
1023     --DisableDefines;
1024 }
1025
1026
1027