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