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 */
/* 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 {
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;
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
+/* Define style macros disabled if != 0 */
+static unsigned DisableDefines = 0;
+
/*****************************************************************************/
/* 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);
+ }
}
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);
+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 */
{
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) {
NextTok ();
}
+ /* Reset the Incomplete flag now that parsing is done */
+ M->Incomplete = 0;
+
Done:
/* Switch out of raw token mode */
LeaveRawTokenMode ();
+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
-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) {
+ 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);
}
}
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;
+}
+
+