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