]> git.sur5r.net Git - cc65/blob - src/ca65/macro.c
Create separate line infos for macros and .repeat statements and other token
[cc65] / src / ca65 / macro.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  macro.c                                  */
4 /*                                                                           */
5 /*                    Macros for the ca65 macroassembler                     */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <string.h>
38
39 /* common */
40 #include "check.h"
41 #include "hashstr.h"
42 #include "hashtab.h"
43 #include "xmalloc.h"
44
45 /* ca65 */
46 #include "condasm.h"
47 #include "error.h"
48 #include "global.h"
49 #include "instr.h"
50 #include "istack.h"
51 #include "lineinfo.h"
52 #include "nexttok.h"
53 #include "pseudo.h"
54 #include "toklist.h"
55 #include "macro.h"
56
57
58
59 /*****************************************************************************/
60 /*                                 Forwards                                  */
61 /*****************************************************************************/
62
63
64
65 static unsigned HT_GenHash (const void* Key);
66 /* Generate the hash over a key. */
67
68 static const void* HT_GetKey (void* Entry);
69 /* Given a pointer to the user entry data, return a pointer to the key */
70
71 static HashNode* HT_GetHashNode (void* Entry);
72 /* Given a pointer to the user entry data, return a pointer to the hash node */
73
74 static int HT_Compare (const void* Key1, const void* Key2);
75 /* Compare two keys. The function must return a value less than zero if
76  * Key1 is smaller than Key2, zero if both are equal, and a value greater
77  * than zero if Key1 is greater then Key2.
78  */
79
80
81
82 /*****************************************************************************/
83 /*                                   Data                                    */
84 /*****************************************************************************/
85
86
87
88 /* Struct that describes an identifer (macro param, local list) */
89 typedef struct IdDesc IdDesc;
90 struct IdDesc {
91     IdDesc*         Next;       /* Linked list */
92     StrBuf          Id;         /* Identifier, dynamically allocated */
93 };
94
95
96
97 /* Struct that describes a macro definition */
98 typedef struct Macro Macro;
99 struct Macro {
100     HashNode        Node;       /* Hash list node */
101     Macro*          List;       /* List of all macros */
102     unsigned        LocalCount; /* Count of local symbols */
103     IdDesc*         Locals;     /* List of local symbols */
104     unsigned        ParamCount; /* Parameter count of macro */
105     IdDesc*         Params;     /* Identifiers of macro parameters */
106     unsigned        TokCount;   /* Number of tokens for this macro */
107     TokNode*        TokRoot;    /* Root of token list */
108     TokNode*        TokLast;    /* Pointer to last token in list */
109     unsigned char   Style;      /* Macro style */
110     StrBuf          Name;       /* Macro name, dynamically allocated */
111 };
112
113 /* Hash table functions */
114 static const HashFunctions HashFunc = {
115     HT_GenHash,
116     HT_GetKey,
117     HT_GetHashNode,
118     HT_Compare
119 };
120
121 /* Macro hash table */
122 static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
123
124 /* Global macro data */
125 static Macro*   MacroRoot = 0;  /* List of all macros */
126
127 /* Structs that holds data for a macro expansion */
128 typedef struct MacExp MacExp;
129 struct MacExp {
130     MacExp*     Next;           /* Pointer to next expansion */
131     Macro*      M;              /* Which macro do we expand? */
132     unsigned    IfSP;           /* .IF stack pointer at start of expansion */
133     TokNode*    Exp;            /* Pointer to current token */
134     TokNode*    Final;          /* Pointer to final token */
135     unsigned    LocalStart;     /* Start of counter for local symbol names */
136     unsigned    ParamCount;     /* Number of actual parameters */
137     TokNode**   Params;         /* List of actual parameters */
138     TokNode*    ParamExp;       /* Node for expanding parameters */
139     unsigned    LISlot;         /* Slot for additional line infos */
140 };
141
142 /* Number of active macro expansions */
143 static unsigned MacExpansions = 0;
144
145 /* Flag if a macro expansion should get aborted */
146 static int DoMacAbort = 0;
147
148 /* Counter to create local names for symbols */
149 static unsigned LocalName = 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 HashNode* HT_GetHashNode (void* Entry)
176 /* Given a pointer to the user entry data, return a pointer to the hash node */
177 {
178     return &((Macro*) Entry)->Node;
179 }
180
181
182
183 static int HT_Compare (const void* Key1, const void* Key2)
184 /* Compare two keys. The function must return a value less than zero if
185  * Key1 is smaller than Key2, zero if both are equal, and a value greater
186  * than zero if Key1 is greater then Key2.
187  */
188 {
189     return SB_Compare (Key1, Key2);
190 }
191
192
193
194 /*****************************************************************************/
195 /*                                   Code                                    */
196 /*****************************************************************************/
197
198
199
200 static IdDesc* NewIdDesc (const StrBuf* Id)
201 /* Create a new IdDesc, initialize and return it */
202 {
203     /* Allocate memory */
204     IdDesc* I = xmalloc (sizeof (IdDesc));
205
206     /* Initialize the struct */
207     I->Next = 0;
208     SB_Init (&I->Id);
209     SB_Copy (&I->Id, Id);
210
211     /* Return the new struct */
212     return I;
213 }
214
215
216
217 static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
218 /* Generate a new macro entry, initialize and return it */
219 {
220     /* Allocate memory */
221     Macro* M = xmalloc (sizeof (Macro));
222
223     /* Initialize the macro struct */
224     InitHashNode (&M->Node, M);
225     M->LocalCount = 0;
226     M->Locals     = 0;
227     M->ParamCount = 0;
228     M->Params     = 0;
229     M->TokCount   = 0;
230     M->TokRoot    = 0;
231     M->TokLast    = 0;
232     M->Style      = Style;
233     SB_Init (&M->Name);
234     SB_Copy (&M->Name, Name);
235
236     /* Insert the macro into the global macro list */
237     M->List = MacroRoot;
238     MacroRoot = M;
239
240     /* Insert the macro into the hash table */
241     HT_Insert (&MacroTab, &M->Node);
242
243     /* Return the new macro struct */
244     return M;
245 }
246
247
248
249 static MacExp* NewMacExp (Macro* M)
250 /* Create a new expansion structure for the given macro */
251 {
252     unsigned I;
253
254     /* Allocate memory */
255     MacExp* E = xmalloc (sizeof (MacExp));
256
257     /* Initialize the data */
258     E->M          = M;
259     E->IfSP       = GetIfStack ();
260     E->Exp        = M->TokRoot;
261     E->Final      = 0;
262     E->LocalStart = LocalName;
263     LocalName    += M->LocalCount;
264     E->ParamCount = 0;
265     E->Params     = xmalloc (M->ParamCount * sizeof (TokNode*));
266     E->ParamExp   = 0;
267     for (I = 0; I < M->ParamCount; ++I) {
268         E->Params[I] = 0;
269     }
270     E->LISlot     = AllocLineInfoSlot (LI_TYPE_MACRO | MacExpansions);
271
272     /* One macro expansion more */
273     ++MacExpansions;
274
275     /* Return the new macro expansion */
276     return E;
277 }
278
279
280
281 static void FreeMacExp (MacExp* E)
282 /* Remove and free the current macro expansion */
283 {
284     unsigned I;
285
286     /* One macro expansion less */
287     --MacExpansions;
288
289     /* Free the parameter lists */
290     for (I = 0; I < E->ParamCount; ++I) {
291         /* Free one parameter list */
292         TokNode* N = E->Params[I];
293         while (N) {
294             TokNode* P = N->Next;
295             FreeTokNode (N);
296             N = P;
297         }
298     }
299     xfree (E->Params);
300
301     /* Free the additional line info slot */
302     FreeLineInfoSlot (E->LISlot);
303
304     /* Free the final token if we have one */
305     if (E->Final) {
306         FreeTokNode (E->Final);
307     }
308
309     /* Free the structure itself */
310     xfree (E);
311 }
312
313
314
315 static void MacSkipDef (unsigned Style)
316 /* Skip a macro definition */
317 {
318     if (Style == MAC_STYLE_CLASSIC) {
319         /* Skip tokens until we reach the final .endmacro */
320         while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
321             NextTok ();
322         }
323         if (CurTok.Tok != TOK_EOF) {
324             SkipUntilSep ();
325         } else {
326             Error ("`.ENDMACRO' expected");
327         }
328     } else {
329         /* Skip until end of line */
330         SkipUntilSep ();
331     }
332 }
333
334
335
336 void MacDef (unsigned Style)
337 /* Parse a macro definition */
338 {
339     Macro* M;
340     TokNode* N;
341     int HaveParams;
342
343     /* We expect a macro name here */
344     if (CurTok.Tok != TOK_IDENT) {
345         Error ("Identifier expected");
346         MacSkipDef (Style);
347         return;
348     } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
349         /* The identifier is a name of a 6502 instruction, which is not
350          * allowed if not explicitly enabled.
351          */
352         Error ("Cannot use an instruction as macro name");
353         MacSkipDef (Style);
354         return;
355     }
356
357     /* Did we already define that macro? */
358     if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
359         /* Macro is already defined */
360         Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
361         /* Skip tokens until we reach the final .endmacro */
362         MacSkipDef (Style);
363         return;
364     }
365
366     /* Define the macro */
367     M = NewMacro (&CurTok.SVal, Style);
368
369     /* Switch to raw token mode and skip the macro name */
370     EnterRawTokenMode ();
371     NextTok ();
372
373     /* If we have a DEFINE style macro, we may have parameters in braces,
374      * otherwise we may have parameters without braces.
375      */
376     if (Style == MAC_STYLE_CLASSIC) {
377         HaveParams = 1;
378     } else {
379         if (CurTok.Tok == TOK_LPAREN) {
380             HaveParams = 1;
381             NextTok ();
382         } else {
383             HaveParams = 0;
384         }
385     }
386
387     /* Parse the parameter list */
388     if (HaveParams) {
389
390         while (CurTok.Tok == TOK_IDENT) {
391
392             /* Create a struct holding the identifier */
393             IdDesc* I = NewIdDesc (&CurTok.SVal);
394
395             /* Insert the struct into the list, checking for duplicate idents */
396             if (M->ParamCount == 0) {
397                 M->Params = I;
398             } else {
399                 IdDesc* List = M->Params;
400                 while (1) {
401                     if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
402                         Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
403                     }
404                     if (List->Next == 0) {
405                         break;
406                     } else {
407                         List = List->Next;
408                     }
409                 }
410                 List->Next = I;
411             }
412             ++M->ParamCount;
413
414             /* Skip the name */
415             NextTok ();
416
417             /* Maybe there are more params... */
418             if (CurTok.Tok == TOK_COMMA) {
419                 NextTok ();
420             } else {
421                 break;
422             }
423         }
424     }
425
426     /* For class macros, we expect a separator token, for define style macros,
427      * we expect the closing paren.
428      */
429     if (Style == MAC_STYLE_CLASSIC) {
430         ConsumeSep ();
431     } else if (HaveParams) {
432         ConsumeRParen ();
433     }
434
435     /* Preparse the macro body. We will read the tokens until we reach end of
436      * file, or a .endmacro (or end of line for DEFINE style macros) and store
437      * them into an token list internal to the macro. For classic macros, there
438      * the .LOCAL command is detected and removed at this time.
439      */
440     while (1) {
441
442         /* Check for end of macro */
443         if (Style == MAC_STYLE_CLASSIC) {
444             /* In classic macros, only .endmacro is allowed */
445             if (CurTok.Tok == TOK_ENDMACRO) {
446                 /* Done */
447                 break;
448             }
449             /* May not have end of file in a macro definition */
450             if (CurTok.Tok == TOK_EOF) {
451                 Error ("`.ENDMACRO' expected");
452                 goto Done;
453             }
454         } else {
455             /* Accept a newline or end of file for new style macros */
456             if (TokIsSep (CurTok.Tok)) {
457                 break;
458             }
459         }
460
461         /* Check for a .LOCAL declaration */
462         if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
463
464             while (1) {
465
466                 IdDesc* I;
467
468                 /* Skip .local or comma */
469                 NextTok ();
470
471                 /* Need an identifer */
472                 if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
473                     Error ("Identifier expected");
474                     SkipUntilSep ();
475                     break;
476                 }
477
478                 /* Put the identifier into the locals list and skip it */
479                 I = NewIdDesc (&CurTok.SVal);
480                 I->Next = M->Locals;
481                 M->Locals = I;
482                 ++M->LocalCount;
483                 NextTok ();
484
485                 /* Check for end of list */
486                 if (CurTok.Tok != TOK_COMMA) {
487                     break;
488                 }
489
490             }
491
492             /* We need end of line after the locals */
493             ConsumeSep ();
494             continue;
495         }
496
497         /* Create a token node for the current token */
498         N = NewTokNode ();
499
500         /* If the token is an ident, check if it is a local parameter */
501         if (CurTok.Tok == TOK_IDENT) {
502             unsigned Count = 0;
503             IdDesc* I = M->Params;
504             while (I) {
505                 if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
506                     /* Local param name, replace it */
507                     N->T.Tok  = TOK_MACPARAM;
508                     N->T.IVal = Count;
509                     break;
510                 }
511                 ++Count;
512                 I = I->Next;
513             }
514         }
515
516         /* Insert the new token in the list */
517         if (M->TokCount == 0) {
518             /* First token */
519             M->TokRoot = M->TokLast = N;
520         } else {
521             /* We have already tokens */
522             M->TokLast->Next = N;
523             M->TokLast = N;
524         }
525         ++M->TokCount;
526
527         /* Read the next token */
528         NextTok ();
529     }
530
531     /* Skip the .endmacro for a classic macro */
532     if (Style == MAC_STYLE_CLASSIC) {
533         NextTok ();
534     }
535
536 Done:
537     /* Switch out of raw token mode */
538     LeaveRawTokenMode ();
539 }
540
541
542
543 static int MacExpand (void* Data)
544 /* If we're currently expanding a macro, set the the scanner token and
545  * attribute to the next value and return true. If we are not expanding
546  * a macro, return false.
547  */
548 {
549     /* Cast the Data pointer to the actual data structure */
550     MacExp* Mac = (MacExp*) Data;
551
552     /* Check if we should abort this macro */
553     if (DoMacAbort) {
554
555         /* Reset the flag */
556         DoMacAbort = 0;
557
558         /* Abort any open .IF statements in this macro expansion */
559         CleanupIfStack (Mac->IfSP);
560
561         /* Terminate macro expansion */
562         goto MacEnd;
563     }
564
565     /* We're expanding a macro. Check if we are expanding one of the
566      * macro parameters.
567      */
568     if (Mac->ParamExp) {
569
570         /* Ok, use token from parameter list */
571         TokSet (Mac->ParamExp, Mac->LISlot);
572
573         /* Set pointer to next token */
574         Mac->ParamExp = Mac->ParamExp->Next;
575
576         /* Done */
577         return 1;
578
579     }
580
581     /* We're not expanding macro parameters. Check if we have tokens left from
582      * the macro itself.
583      */
584     if (Mac->Exp) {
585
586         /* Use next macro token */
587         TokSet (Mac->Exp, Mac->LISlot);
588
589         /* Set pointer to next token */
590         Mac->Exp = Mac->Exp->Next;
591
592         /* Is it a request for actual parameter count? */
593         if (CurTok.Tok == TOK_PARAMCOUNT) {
594             CurTok.Tok  = TOK_INTCON;
595             CurTok.IVal = Mac->ParamCount;
596             return 1;
597         }
598
599         /* Is it the name of a macro parameter? */
600         if (CurTok.Tok == TOK_MACPARAM) {
601
602             /* Start to expand the parameter token list */
603             Mac->ParamExp = Mac->Params [CurTok.IVal];
604
605             /* Recursive call to expand the parameter */
606             return MacExpand (Mac);
607         }
608
609         /* If it's an identifier, it may in fact be a local symbol */
610         if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
611             Mac->M->LocalCount) {
612             /* Search for the local symbol in the list */
613             unsigned Index = 0;
614             IdDesc* I = Mac->M->Locals;
615             while (I) {
616                 if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
617                     /* This is in fact a local symbol, change the name. Be sure
618                      * to generate a local label name if the original name was
619                      * a local label, and also generate a name that cannot be
620                      * generated by a user.
621                      */
622                     if (SB_At (&I->Id, 0) == LocalStart) {
623                         /* Must generate a local symbol */
624                         SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
625                                    LocalStart, Mac->LocalStart + Index);
626                     } else {
627                         /* Global symbol */
628                         SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
629                                    Mac->LocalStart + Index);
630                     }
631                     break;
632                 }
633                 /* Next symbol */
634                 ++Index;
635                 I = I->Next;
636             }
637
638             /* Done */
639             return 1;
640         }
641
642         /* The token was successfully set */
643         return 1;
644
645     }
646
647     /* No more macro tokens. Do we have a final token? */
648     if (Mac->Final) {
649
650         /* Set the final token and remove it */
651         TokSet (Mac->Final, Mac->LISlot);
652         FreeTokNode (Mac->Final);
653         Mac->Final = 0;
654
655         /* The token was successfully set */
656         return 1;
657
658     }
659
660 MacEnd:
661     /* End of macro expansion */
662     FreeMacExp (Mac);
663
664     /* Pop the input function */
665     PopInput ();
666
667     /* No token available */
668     return 0;
669 }
670
671
672
673 static void StartExpClassic (Macro* M)
674 /* Start expanding the classic macro M */
675 {
676     MacExp*     E;
677     token_t     Term;
678
679
680     /* Skip the macro name */
681     NextTok ();
682
683     /* Create a structure holding expansion data */
684     E = NewMacExp (M);
685
686     /* Read the actual parameters */
687     while (!TokIsSep (CurTok.Tok)) {
688
689         TokNode* Last;
690
691         /* Check for maximum parameter count */
692         if (E->ParamCount >= M->ParamCount) {
693             ErrorSkip ("Too many macro parameters");
694             break;
695         }
696
697         /* The macro may optionally be enclosed in curly braces */
698         Term = GetTokListTerm (TOK_COMMA);
699
700         /* Read tokens for one parameter, accept empty params */
701         Last = 0;
702         while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
703
704             TokNode* T;
705
706             /* Check for end of file */
707             if (CurTok.Tok == TOK_EOF) {
708                 Error ("Unexpected end of file");
709                 FreeMacExp (E);
710                 return;
711             }
712
713             /* Get the next token in a node */
714             T = NewTokNode ();
715
716             /* Insert it into the list */
717             if (Last == 0) {
718                 E->Params [E->ParamCount] = T;
719             } else {
720                 Last->Next = T;
721             }
722             Last = T;
723
724             /* And skip it... */
725             NextTok ();
726         }
727
728         /* One parameter more */
729         ++E->ParamCount;
730
731         /* If the macro argument was enclosed in curly braces, end-of-line
732          * is an error. Skip the closing curly brace.
733          */
734         if (Term == TOK_RCURLY) {
735             if (CurTok.Tok == TOK_SEP) {
736                 Error ("End of line encountered within macro argument");
737                 break;
738             }
739             NextTok ();
740         }
741
742         /* Check for a comma */
743         if (CurTok.Tok == TOK_COMMA) {
744             NextTok ();
745         } else {
746             break;
747         }
748     }
749
750     /* We must be at end of line now, otherwise something is wrong */
751     ExpectSep ();
752
753     /* Insert a new token input function */
754     PushInput (MacExpand, E, ".MACRO");
755 }
756
757
758
759 static void StartExpDefine (Macro* M)
760 /* Start expanding a DEFINE style macro */
761 {
762     /* Create a structure holding expansion data */
763     MacExp* E = NewMacExp (M);
764
765     /* A define style macro must be called with as many actual parameters
766      * as there are formal ones. Get the parameter count.
767      */
768     unsigned Count = M->ParamCount;
769
770     /* Skip the current token */
771     NextTok ();
772
773     /* Read the actual parameters */
774     while (Count--) {
775
776         TokNode*   Last;
777
778         /* The macro may optionally be enclosed in curly braces */
779         token_t Term = GetTokListTerm (TOK_COMMA);
780
781         /* Check if there is really a parameter */
782         if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
783             ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
784             FreeMacExp (E);
785             return;
786         }
787
788         /* Read tokens for one parameter */
789         Last = 0;
790         do {
791
792             TokNode* T;
793
794             /* Get the next token in a node */
795             T = NewTokNode ();
796
797             /* Insert it into the list */
798             if (Last == 0) {
799                 E->Params [E->ParamCount] = T;
800             } else {
801                 Last->Next = T;
802             }
803             Last = T;
804
805             /* And skip it... */
806             NextTok ();
807
808         } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
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 (TokIsSep (CurTok.Tok)) {
818                 Error ("End of line encountered within macro argument");
819                 break;
820             }
821             NextTok ();
822         }
823
824         /* Check for a comma */
825         if (Count > 0) {
826             if (CurTok.Tok == TOK_COMMA) {
827                 NextTok ();
828             } else {
829                 Error ("`,' expected");
830             }
831         }
832     }
833
834     /* Macro expansion will overwrite the current token. This is a problem
835      * for define style macros since these are called from the scanner level.
836      * To avoid it, remember the current token and re-insert it, once macro
837      * expansion is done.
838      */
839     E->Final = NewTokNode ();
840
841     /* Insert a new token input function */
842     PushInput (MacExpand, E, ".DEFINE");
843 }
844
845
846
847 void MacExpandStart (void)
848 /* Start expanding the macro in SVal */
849 {
850     /* Search for the macro */
851     Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
852     CHECK (M != 0);
853
854     /* Call the apropriate subroutine */
855     switch (M->Style) {
856         case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
857         case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
858         default:                Internal ("Invalid macro style: %d", M->Style);
859     }
860 }
861
862
863
864 void MacAbort (void)
865 /* Abort the current macro expansion */
866 {
867     /* Must have an expansion */
868     CHECK (MacExpansions > 0);
869
870     /* Set a flag so macro expansion will terminate on the next call */
871     DoMacAbort = 1;
872 }
873
874
875
876 int IsMacro (const StrBuf* Name)
877 /* Return true if the given name is the name of a macro */
878 {
879     return (HT_Find (&MacroTab, Name) != 0);
880 }
881
882
883
884 int IsDefine (const StrBuf* Name)
885 /* Return true if the given name is the name of a define style macro */
886 {
887     Macro* M = HT_FindEntry (&MacroTab, Name);
888     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
889 }
890
891
892
893 int InMacExpansion (void)
894 /* Return true if we're currently expanding a macro */
895 {
896     return (MacExpansions > 0);
897 }
898
899
900
901