unsigned TokCount; /* Number of tokens for this macro */
TokNode* TokRoot; /* Root of token list */
TokNode* TokLast; /* Pointer to last token in list */
+ 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 */
- StrBuf Name; /* Macro name, dynamically allocated */
};
/* Hash table functions */
/* 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 {
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
+/* Define style macros disabled if != 0 */
+static unsigned DisableDefines = 0;
+
/*****************************************************************************/
M->TokCount = 0;
M->TokRoot = 0;
M->TokLast = 0;
- M->Style = Style;
- M->Incomplete = 1;
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);
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->ParamExp = 0;
E->LISlot = AllocLineInfoSlot (LI_TYPE_MACRO, MacExpansions);
+ /* Mark the macro as expanding */
+ ++M->Expansions;
+
/* One macro expansion more */
++MacExpansions;
/* 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 */
/* Skip a macro definition */
{
if (Style == MAC_STYLE_CLASSIC) {
- /* 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");
- }
+ /* 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 ();
}
}
/* Done */
break;
}
- /* May not have end of file in a macro definition */
+ /* May not have end of file in a macro definition */
if (CurTok.Tok == TOK_EOF) {
Error ("`.ENDMACRO' expected");
goto Done;
I->Next = M->Locals;
M->Locals = I;
++M->LocalCount;
- NextTok ();
+ NextTok ();
/* Check for end of list */
if (CurTok.Tok != TOK_COMMA) {
+void MacUndef (const StrBuf* Name)
+/* Undefine the macro with the given name. */
+{
+ /* Search for the macro */
+ Macro* M = HT_FindEntry (&MacroTab, Name);
+
+ /* Don't let the user kid with us */
+ if (M == 0) {
+ 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);
+}
+
+
+
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
-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;
-
- /* Create a structure holding expansion data. This must be done before
- * skipping the macro name, because the call to NextTok may cause a new
- * expansion if the next token is actually a .define style macro.
- */
- E = NewMacExp (M);
-
/* Skip the macro name */
NextTok ();
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);
} else {
Last->Next = T;
}
- Last = T;
+ Last = T;
/* And skip it... */
NextTok ();
/* Check for a comma */
if (CurTok.Tok == TOK_COMMA) {
- NextTok ();
- } else {
+ NextTok ();
+ } else {
break;
}
}
-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 ();
}
Last = T;
- /* And skip it... */
- NextTok ();
+ /* And skip it... */
+ NextTok ();
} 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.
void MacExpandStart (void)
/* Start expanding the macro in SVal */
{
+ MacExp* E;
+
/* Search for the macro */
Macro* M = HT_FindEntry (&MacroTab, &CurTok.SVal);
- CHECK (M != 0);
+ CHECK (M != 0 && (M->Style != MAC_STYLE_DEFINE || DisableDefines == 0));
/* We cannot expand an incomplete macro */
if (M->Incomplete) {
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);
}
}
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);
}
+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;
+}
+
+
/* */
/* */
/* */
-/* (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 */
/*****************************************************************************/
-/* Data */
+/* Forwards */
+/*****************************************************************************/
+
+
+
+struct StrBuf;
+
+
+
+/*****************************************************************************/
+/* Data */
/*****************************************************************************/
/* Macro styles */
-#define MAC_STYLE_CLASSIC 0
-#define MAC_STYLE_DEFINE 1
+#define MAC_STYLE_CLASSIC 0
+#define MAC_STYLE_DEFINE 1
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
void MacDef (unsigned Style);
/* Parse a macro definition */
+void MacUndef (const struct StrBuf* Name);
+/* Undefine the macro with the given name. */
+
void MacExpandStart (void);
/* Start expanding the macro in SVal */
int InMacExpansion (void);
/* Return true if we're currently expanding a macro */
+void DisableDefineStyleMacros (void);
+/* Disable define style macros until EnableDefineStyleMacros is called */
+
+void EnableDefineStyleMacros (void);
+/* Re-enable define style macros previously disabled with
+ * DisableDefineStyleMacros.
+ */
+
/* End of macro.h */
+static void DoUnDef (void)
+/* Undefine a macro */
+{
+ /* The function is called with the .UNDEF token in place, because we need
+ * to disable .define macro expansions before reading the next token.
+ * Otherwise the name of the macro would be expanded, so we would never
+ * see it.
+ */
+ DisableDefineStyleMacros ();
+ NextTok ();
+ EnableDefineStyleMacros ();
+
+ /* We expect an identifier */
+ if (CurTok.Tok != TOK_IDENT) {
+ ErrorSkip ("Identifier expected");
+ } else {
+ MacUndef (&CurTok.SVal);
+ NextTok ();
+ }
+}
+
+
+
static void DoUnexpected (void)
/* Got an unexpected keyword */
{
/*****************************************************************************/
-/* Table data */
+/* Table data */
/*****************************************************************************/
{ ccKeepToken, DoConditionals }, /* .IFP816 */
{ ccKeepToken, DoConditionals }, /* .IFPC02 */
{ ccKeepToken, DoConditionals }, /* .IFPSC02 */
- { ccKeepToken, DoConditionals }, /* .IFREF */
+ { ccKeepToken, DoConditionals }, /* .IFREF */
{ ccNone, DoImport },
{ ccNone, DoImportZP },
{ ccNone, DoIncBin },
{ ccNone, DoInvalid }, /* .MID */
{ ccNone, DoUnexpected }, /* .MIN */
{ ccNone, DoNull },
- { ccNone, DoOrg },
+ { ccNone, DoOrg },
{ ccNone, DoOut },
{ ccNone, DoP02 },
{ ccNone, DoP816 },
{ ccNone, DoTag },
{ ccNone, DoUnexpected }, /* .TCOUNT */
{ ccNone, DoUnexpected }, /* .TIME */
+ { ccKeepToken, DoUnDef },
{ ccNone, DoUnion },
{ ccNone, DoUnexpected }, /* .VERSION */
{ ccNone, DoWarning },
- { ccNone, DoWord },
+ { ccNone, DoWord },
{ ccNone, DoUnexpected }, /* .XMATCH */
{ ccNone, DoZeropage },
};
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/