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