/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (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 */
/* common */
#include "check.h"
#include "hashstr.h"
+#include "hashtab.h"
#include "xmalloc.h"
/* ca65 */
#include "condasm.h"
#include "error.h"
#include "global.h"
+#include "instr.h"
#include "istack.h"
+#include "lineinfo.h"
#include "nexttok.h"
#include "pseudo.h"
#include "toklist.h"
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key);
+/* Generate the hash over a key. */
+
+static const void* HT_GetKey (void* Entry);
+/* Given a pointer to the user entry data, return a pointer to the key */
+
+static HashNode* HT_GetHashNode (void* Entry);
+/* Given a pointer to the user entry data, return a pointer to the hash node */
+
+static int HT_Compare (const void* Key1, const void* Key2);
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
+
+
+
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Struct that describes an identifer (macro param, local list) */
-typedef struct IdDesc_ IdDesc;
-struct IdDesc_ {
- IdDesc* Next; /* Linked list */
- char Id [1]; /* Identifier, dynamically allocated */
+typedef struct IdDesc IdDesc;
+struct IdDesc {
+ IdDesc* Next; /* Linked list */
+ StrBuf Id; /* Identifier, dynamically allocated */
};
/* Struct that describes a macro definition */
-typedef struct Macro_ Macro;
-struct Macro_ {
- Macro* Next; /* Next macro with same hash */
+typedef struct Macro Macro;
+struct Macro {
+ HashNode Node; /* Hash list node */
Macro* List; /* List of all macros */
unsigned LocalCount; /* Count of local symbols */
IdDesc* Locals; /* List of local symbols */
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 */
- char Name [1]; /* Macro name, dynamically allocated */
+ unsigned char Incomplete; /* Macro is currently built */
};
-/* Macro hash table */
-#define HASHTAB_SIZE 117
-static Macro* MacroTab [HASHTAB_SIZE];
+/* Hash table functions */
+static const HashFunctions HashFunc = {
+ HT_GenHash,
+ HT_GetKey,
+ HT_GetHashNode,
+ HT_Compare
+};
-/* Global macro data */
-static Macro* MacroRoot = 0; /* List of all macros */
+/* Macro hash table */
+static HashTable MacroTab = STATIC_HASHTABLE_INITIALIZER (117, &HashFunc);
/* 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 */
+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 */
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;
/* Counter to create local names for symbols */
static unsigned LocalName = 0;
+/* Define style macros disabled if != 0 */
+static unsigned DisableDefines = 0;
+
+
+
+/*****************************************************************************/
+/* Hash table functions */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key)
+/* Generate the hash over a key. */
+{
+ return HashBuf (Key);
+}
+
+
+
+static const void* HT_GetKey (void* Entry)
+/* Given a pointer to the user entry data, return a pointer to the index */
+{
+ return &((Macro*) Entry)->Name;
+}
+
+
+
+static HashNode* HT_GetHashNode (void* Entry)
+/* Given a pointer to the user entry data, return a pointer to the hash node */
+{
+ return &((Macro*) Entry)->Node;
+}
+
+
+
+static int HT_Compare (const void* Key1, const void* Key2)
+/* Compare two keys. The function must return a value less than zero if
+ * Key1 is smaller than Key2, zero if both are equal, and a value greater
+ * than zero if Key1 is greater then Key2.
+ */
+{
+ return SB_Compare (Key1, Key2);
+}
+
/*****************************************************************************/
-static IdDesc* NewIdDesc (const char* Id)
+static IdDesc* NewIdDesc (const StrBuf* Id)
/* Create a new IdDesc, initialize and return it */
{
/* Allocate memory */
- unsigned Len = strlen (Id);
- IdDesc* I = xmalloc (sizeof (IdDesc) + Len);
+ IdDesc* ID = xmalloc (sizeof (IdDesc));
/* Initialize the struct */
- I->Next = 0;
- memcpy (I->Id, Id, Len);
- I->Id [Len] = '\0';
+ ID->Next = 0;
+ SB_Init (&ID->Id);
+ SB_Copy (&ID->Id, Id);
/* Return the new struct */
- return I;
+ return ID;
}
-static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
+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);
+ }
+}
+
+
+
+static Macro* NewMacro (const StrBuf* Name, unsigned char Style)
/* Generate a new macro entry, initialize and return it */
{
/* Allocate memory */
- unsigned Len = strlen (Name);
- Macro* M = xmalloc (sizeof (Macro) + Len);
+ Macro* M = xmalloc (sizeof (Macro));
/* Initialize the macro struct */
+ InitHashNode (&M->Node, M);
M->LocalCount = 0;
+ M->Locals = 0;
M->ParamCount = 0;
M->Params = 0;
M->TokCount = 0;
M->TokRoot = 0;
M->TokLast = 0;
+ SB_Init (&M->Name);
+ SB_Copy (&M->Name, Name);
+ M->Expansions = 0;
M->Style = Style;
- memcpy (M->Name, Name, Len);
- M->Name [Len] = '\0';
-
- /* Insert the macro into the global macro list */
- M->List = MacroRoot;
- MacroRoot = M;
+ M->Incomplete = 1;
/* Insert the macro into the hash table */
- M->Next = MacroTab [HashVal];
- MacroTab [HashVal] = M;
+ HT_Insert (&MacroTab, &M->Node);
/* Return the new macro struct */
return M;
+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 */
{
/* 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;
/* One macro expansion less */
--MacExpansions;
- /* Free the parameter list */
+ /* No longer expanding this macro */
+ --E->M->Expansions;
+
+ /* Free the parameter lists */
for (I = 0; I < E->ParamCount; ++I) {
- xfree (E->Params [I]);
+ /* Free one parameter list */
+ TokNode* N = E->Params[I];
+ while (N) {
+ TokNode* P = N->Next;
+ FreeTokNode (N);
+ N = P;
+ }
}
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);
/* 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 (ERR_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 ();
}
}
-static Macro* MacFind (const char* Name, unsigned HashVal)
-/* Search for a macro in the hash table */
-{
- /* Search for the identifier */
- Macro* M = MacroTab [HashVal];
- while (M) {
- if (strcmp (Name, M->Name) == 0) {
- return M;
- }
- M = M->Next;
- }
- return 0;
-}
-
-
-
void MacDef (unsigned Style)
/* Parse a macro definition */
{
Macro* M;
- TokNode* T;
- unsigned HashVal;
+ TokNode* N;
int HaveParams;
/* We expect a macro name here */
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
+ if (CurTok.Tok != TOK_IDENT) {
+ Error ("Identifier expected");
MacSkipDef (Style);
return;
+ } else if (!UbiquitousIdents && FindInstruction (&CurTok.SVal) >= 0) {
+ /* The identifier is a name of a 6502 instruction, which is not
+ * allowed if not explicitly enabled.
+ */
+ Error ("Cannot use an instruction as macro name");
+ MacSkipDef (Style);
+ return;
}
- /* Generate the hash value */
- HashVal = HashStr (SVal) % HASHTAB_SIZE;
-
/* Did we already define that macro? */
- if (MacFind (SVal, HashVal) != 0) {
+ if (HT_Find (&MacroTab, &CurTok.SVal) != 0) {
/* Macro is already defined */
- Error (ERR_SYM_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, HashVal, Style);
+ M = NewMacro (&CurTok.SVal, Style);
/* Switch to raw token mode and skip the macro name */
EnterRawTokenMode ();
* otherwise we may have parameters without braces.
*/
if (Style == MAC_STYLE_CLASSIC) {
- HaveParams = 1;
+ HaveParams = 1;
} else {
- if (Tok == TOK_LPAREN) {
- HaveParams = 1;
- NextTok ();
- } else {
- HaveParams = 0;
- }
+ if (CurTok.Tok == TOK_LPAREN) {
+ HaveParams = 1;
+ NextTok ();
+ } else {
+ HaveParams = 0;
+ }
}
/* Parse the parameter list */
if (HaveParams) {
- while (Tok == TOK_IDENT) {
-
- /* Create a struct holding the identifier */
- IdDesc* I = NewIdDesc (SVal);
-
- /* Insert the struct into the list, checking for duplicate idents */
- if (M->ParamCount == 0) {
- M->Params = I;
- } else {
- IdDesc* List = M->Params;
- while (1) {
- if (strcmp (List->Id, SVal) == 0) {
- Error (ERR_SYM_ALREADY_DEFINED, SVal);
- }
- if (List->Next == 0) {
- break;
- } else {
- List = List->Next;
- }
- }
- List->Next = I;
- }
- ++M->ParamCount;
+ while (CurTok.Tok == TOK_IDENT) {
+
+ /* Create a struct holding the identifier */
+ IdDesc* I = NewIdDesc (&CurTok.SVal);
+
+ /* Insert the struct into the list, checking for duplicate idents */
+ if (M->ParamCount == 0) {
+ M->Params = I;
+ } else {
+ IdDesc* List = M->Params;
+ while (1) {
+ if (SB_Compare (&List->Id, &CurTok.SVal) == 0) {
+ Error ("Duplicate symbol `%m%p'", &CurTok.SVal);
+ }
+ if (List->Next == 0) {
+ break;
+ } else {
+ List = List->Next;
+ }
+ }
+ List->Next = I;
+ }
+ ++M->ParamCount;
/* Skip the name */
- NextTok ();
+ NextTok ();
/* Maybe there are more params... */
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
} else {
break;
/* 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) {
- Error (ERR_ENDMACRO_EXPECTED);
+ /* 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) {
NextTok ();
/* Need an identifer */
- if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
+ 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;
}
}
/* 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 (strcmp (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;
/* 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;
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
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;
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 && 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 (strcmp (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
* generated by a user.
*/
- unsigned PrefixLen = (I->Id[0] == LocalStart);
- sprintf (SVal, "%.*sLOCAL-MACRO-SYMBOL-%04X", PrefixLen,
- I->Id, Mac->LocalStart + Index);
+ if (SB_At (&I->Id, 0) == LocalStart) {
+ /* Must generate a local symbol */
+ SB_Printf (&CurTok.SVal, "%cLOCAL-MACRO_SYMBOL-%04X",
+ LocalStart, Mac->LocalStart + Index);
+ } else {
+ /* Global symbol */
+ SB_Printf (&CurTok.SVal, "LOCAL-MACRO_SYMBOL-%04X",
+ Mac->LocalStart + Index);
+ }
break;
}
/* Next symbol */
if (Mac->Final) {
/* Set the final token and remove it */
- TokSet (Mac->Final);
+ TokSet (Mac->Final, Mac->LISlot);
FreeTokNode (Mac->Final);
Mac->Final = 0;
-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) {
- Error (ERR_TOO_MANY_PARAMS);
- SkipUntilSep ();
+ 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 */
+ /* Read tokens for one parameter, accept empty params */
Last = 0;
- while (!TokIsSep (Tok)) {
+ while (CurTok.Tok != Term && CurTok.Tok != TOK_SEP) {
TokNode* T;
/* Check for end of file */
- if (Tok == TOK_EOF) {
- Error (ERR_UNEXPECTED_EOF);
- return;
+ if (CurTok.Tok == TOK_EOF) {
+ Error ("Unexpected end of file");
+ FreeMacExp (E);
+ return;
}
/* Get the next token in a node */
if (Last == 0) {
E->Params [E->ParamCount] = T;
} else {
- Last->Next = T;
+ Last->Next = T;
}
- Last = T;
+ Last = T;
/* And skip it... */
NextTok ();
/* 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 (CurTok.Tok == TOK_SEP) {
+ Error ("End of line encountered within macro argument");
+ break;
+ }
+ NextTok ();
+ }
+
/* Check for a comma */
- if (Tok == TOK_COMMA) {
- NextTok ();
- } else {
- break;
- }
+ if (CurTok.Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
}
+ /* We must be at end of line now, otherwise something is wrong */
+ ExpectSep ();
+
/* Insert a new token input function */
PushInput (MacExpand, E, ".MACRO");
}
-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 ();
/* Read the actual parameters */
while (Count--) {
- TokNode* Last;
+ TokNode* Last;
+
+ /* The macro may optionally be enclosed in curly braces */
+ token_t Term = GetTokListTerm (TOK_COMMA);
/* Check if there is really a parameter */
- if (TokIsSep (Tok) || Tok == TOK_COMMA) {
- Error (ERR_MACRO_PARAM_EXPECTED);
- SkipUntilSep ();
- return;
- }
+ if (TokIsSep (CurTok.Tok) || CurTok.Tok == Term) {
+ ErrorSkip ("Macro parameter #%u is empty", E->ParamCount+1);
+ FreeMacExp (E);
+ return;
+ }
/* Read tokens for one parameter */
Last = 0;
}
Last = T;
- /* And skip it... */
- NextTok ();
+ /* And skip it... */
+ NextTok ();
- } while (Tok != TOK_COMMA && !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 (CurTok.Tok)) {
+ Error ("End of line encountered within macro argument");
+ break;
+ }
+ NextTok ();
+ }
/* Check for a comma */
if (Count > 0) {
- if (Tok == TOK_COMMA) {
+ if (CurTok.Tok == TOK_COMMA) {
NextTok ();
} else {
- Error (ERR_COMMA_EXPECTED);
+ Error ("`,' expected");
}
}
}
/* Macro expansion will overwrite the current token. This is a problem
* for define style macros since these are called from the scanner level.
- * To avoid it, remember the current token and re-insert it if macro
+ * To avoid it, remember the current token and re-insert it, once macro
* expansion is done.
*/
E->Final = NewTokNode ();
void MacExpandStart (void)
/* Start expanding the macro in SVal */
{
+ MacExp* E;
+
/* Search for the macro */
- Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
- 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);
}
}
-int IsMacro (const char* Name)
+int IsMacro (const StrBuf* Name)
/* Return true if the given name is the name of a macro */
{
- return MacFind (Name, HashStr (Name) % HASHTAB_SIZE) != 0;
+ return (HT_Find (&MacroTab, Name) != 0);
}
-int IsDefine (const char* Name)
+int IsDefine (const StrBuf* Name)
/* Return true if the given name is the name of a define style macro */
{
- Macro* M = MacFind (Name, HashStr (Name) % HASHTAB_SIZE);
+ 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;
+}