]> git.sur5r.net Git - cc65/blobdiff - src/ca65/macro.c
Finished implemenation of commands to delete macros. Added the new commands to
[cc65] / src / ca65 / macro.c
index fdb65794bfa143d6ac4d398c36688ce1759e7786..a5c86e9ad9975455f6bc8b21a6059bbe874fbbac 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2008 Ullrich von Bassewitz                                       */
-/*               Roemerstrasse 52                                            */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -48,6 +48,7 @@
 #include "global.h"
 #include "instr.h"
 #include "istack.h"
+#include "lineinfo.h"
 #include "nexttok.h"
 #include "pseudo.h"
 #include "toklist.h"
@@ -105,8 +106,10 @@ struct Macro {
     unsigned       TokCount;   /* Number of tokens for this macro */
     TokNode*       TokRoot;    /* Root of token list */
     TokNode*       TokLast;    /* Pointer to last token in list */
-    unsigned char   Style;     /* Macro style */
     StrBuf          Name;      /* Macro name, dynamically allocated */
+    unsigned        Expansions; /* Number of active macro expansions */
+    unsigned char   Style;     /* Macro style */
+    unsigned char   Incomplete; /* Macro is currently built */
 };
 
 /* Hash table functions */
@@ -120,23 +123,24 @@ static const HashFunctions HashFunc = {
 /* Macro hash table */
 static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
 
-/* Global macro data */
-static Macro*          MacroRoot = 0;  /* List of all macros */
-
 /* Structs that holds data for a macro expansion */
 typedef struct MacExp MacExp;
 struct MacExp {
-    MacExp*    Next;           /* Pointer to next expansion */
-    Macro*     M;              /* Which macro do we expand? */
-    unsigned   IfSP;           /* .IF stack pointer at start of expansion */
+    MacExp*            Next;           /* Pointer to next expansion */
+    Macro*             M;              /* Which macro do we expand? */
+    unsigned           IfSP;           /* .IF stack pointer at start of expansion */
     TokNode*           Exp;            /* Pointer to current token */
-    TokNode*   Final;          /* Pointer to final token */
+    TokNode*           Final;          /* Pointer to final token */
     unsigned    LocalStart;    /* Start of counter for local symbol names */
-    unsigned   ParamCount;     /* Number of actual parameters */
-    TokNode**  Params;         /* List of actual parameters */
-    TokNode*   ParamExp;       /* Node for expanding parameters */
+    unsigned           ParamCount;     /* Number of actual parameters */
+    TokNode**          Params;         /* List of actual parameters */
+    TokNode*           ParamExp;       /* Node for expanding parameters */
+    unsigned    LISlot;         /* Slot for additional line infos */
 };
 
+/* Maximum number of nested macro expansions */
+#define MAX_MACEXPANSIONS       256U
+
 /* Number of active macro expansions */
 static unsigned MacExpansions = 0;
 
@@ -146,6 +150,9 @@ static int DoMacAbort = 0;
 /* Counter to create local names for symbols */
 static unsigned LocalName = 0;
 
+/* Define style macros disabled if != 0 */
+static unsigned DisableDefines = 0;
+
 
 
 /*****************************************************************************/
@@ -199,15 +206,39 @@ static IdDesc* NewIdDesc (const StrBuf* Id)
 /* Create a new IdDesc, initialize and return it */
 {
     /* Allocate memory */
-    IdDesc* I = xmalloc (sizeof (IdDesc));
+    IdDesc* ID = xmalloc (sizeof (IdDesc));
 
     /* Initialize the struct */
-    I->Next = 0;
-    SB_Init (&I->Id);
-    SB_Copy (&I->Id, Id);
+    ID->Next = 0;
+    SB_Init (&ID->Id);
+    SB_Copy (&ID->Id, Id);
 
     /* Return the new struct */
-    return I;
+    return ID;
+}
+
+
+
+static void FreeIdDesc (IdDesc* ID)
+/* Free an IdDesc */
+{
+    /* Free the name */
+    SB_Done (&ID->Id);
+
+    /* Free the structure itself */
+    xfree (ID);
+}
+
+
+
+static void FreeIdDescList (IdDesc* ID)
+/* Free a complete list of IdDesc structures */
+{
+    while (ID) {
+        IdDesc* This = ID;      
+        ID = ID->Next;
+        FreeIdDesc (This);
+    }
 }
 
 
@@ -227,13 +258,11 @@ static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
     M->TokCount          = 0;
     M->TokRoot    = 0;
     M->TokLast    = 0;
-    M->Style     = Style;
     SB_Init (&M->Name);
     SB_Copy (&M->Name, Name);
-
-    /* Insert the macro into the global macro list */
-    M->List = MacroRoot;
-    MacroRoot = M;
+    M->Expansions = 0;
+    M->Style     = Style;
+    M->Incomplete = 1;
 
     /* Insert the macro into the hash table */
     HT_Insert (&MacroTab, &M->Node);
@@ -244,6 +273,32 @@ static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
 
 
 
+static void FreeMacro (Macro* M)
+/* Free a macro entry which has already been removed from the macro table. */
+{
+    TokNode* T;
+
+    /* Free locals */
+    FreeIdDescList (M->Locals);
+
+    /* Free identifiers of parameters */
+    FreeIdDescList (M->Params);
+
+    /* Free the token list for the macro */
+    while ((T = M->TokRoot) != 0) {
+        M->TokRoot = T->Next;
+        FreeTokNode (T);
+    }
+
+    /* Free the macro name */
+    SB_Done (&M->Name);
+
+    /* Free the macro structure itself */
+    xfree (M);
+}
+
+
+
 static MacExp* NewMacExp (Macro* M)
 /* Create a new expansion structure for the given macro */
 {
@@ -254,17 +309,21 @@ static MacExp* NewMacExp (Macro* M)
 
     /* Initialize the data */
     E->M                 = M;
-    E->IfSP      = GetIfStack ();
+    E->IfSP              = GetIfStack ();
     E->Exp               = M->TokRoot;
-    E->Final     = 0;
+    E->Final             = 0;
     E->LocalStart = LocalName;
     LocalName    += M->LocalCount;
     E->ParamCount = 0;
     E->Params     = xmalloc (M->ParamCount * sizeof (TokNode*));
-    E->ParamExp          = 0;
     for (I = 0; I < M->ParamCount; ++I) {
-       E->Params [I] = 0;
+       E->Params[I] = 0;
     }
+    E->ParamExp          = 0;
+    E->LISlot     = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
+
+    /* Mark the macro as expanding */
+    ++M->Expansions;
 
     /* One macro expansion more */
     ++MacExpansions;
@@ -283,6 +342,9 @@ static void FreeMacExp (MacExp* E)
     /* One macro expansion less */
     --MacExpansions;
 
+    /* No longer expanding this macro */
+    --E->M->Expansions;
+
     /* Free the parameter lists */
     for (I = 0; I < E->ParamCount; ++I) {
         /* Free one parameter list */
@@ -295,6 +357,9 @@ static void FreeMacExp (MacExp* E)
     }
     xfree (E->Params);
 
+    /* Free the additional line info slot */
+    FreeLineInfoSlot (E->LISlot);
+
     /* Free the final token if we have one */
     if (E->Final) {
        FreeTokNode (E->Final);
@@ -310,18 +375,18 @@ static void MacSkipDef (unsigned Style)
 /* Skip a macro definition */
 {
     if (Style == MAC_STYLE_CLASSIC) {
-       /* Skip tokens until we reach the final .endmacro */
-       while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
-           NextTok ();
-       }
-       if (Tok != TOK_EOF) {
-           SkipUntilSep ();
-       } else {
-           Error ("`.ENDMACRO' expected");
-       }
+               /* Skip tokens until we reach the final .endmacro */
+               while (CurTok.Tok != TOK_ENDMACRO && CurTok.Tok != TOK_EOF) {
+                   NextTok ();
+               }
+               if (CurTok.Tok != TOK_EOF) {
+                   SkipUntilSep ();
+               } else {
+                   Error ("`.ENDMACRO' expected");
+               }
     } else {
-       /* Skip until end of line */
-       SkipUntilSep ();
+               /* Skip until end of line */
+               SkipUntilSep ();
     }
 }
 
@@ -331,15 +396,15 @@ void MacDef (unsigned Style)
 /* Parse a macro definition */
 {
     Macro* M;
-    TokNode* T;
+    TokNode* N;
     int HaveParams;
 
     /* We expect a macro name here */
-    if (Tok != TOK_IDENT) {
+    if (CurTok.Tok != TOK_IDENT) {
        Error ("Identifier expected");
        MacSkipDef (Style);
        return;
-    } else if (!UbiquitousIdents && FindInstruction (&SVal) >= 0) {
+    } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
         /* The identifier is a name of a 6502 instruction, which is not
          * allowed if not explicitly enabled.
          */
@@ -349,16 +414,16 @@ void MacDef (unsigned Style)
     }
 
     /* Did we already define that macro? */
-    if (HT_Find (&MacroTab, &SVal) != 0) {
+    if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
                /* Macro is already defined */
-               Error ("A macro named `%m%p' is already defined", &SVal);
+               Error ("A macro named `%m%p' is already defined", &CurTok.SVal);
        /* Skip tokens until we reach the final .endmacro */
        MacSkipDef (Style);
                return;
     }
 
     /* Define the macro */
-    M = NewMacro (&SVal, Style);
+    M = NewMacro (&CurTok.SVal, Style);
 
     /* Switch to raw token mode and skip the macro name */
     EnterRawTokenMode ();
@@ -370,7 +435,7 @@ void MacDef (unsigned Style)
     if (Style == MAC_STYLE_CLASSIC) {
        HaveParams = 1;
     } else {
-       if (Tok == TOK_LPAREN) {
+       if (CurTok.Tok == TOK_LPAREN) {
            HaveParams = 1;
            NextTok ();
        } else {
@@ -381,10 +446,10 @@ void MacDef (unsigned Style)
     /* Parse the parameter list */
     if (HaveParams) {
 
-       while (Tok == TOK_IDENT) {
+       while (CurTok.Tok == TOK_IDENT) {
 
            /* Create a struct holding the identifier */
-           IdDesc* I = NewIdDesc (&SVal);
+           IdDesc* I = NewIdDesc (&CurTok.SVal);
 
            /* Insert the struct into the list, checking for duplicate idents */
            if (M->ParamCount == 0) {
@@ -392,8 +457,8 @@ void MacDef (unsigned Style)
            } else {
                IdDesc* List = M->Params;
                while (1) {
-                   if (SB_Compare (&List->Id, &SVal) == 0) {
-                       Error ("Duplicate symbol `%m%p'", &SVal);
+                   if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
+                       Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
                    }
                    if (List->Next == 0) {
                        break;
@@ -409,7 +474,7 @@ void MacDef (unsigned Style)
            NextTok ();
 
            /* Maybe there are more params... */
-           if (Tok == TOK_COMMA) {
+           if (CurTok.Tok == TOK_COMMA) {
                NextTok ();
            } else {
                break;
@@ -436,24 +501,24 @@ void MacDef (unsigned Style)
        /* Check for end of macro */
        if (Style == MAC_STYLE_CLASSIC) {
            /* In classic macros, only .endmacro is allowed */
-           if (Tok == TOK_ENDMACRO) {
+           if (CurTok.Tok == TOK_ENDMACRO) {
                /* Done */
                break;
            }
-           /* May not have end of file in a macro definition */
-           if (Tok == TOK_EOF) {
+           /* May not have end of file in a macro definition */
+           if (CurTok.Tok == TOK_EOF) {
                Error ("`.ENDMACRO' expected");
                goto Done;
            }
        } else {
            /* Accept a newline or end of file for new style macros */
-           if (TokIsSep (Tok)) {
+           if (TokIsSep (CurTok.Tok)) {
                break;
            }
        }
 
        /* Check for a .LOCAL declaration */
-       if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
+       if (CurTok.Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
 
            while (1) {
 
@@ -463,21 +528,21 @@ void MacDef (unsigned Style)
                        NextTok ();
 
                /* Need an identifer */
-               if (Tok != TOK_IDENT && Tok != TOK_LOCAL_IDENT) {
+               if (CurTok.Tok != TOK_IDENT && CurTok.Tok != TOK_LOCAL_IDENT) {
                    Error ("Identifier expected");
                    SkipUntilSep ();
                    break;
                }
 
                /* Put the identifier into the locals list and skip it */
-                       I = NewIdDesc (&SVal);
+                       I = NewIdDesc (&CurTok.SVal);
                I->Next = M->Locals;
                M->Locals = I;
                ++M->LocalCount;
-               NextTok ();
+                       NextTok ();
 
                /* Check for end of list */
-               if (Tok != TOK_COMMA) {
+               if (CurTok.Tok != TOK_COMMA) {
                    break;
                }
 
@@ -489,17 +554,17 @@ void MacDef (unsigned Style)
        }
 
        /* Create a token node for the current token */
-       T = NewTokNode ();
+       N = NewTokNode ();
 
        /* If the token is an ident, check if it is a local parameter */
-       if (Tok == TOK_IDENT) {
+       if (CurTok.Tok == TOK_IDENT) {
            unsigned Count = 0;
            IdDesc* I = M->Params;
            while (I) {
-               if (SB_Compare (&I->Id, &SVal) == 0) {
+               if (SB_Compare (&I->Id, &CurTok.SVal) == 0) {
                    /* Local param name, replace it */
-                   T->Tok  = TOK_MACPARAM;
-                   T->IVal = Count;
+                           N->T.Tok  = TOK_MACPARAM;
+                   N->T.IVal = Count;
                    break;
                }
                ++Count;
@@ -510,11 +575,11 @@ void MacDef (unsigned Style)
        /* Insert the new token in the list */
        if (M->TokCount == 0) {
            /* First token */
-           M->TokRoot = M->TokLast = T;
+           M->TokRoot = M->TokLast = N;
        } else {
            /* We have already tokens */
-           M->TokLast->Next = T;
-           M->TokLast = T;
+           M->TokLast->Next = N;
+           M->TokLast = N;
        }
        ++M->TokCount;
 
@@ -527,6 +592,9 @@ void MacDef (unsigned Style)
        NextTok ();
     }
 
+    /* Reset the Incomplete flag now that parsing is done */
+    M->Incomplete = 0;
+
 Done:
     /* Switch out of raw token mode */
     LeaveRawTokenMode ();
@@ -534,6 +602,33 @@ Done:
 
 
 
+void MacUndef (const StrBuf* Name, unsigned char Style)
+/* Undefine the macro with the given name and style. A style mismatch is
+ * treated as if the macro didn't exist.
+ */
+{
+    /* Search for the macro */
+    Macro* M = HT_FindEntry (&MacroTab, Name);
+
+    /* Don't let the user kid with us */
+    if (M == 0 || M->Style != Style) {
+        Error ("No such macro: %m%p", Name);
+        return;
+    }
+    if (M->Expansions > 0) {
+        Error ("Cannot delete a macro that is currently expanded");
+        return;
+    }
+
+    /* Remove the macro from the macro table */
+    HT_RemoveEntry (&MacroTab, M);
+
+    /* Free the macro structure */
+    FreeMacro (M);
+}
+
+
+
 static int MacExpand (void* Data)
 /* If we're currently expanding a macro, set the the scanner token and
  * attribute to the next value and return true. If we are not expanding
@@ -562,7 +657,7 @@ static int MacExpand (void* Data)
     if (Mac->ParamExp) {
 
                /* Ok, use token from parameter list */
-               TokSet (Mac->ParamExp);
+               TokSet (Mac->ParamExp, Mac->LISlot);
 
                /* Set pointer to next token */
                Mac->ParamExp = Mac->ParamExp->Next;
@@ -578,35 +673,36 @@ static int MacExpand (void* Data)
     if (Mac->Exp) {
 
                /* Use next macro token */
-               TokSet (Mac->Exp);
+               TokSet (Mac->Exp, Mac->LISlot);
 
                /* Set pointer to next token */
                Mac->Exp = Mac->Exp->Next;
 
                /* Is it a request for actual parameter count? */
-               if (Tok == TOK_PARAMCOUNT) {
-                   Tok  = TOK_INTCON;
-                   IVal = Mac->ParamCount;
+               if (CurTok.Tok == TOK_PARAMCOUNT) {
+                   CurTok.Tok  = TOK_INTCON;
+                   CurTok.IVal = Mac->ParamCount;
                    return 1;
                }
 
                /* Is it the name of a macro parameter? */
-               if (Tok == TOK_MACPARAM) {
+               if (CurTok.Tok == TOK_MACPARAM) {
 
                    /* Start to expand the parameter token list */
-                   Mac->ParamExp = Mac->Params [IVal];
+                   Mac->ParamExp = Mac->Params [CurTok.IVal];
 
                    /* Recursive call to expand the parameter */
                    return MacExpand (Mac);
                }
 
                /* If it's an identifier, it may in fact be a local symbol */
-               if ((Tok == TOK_IDENT || Tok == TOK_LOCAL_IDENT) && Mac->M->LocalCount) {
+               if ((CurTok.Tok == TOK_IDENT || CurTok.Tok == TOK_LOCAL_IDENT) &&
+            Mac->M->LocalCount) {
                    /* Search for the local symbol in the list */
                    unsigned Index = 0;
                    IdDesc* I = Mac->M->Locals;
                    while (I) {
-                       if (SB_Compare (&SVal, &I->Id) == 0) {
+                       if (SB_Compare (&CurTok.SVal, &I->Id) == 0) {
                            /* This is in fact a local symbol, change the name. Be sure
                      * to generate a local label name if the original name was
                      * a local label, and also generate a name that cannot be
@@ -614,11 +710,11 @@ static int MacExpand (void* Data)
                      */
                     if (SB_At (&I->Id, 0) == LocalStart) {
                         /* Must generate a local symbol */
-                        SB_Printf (&SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
+                        SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
                                    LocalStart, Mac->LocalStart + Index);
                     } else {
                         /* Global symbol */
-                        SB_Printf (&SVal, "LOCAL-MACRO_SYMBOL-%04X",
+                        SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
                                    Mac->LocalStart + Index);
                     }
                            break;
@@ -641,7 +737,7 @@ static int MacExpand (void* Data)
     if (Mac->Final) {
 
        /* Set the final token and remove it */
-       TokSet (Mac->Final);
+       TokSet (Mac->Final, Mac->LISlot);
        FreeTokNode (Mac->Final);
        Mac->Final = 0;
 
@@ -663,41 +759,36 @@ MacEnd:
 
 
 
-static void StartExpClassic (Macro* M)
-/* Start expanding the classic macro M */
+static void StartExpClassic (MacExp* E)
+/* Start expanding a classic macro */
 {
-    MacExp*     E;
     token_t     Term;
 
-
     /* Skip the macro name */
     NextTok ();
 
-    /* Create a structure holding expansion data */
-    E = NewMacExp (M);
-
     /* Read the actual parameters */
-    while (!TokIsSep (Tok)) {
+    while (!TokIsSep (CurTok.Tok)) {
 
        TokNode* Last;
 
                /* Check for maximum parameter count */
-       if (E->ParamCount >= M->ParamCount) {
+       if (E->ParamCount >= E->M->ParamCount) {
                    ErrorSkip ("Too many macro parameters");
            break;
-       }
+       }
 
         /* The macro may optionally be enclosed in curly braces */
         Term = GetTokListTerm (TOK_COMMA);
 
                /* Read tokens for one parameter, accept empty params */
        Last = 0;
-       while (Tok != Term && Tok != TOK_SEP) {
+       while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
 
            TokNode* T;
 
            /* Check for end of file */
-           if (Tok == TOK_EOF) {
+           if (CurTok.Tok == TOK_EOF) {
                Error ("Unexpected end of file");
                 FreeMacExp (E);
                return;
@@ -712,7 +803,7 @@ static void StartExpClassic (Macro* M)
            } else {
                Last->Next = T;
            }
-           Last = T;
+                   Last = T;
 
            /* And skip it... */
            NextTok ();
@@ -725,7 +816,7 @@ static void StartExpClassic (Macro* M)
          * is an error. Skip the closing curly brace.
          */
         if (Term == TOK_RCURLY) {
-            if (Tok == TOK_SEP) {
+            if (CurTok.Tok == TOK_SEP) {
                 Error ("End of line encountered within macro argument");
                 break;
             }
@@ -733,9 +824,9 @@ static void StartExpClassic (Macro* M)
         }
 
        /* Check for a comma */
-       if (Tok == TOK_COMMA) {
-           NextTok ();
-       } else {
+       if (CurTok.Tok == TOK_COMMA) {
+           NextTok ();
+       } else {
            break;
        }
     }
@@ -749,16 +840,13 @@ static void StartExpClassic (Macro* M)
 
 
 
-static void StartExpDefine (Macro* M)
+static void StartExpDefine (MacExp* E)
 /* Start expanding a DEFINE style macro */
 {
-    /* Create a structure holding expansion data */
-    MacExp* E = NewMacExp (M);
-
     /* A define style macro must be called with as many actual parameters
      * as there are formal ones. Get the parameter count.
      */
-    unsigned Count = M->ParamCount;
+    unsigned Count = E->M->ParamCount;
 
     /* Skip the current token */
     NextTok ();
@@ -772,7 +860,7 @@ static void StartExpDefine (Macro* M)
         token_t Term = GetTokListTerm (TOK_COMMA);
 
                /* Check if there is really a parameter */
-               if (TokIsSep (Tok) || Tok == Term) {
+               if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
             ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
             FreeMacExp (E);
             return;
@@ -795,19 +883,19 @@ static void StartExpDefine (Macro* M)
                    }
                    Last = T;
 
-           /* And skip it... */
-           NextTok ();
+           /* And skip it... */
+           NextTok ();
 
-               } while (Tok != Term && !TokIsSep (Tok));
+               } while (CurTok.Tok != Term && !TokIsSep (CurTok.Tok));
 
-       /* One parameter more */
-       ++E->ParamCount;
+       /* One parameter more */
+       ++E->ParamCount;
 
         /* If the macro argument was enclosed in curly braces, end-of-line
          * is an error. Skip the closing curly brace.
          */
         if (Term == TOK_RCURLY) {
-            if (TokIsSep (Tok)) {
+            if (TokIsSep (CurTok.Tok)) {
                 Error ("End of line encountered within macro argument");
                 break;
             }
@@ -816,7 +904,7 @@ static void StartExpDefine (Macro* M)
 
                /* Check for a comma */
                if (Count > 0) {
-                   if (Tok == TOK_COMMA) {
+                   if (CurTok.Tok == TOK_COMMA) {
                        NextTok ();
                    } else {
                        Error ("`,' expected");
@@ -840,15 +928,34 @@ static void StartExpDefine (Macro* M)
 void MacExpandStart (void)
 /* Start expanding the macro in SVal */
 {
+    MacExp* E;
+
     /* Search for the macro */
-    Macro* M = HT_FindEntry (&MacroTab, &SVal);
-    CHECK (M != 0);
+    Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
+    CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
+
+    /* We cannot expand an incomplete macro */
+    if (M->Incomplete) {
+        Error ("Cannot expand an incomplete macro");
+        return;
+    }
+
+    /* Don't allow too many nested macro expansions - otherwise it is possible
+     * to force an endless loop and assembler crash.
+     */
+    if (MacExpansions >= MAX_MACEXPANSIONS) {
+        Error ("Too many nested macro expansions");
+        return;
+    }
+
+    /* Create a structure holding expansion data */
+    E = NewMacExp (M);
 
     /* Call the apropriate subroutine */
     switch (M->Style) {
-       case MAC_STYLE_CLASSIC: StartExpClassic (M);    break;
-       case MAC_STYLE_DEFINE:  StartExpDefine (M);     break;
-       default:                Internal ("Invalid macro style: %d", M->Style);
+       case MAC_STYLE_CLASSIC: StartExpClassic (E);    break;
+       case MAC_STYLE_DEFINE:  StartExpDefine (E);     break;
+       default:                Internal ("Invalid macro style: %d", M->Style);
     }
 }
 
@@ -877,7 +984,15 @@ int IsMacro (const StrBuf* Name)
 int IsDefine (const StrBuf* Name)
 /* Return true if the given name is the name of a define style macro */
 {
-    Macro* M = HT_FindEntry (&MacroTab, Name);
+    Macro* M;
+
+    /* Never if disabled */
+    if (DisableDefines) {
+        return 0;
+    }
+
+    /* Check if we have such a macro */
+    M = HT_FindEntry (&MacroTab, Name);
     return (M != 0 && M->Style == MAC_STYLE_DEFINE);
 }
 
@@ -891,3 +1006,22 @@ int InMacExpansion (void)
 
 
 
+void DisableDefineStyleMacros (void)
+/* Disable define style macros until EnableDefineStyleMacros is called */
+{
+    ++DisableDefines;
+}
+
+
+
+void EnableDefineStyleMacros (void)
+/* Re-enable define style macros previously disabled with
+ * DisableDefineStyleMacros.
+ */
+{
+    PRECONDITION (DisableDefines > 0);
+    --DisableDefines;
+}
+
+
+