]> git.sur5r.net Git - cc65/blobdiff - src/ca65/macro.c
New module strstack
[cc65] / src / ca65 / macro.c
index 0b3cc9caacacd7e160b025a45b5964c5b87dcabe..3b60297d09175250035155613819878474434a2e 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (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       */
 /* common */
 #include "check.h"
 #include "hashstr.h"
+#include "hashtab.h"
 #include "xmalloc.h"
 
 /* ca65 */
 #include "condasm.h"
 #include "error.h"
+#include "global.h"
 #include "istack.h"
 #include "nexttok.h"
 #include "pseudo.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 */
@@ -83,25 +108,32 @@ struct Macro_ {
     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? */
-    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 */
+    unsigned   ParamCount;     /* Number of actual parameters */
     TokNode**  Params;         /* List of actual parameters */
-    TokNode*   ParamExp;       /* Node for expanding parameters */
+    TokNode*   ParamExp;       /* Node for expanding parameters */
 };
 
 /* Number of active macro expansions */
@@ -115,6 +147,47 @@ 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);
+}
+
+
+
 /*****************************************************************************/
 /*                                          Code                                    */
 /*****************************************************************************/
@@ -139,7 +212,7 @@ static IdDesc* NewIdDesc (const char* Id)
 
 
 
-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 */
@@ -147,23 +220,23 @@ static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
     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;
@@ -238,7 +311,7 @@ static void MacSkipDef (unsigned Style)
        if (Tok != TOK_EOF) {
            SkipUntilSep ();
        } else {
-           Error (ERR_ENDMACRO_EXPECTED);
+           Error ("`.ENDMACRO' expected");
        }
     } else {
        /* Skip until end of line */
@@ -248,51 +321,31 @@ static void MacSkipDef (unsigned Style)
 
 
 
-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 ();
@@ -327,8 +380,8 @@ void MacDef (unsigned Style)
                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 {
@@ -376,12 +429,12 @@ void MacDef (unsigned Style)
            }
            /* May not have end of file in a macro definition */
            if (Tok == TOK_EOF) {
-               Error (ERR_ENDMACRO_EXPECTED);
+               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;
            }
        }
@@ -398,7 +451,7 @@ void MacDef (unsigned Style)
 
                /* Need an identifer */
                if (Tok != TOK_IDENT) {
-                   Error (ERR_IDENT_EXPECTED);
+                   Error ("Identifier expected");
                    SkipUntilSep ();
                    break;
                }
@@ -541,8 +594,14 @@ static int MacExpand (void* Data)
                    IdDesc* I = Mac->M->Locals;
                    while (I) {
                        if (strcmp (SVal, I->Id) == 0) {
-                           /* This is in fact a local symbol, change the name */
-                           sprintf (SVal, "___%04X__", Mac->LocalStart + Index);
+                           /* 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 */
@@ -597,14 +656,14 @@ static void StartExpClassic (Macro* M)
     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;
        }
 
@@ -616,7 +675,7 @@ static void StartExpClassic (Macro* M)
 
            /* Check for end of file */
            if (Tok == TOK_EOF) {
-               Error (ERR_UNEXPECTED_EOF);
+               Error ("Unexpected end of file");
                return;
            }
 
@@ -672,8 +731,8 @@ static void StartExpDefine (Macro* M)
                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;
                }
@@ -689,16 +748,16 @@ static void StartExpDefine (Macro* M)
 
                    /* 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;
@@ -708,7 +767,7 @@ static void StartExpDefine (Macro* M)
                    if (Tok == TOK_COMMA) {
                        NextTok ();
                    } else {
-                       Error (ERR_COMMA_EXPECTED);
+                       Error ("`,' expected");
                    }
                }
     }
@@ -730,7 +789,7 @@ void MacExpandStart (void)
 /* Start expanding the macro in SVal */
 {
     /* Search for the macro */
-    Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+    Macro* M = HT_FindEntry (&MacroTab, SVal);
     CHECK (M != 0);
 
     /* Call the apropriate subroutine */
@@ -758,7 +817,7 @@ void MacAbort (void)
 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);
 }
 
 
@@ -766,7 +825,7 @@ int IsMacro (const char* Name)
 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);
 }