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