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