/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2003 Ullrich von Bassewitz */
+/* Römerstraße 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <stdio.h>
#include <string.h>
-#include "../common/hashstr.h"
+/* common */
+#include "check.h"
+#include "hashstr.h"
+#include "hashtab.h"
+#include "xmalloc.h"
-#include "mem.h"
+/* ca65 */
+#include "condasm.h"
#include "error.h"
-#include "scanner.h"
-#include "toknode.h"
+#include "global.h"
+#include "istack.h"
+#include "nexttok.h"
#include "pseudo.h"
+#include "toklist.h"
#include "macro.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 */
+typedef struct IdDesc IdDesc;
+struct IdDesc {
+ IdDesc* Next; /* Linked list */
char Id [1]; /* 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 */
char Name [1]; /* Macro name, dynamically allocated */
};
+/* Hash table functions */
+static const HashFunctions HashFunc = {
+ HT_GenHash,
+ HT_GetKey,
+ HT_GetHashNode,
+ HT_Compare
+};
+
/* Macro hash table */
-#define HASHTAB_SIZE 117
-static Macro* MacroTab [HASHTAB_SIZE];
+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? */
+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 */
+ unsigned ParamCount; /* Number of actual parameters */
TokNode** Params; /* List of actual parameters */
- TokNode* ParamExp; /* Node for expanding parameters */
+ TokNode* ParamExp; /* Node for expanding parameters */
};
-/* Data for macro expansions */
-#define MAX_MACRO_EXPANSIONS 255
-static unsigned MacroNesting = 0;
-static MacExp* CurMac = 0;
-static unsigned LocalName = 0;
+/* Number of active macro expansions */
+static unsigned MacExpansions = 0;
+
+/* Flag if a macro expansion should get aborted */
+static int DoMacAbort = 0;
+
+/* Counter to create local names for symbols */
+static unsigned LocalName = 0;
+
+
+
+/*****************************************************************************/
+/* Hash table functions */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key)
+/* Generate the hash over a key. */
+{
+ return HashStr (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 strcmp (Key1, Key2);
+}
{
/* Allocate memory */
unsigned Len = strlen (Id);
- IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
+ IdDesc* I = xmalloc (sizeof (IdDesc) + Len);
/* Initialize the struct */
I->Next = 0;
-static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
+static Macro* NewMacro (const char* 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) + Len);
/* 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;
M->Style = Style;
- memcpy (M->Name, Name, Len);
- M->Name [Len] = '\0';
+ memcpy (M->Name, Name, Len+1);
/* Insert the macro into the global macro list */
M->List = MacroRoot;
MacroRoot = M;
/* 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;
unsigned I;
/* Allocate memory */
- MacExp* E = Xmalloc (sizeof (MacExp));
+ MacExp* E = xmalloc (sizeof (MacExp));
/* Initialize the data */
E->M = M;
+ E->IfSP = GetIfStack ();
E->Exp = M->TokRoot;
E->Final = 0;
E->LocalStart = LocalName;
LocalName += M->LocalCount;
E->ParamCount = 0;
- E->Params = Xmalloc (M->ParamCount * sizeof (TokNode*));
+ E->Params = xmalloc (M->ParamCount * sizeof (TokNode*));
E->ParamExp = 0;
for (I = 0; I < M->ParamCount; ++I) {
E->Params [I] = 0;
}
- /* And return it... */
- return E;
-}
-
+ /* One macro expansion more */
+ ++MacExpansions;
-
-static void MacInsertExp (MacExp* E)
-/* Insert a macro expansion into the list */
-{
- E->Next = CurMac;
- CurMac = E;
- ++MacroNesting;
+ /* Return the new macro expansion */
+ return E;
}
-static void FreeMacExp (void)
+static void FreeMacExp (MacExp* E)
/* Remove and free the current macro expansion */
{
unsigned I;
- MacExp* E;
+
+ /* One macro expansion less */
+ --MacExpansions;
/* Free the parameter list */
- for (I = 0; I < CurMac->ParamCount; ++I) {
- Xfree (CurMac->Params [I]);
+ for (I = 0; I < E->ParamCount; ++I) {
+ xfree (E->Params [I]);
}
- Xfree (CurMac->Params);
+ xfree (E->Params);
/* Free the final token if we have one */
- if (CurMac->Final) {
- FreeTokNode (CurMac->Final);
+ if (E->Final) {
+ FreeTokNode (E->Final);
}
- /* Reset the list pointer */
- E = CurMac;
- CurMac = E->Next;
- --MacroNesting;
-
/* Free the structure itself */
- Xfree (E);
+ xfree (E);
}
if (Tok != TOK_EOF) {
SkipUntilSep ();
} else {
- Error (ERR_ENDMACRO_EXPECTED);
+ Error ("`.ENDMACRO' expected");
}
} else {
/* Skip until end of line */
-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;
int HaveParams;
/* We expect a macro name here */
if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
+ Error ("Identifier expected");
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, SVal) != 0) {
/* Macro is already defined */
- Error (ERR_SYM_ALREADY_DEFINED, SVal);
+ Error ("A macro named `%s' is already defined", SVal);
/* Skip tokens until we reach the final .endmacro */
MacSkipDef (Style);
return;
}
/* Define the macro */
- M = NewMacro (SVal, HashVal, Style);
+ M = NewMacro (SVal, Style);
+
+ /* Switch to raw token mode and skip the macro name */
+ EnterRawTokenMode ();
NextTok ();
/* If we have a DEFINE style macro, we may have parameters in braces,
IdDesc* List = M->Params;
while (1) {
if (strcmp (List->Id, SVal) == 0) {
- Error (ERR_SYM_ALREADY_DEFINED, SVal);
- }
+ Error ("Duplicate symbol `%s'", SVal);
+ }
if (List->Next == 0) {
break;
} else {
}
/* May not have end of file in a macro definition */
if (Tok == TOK_EOF) {
- Error (ERR_ENDMACRO_EXPECTED);
- return;
+ Error ("`.ENDMACRO' expected");
+ goto Done;
}
} else {
/* Accept a newline or end of file for new style macros */
- if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ if (TokIsSep (Tok)) {
break;
}
}
IdDesc* I;
- /* Skip .local or comma */
+ /* Skip .local or comma */
NextTok ();
/* Need an identifer */
if (Tok != TOK_IDENT) {
- Error (ERR_IDENT_EXPECTED);
+ Error ("Identifier expected");
SkipUntilSep ();
break;
}
if (Style == MAC_STYLE_CLASSIC) {
NextTok ();
}
+
+Done:
+ /* Switch out of raw token mode */
+ LeaveRawTokenMode ();
+}
+
+
+
+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
+ * a macro, return false.
+ */
+{
+ /* Cast the Data pointer to the actual data structure */
+ MacExp* Mac = (MacExp*) Data;
+
+ /* Check if we should abort this macro */
+ if (DoMacAbort) {
+
+ /* Reset the flag */
+ DoMacAbort = 0;
+
+ /* Abort any open .IF statements in this macro expansion */
+ CleanupIfStack (Mac->IfSP);
+
+ /* Terminate macro expansion */
+ goto MacEnd;
+ }
+
+ /* We're expanding a macro. Check if we are expanding one of the
+ * macro parameters.
+ */
+ if (Mac->ParamExp) {
+
+ /* Ok, use token from parameter list */
+ TokSet (Mac->ParamExp);
+
+ /* Set pointer to next token */
+ Mac->ParamExp = Mac->ParamExp->Next;
+
+ /* Done */
+ return 1;
+
+ }
+
+ /* We're not expanding macro parameters. Check if we have tokens left from
+ * the macro itself.
+ */
+ if (Mac->Exp) {
+
+ /* Use next macro token */
+ TokSet (Mac->Exp);
+
+ /* 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;
+ return 1;
+ }
+
+ /* Is it the name of a macro parameter? */
+ if (Tok == TOK_MACPARAM) {
+
+ /* Start to expand the parameter token list */
+ Mac->ParamExp = Mac->Params [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) {
+ /* Search for the local symbol in the list */
+ unsigned Index = 0;
+ IdDesc* I = Mac->M->Locals;
+ while (I) {
+ if (strcmp (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);
+ break;
+ }
+ /* Next symbol */
+ ++Index;
+ I = I->Next;
+ }
+
+ /* Done */
+ return 1;
+ }
+
+ /* The token was successfully set */
+ return 1;
+
+ }
+
+ /* No more macro tokens. Do we have a final token? */
+ if (Mac->Final) {
+
+ /* Set the final token and remove it */
+ TokSet (Mac->Final);
+ FreeTokNode (Mac->Final);
+ Mac->Final = 0;
+
+ /* The token was successfully set */
+ return 1;
+
+ }
+
+MacEnd:
+ /* End of macro expansion */
+ FreeMacExp (Mac);
+
+ /* Pop the input function */
+ PopInput ();
+
+ /* No token available */
+ return 0;
}
E = NewMacExp (M);
/* Read the actual parameters */
- while (Tok != TOK_SEP && Tok != TOK_EOF) {
+ while (!TokIsSep (Tok)) {
TokNode* Last;
/* Check for maximum parameter count */
if (E->ParamCount >= M->ParamCount) {
- Error (ERR_TOO_MANY_PARAMS);
- SkipUntilSep ();
+ Error ("Too many macro parameters");
+ SkipUntilSep ();
break;
}
/* Check for end of file */
if (Tok == TOK_EOF) {
- Error (ERR_SYNTAX);
+ Error ("Unexpected end of file");
return;
}
}
}
- /* Insert the newly created structure into the expansion list */
- MacInsertExp (E);
+ /* Insert a new token input function */
+ PushInput (MacExpand, E, ".MACRO");
}
TokNode* Last;
/* Check if there is really a parameter */
- if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
- Error (ERR_MACRO_PARAM_EXPECTED);
+ if (TokIsSep (Tok) || Tok == TOK_COMMA) {
+ Error ("Macro parameter expected");
SkipUntilSep ();
return;
}
/* Insert it into the list */
if (Last == 0) {
- E->Params [E->ParamCount] = T;
+ E->Params [E->ParamCount] = T;
} else {
- Last->Next = T;
+ Last->Next = T;
}
Last = T;
/* And skip it... */
NextTok ();
- } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
+ } while (Tok != TOK_COMMA && !TokIsSep (Tok));
/* One parameter more */
++E->ParamCount;
if (Tok == TOK_COMMA) {
NextTok ();
} else {
- Error (ERR_COMMA_EXPECTED);
+ Error ("`,' expected");
}
}
}
*/
E->Final = NewTokNode ();
- /* Insert the newly created structure into the expansion list */
- MacInsertExp (E);
+ /* Insert a new token input function */
+ PushInput (MacExpand, E, ".DEFINE");
}
void MacExpandStart (void)
/* Start expanding the macro in SVal */
{
- Macro* M;
-
- /* Beware of runoff macros */
- if (MacroNesting == MAX_MACRO_EXPANSIONS) {
- Fatal (FAT_MACRO_NESTING);
- }
-
/* Search for the macro */
- M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+ Macro* M = HT_FindEntry (&MacroTab, SVal);
CHECK (M != 0);
/* 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);
- }
-}
-
-
-
-int MacExpand (void)
-/* 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
- * a macro, return false.
- */
-{
- if (MacroNesting == 0) {
- /* Not expanding a macro */
- return 0;
- }
-
- /* We're expanding a macro. Check if we are expanding one of the
- * macro parameters.
- */
- if (CurMac->ParamExp) {
-
- /* Ok, use token from parameter list */
- TokSet (CurMac->ParamExp);
-
- /* Set pointer to next token */
- CurMac->ParamExp = CurMac->ParamExp->Next;
-
- /* Done */
- return 1;
-
- } else if (CurMac->Exp) {
-
- /* We're not expanding a parameter, use next macro token */
- TokSet (CurMac->Exp);
-
- /* Set pointer to next token */
- CurMac->Exp = CurMac->Exp->Next;
-
- /* Is it a request for actual parameter count? */
- if (Tok == TOK_PARAMCOUNT) {
- Tok = TOK_INTCON;
- IVal = CurMac->ParamCount;
- return 1;
- }
-
- /* Is it an .exitmacro command? */
- if (Tok == TOK_EXITMACRO) {
- /* Forced exit from macro expansion */
- FreeMacExp ();
- return MacExpand ();
- }
-
- /* Is it the name of a macro parameter? */
- if (Tok == TOK_MACPARAM) {
-
- /* Start to expand the parameter token list */
- CurMac->ParamExp = CurMac->Params [IVal];
-
- /* Recursive call to expand the parameter */
- return MacExpand ();
- }
-
- /* If it's an identifier, it may in fact be a local symbol */
- if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
- /* Search for the local symbol in the list */
- unsigned Index = 0;
- IdDesc* I = CurMac->M->Locals;
- while (I) {
- if (strcmp (SVal, I->Id) == 0) {
- /* This is in fact a local symbol, change the name */
- sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
- break;
- }
- /* Next symbol */
- ++Index;
- I = I->Next;
- }
-
- /* Done */
- return 1;
- }
-
- /* The token was successfully set */
- return 1;
-
- } else if (CurMac->Final) {
-
- /* Set the final token and remove it */
- TokSet (CurMac->Final);
- FreeTokNode (CurMac->Final);
- CurMac->Final = 0;
-
- /* The token was successfully set */
- return 1;
-
- } else {
-
- /* End of macro expansion */
- FreeMacExp ();
- return MacExpand ();
-
+ default: Internal ("Invalid macro style: %d", M->Style);
}
}
/* Abort the current macro expansion */
{
/* Must have an expansion */
- CHECK (CurMac != 0);
+ CHECK (MacExpansions > 0);
- /* Free current structure */
- FreeMacExp ();
+ /* Set a flag so macro expansion will terminate on the next call */
+ DoMacAbort = 1;
}
int IsMacro (const char* Name)
/* Return true if the given name is the name of a macro */
{
- return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
+ return (HT_Find (&MacroTab, Name) != 0);
}
int IsDefine (const char* Name)
/* Return true if the given name is the name of a define style macro */
{
- Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+ Macro* M = HT_FindEntry (&MacroTab, Name);
return (M != 0 && M->Style == MAC_STYLE_DEFINE);
}
int InMacExpansion (void)
/* Return true if we're currently expanding a macro */
{
- return MacroNesting != 0;
+ return (MacExpansions > 0);
}