]> git.sur5r.net Git - cc65/commitdiff
Rewrote most of the #pragma parsing code. I'm still not satisfied, but at
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 13 Oct 2009 21:24:32 +0000 (21:24 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Tue, 13 Oct 2009 21:24:32 +0000 (21:24 +0000)
least, it's a bit better than before. #pragma warn (...) is now used to switch
single warnings instead of a global on/off switch.

git-svn-id: svn://svn.cc65.org/cc65/trunk@4362 b7a2c559-68d2-44c3-8de9-860c34a00d81

doc/cc65.sgml
src/cc65/pragma.c
src/cc65/scanstrbuf.c
src/cc65/scanstrbuf.h

index a1daf3deaf6f9bbe02128300196e9523c189b4d5..2226cc26fcf9e450cc7bc9a2b475d94ddda5b000 100644 (file)
@@ -118,7 +118,7 @@ Here is a description of all the command line options:
   Tells the compiler to generate code that checks for stack overflows. See
   <tt><ref id="pragma-checkstack" name="#pragma&nbsp;checkstack"></tt> for an
   explanation of this feature.
-                                
+
 
   <tag><tt>--code-name seg</tt></tag>
 
@@ -731,7 +731,7 @@ If the first parameter is <tt/push/, the old value is saved onto a stack
 before changing it. The value may later be restored by using the <tt/pop/
 parameter with the <tt/#pragma/.
 
-<sect1><tt>#pragma bssseg (&lsqb;push,&rsqb;&lt;name&gt;)</tt><p>
+<sect1><tt>#pragma bssseg (&lsqb;push,&rsqb; &lt;name&gt;)</tt><p>
 
   This pragma changes the name used for the BSS segment (the BSS segment
   is used to store uninitialized data). The argument is a string enclosed
@@ -787,7 +787,7 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
-<sect1><tt>#pragma checkstack ([push,]on|off)</tt><label id="pragma-checkstack"><p>
+<sect1><tt>#pragma checkstack ([push,] on|off)</tt><label id="pragma-checkstack"><p>
 
   Tells the compiler to insert calls to a stack checking subroutine to detect
   stack overflows. The stack checking code will lead to somewhat larger and
@@ -800,7 +800,7 @@ parameter with the <tt/#pragma/.
 
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
-<sect1><tt>#pragma codeseg ([push,]&lt;name&gt;)</tt><p>
+<sect1><tt>#pragma codeseg ([push,] &lt;name&gt;)</tt><p>
 
   This pragma changes the name used for the CODE segment (the CODE segment
   is used to store executable code). The argument is a string enclosed in
@@ -818,7 +818,7 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
-<sect1><tt>#pragma codesize ([push,]&lt;int&gt;)</tt><label id="pragma-codesize"><p>
+<sect1><tt>#pragma codesize ([push,] &lt;int&gt;)</tt><label id="pragma-codesize"><p>
 
   This pragma allows finer control about speed vs. size decisions in the code
   generation and optimization phase. It gives the allowed size increase factor
@@ -828,7 +828,7 @@ parameter with the <tt/#pragma/.
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
 
-<sect1><tt>#pragma dataseg ([push,]&lt;name&gt;)</tt><p>
+<sect1><tt>#pragma dataseg ([push,] &lt;name&gt;)</tt><p>
 
   This pragma changes the name used for the DATA segment (the DATA segment
   is used to store initialized data). The argument is a string enclosed in
@@ -846,7 +846,7 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
-<sect1><tt>#pragma optimize ([push,]on|off)</tt><label id="pragma-optimize"><p>
+<sect1><tt>#pragma optimize ([push,] on|off)</tt><label id="pragma-optimize"><p>
 
   Switch optimization on or off. If the argument is "off", optimization is
   disabled, otherwise it is enabled. Please note that this pragma only effects
@@ -862,7 +862,7 @@ parameter with the <tt/#pragma/.
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
 
-<sect1><tt>#pragma rodataseg ([push,]&lt;name&gt;)</tt><p>
+<sect1><tt>#pragma rodataseg ([push,] &lt;name&gt;)</tt><p>
 
   This pragma changes the name used for the RODATA segment (the RODATA
   segment is used to store readonly data). The argument is a string
@@ -880,7 +880,7 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
-<sect1><tt>#pragma regvaraddr ([push,]on|off)</tt><p>
+<sect1><tt>#pragma regvaraddr ([push,] on|off)</tt><p>
 
   The compiler does not allow to take the address of register variables.
   The regvaraddr pragma changes this. Taking the address of a register
@@ -904,7 +904,7 @@ parameter with the <tt/#pragma/.
   </verb></tscreen>
 
 
-<sect1><tt>#pragma regvars ([push,]on|off)</tt><label id="pragma-regvars"><p>
+<sect1><tt>#pragma regvars ([push,] on|off)</tt><label id="pragma-regvars"><p>
 
   Enables or disables use of register variables. If register variables are
   disabled (the default), the <tt/register/ keyword is ignored. Register
@@ -914,7 +914,7 @@ parameter with the <tt/#pragma/.
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
 
-<sect1><tt>#pragma signedchars ([push,]on|off)</tt><label id="pragma-signedchars"><p>
+<sect1><tt>#pragma signedchars ([push,] on|off)</tt><label id="pragma-signedchars"><p>
 
   Changes the signedness of the default character type. If the argument is
   "on", default characters are signed, otherwise characters are unsigned.
@@ -925,7 +925,7 @@ parameter with the <tt/#pragma/.
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
 
-<sect1><tt>#pragma staticlocals ([push,]on|off)</tt><label id="pragma-staticlocals"<p>
+<sect1><tt>#pragma staticlocals ([push,] on|off)</tt><label id="pragma-staticlocals"<p>
 
   Use variables in the bss segment instead of variables on the stack. This
   pragma changes the default set by the compiler option <tt/-Cl/. If the
@@ -935,13 +935,13 @@ parameter with the <tt/#pragma/.
   The <tt/#pragma/ understands the push and pop parameters as explained above.
 
 
-<sect1><tt>#pragma warn ([push,]on|off)</tt><label id="pragma-warn"><p>
-
-  Switch compiler warnings on or off. If the argument is "off", warnings are
-  disabled, otherwise they're enabled. The default is "on", but may be changed
-  with the <tt/<ref name="-W" id="option-W">/ compiler option.
+<sect1><tt>#pragma warn (name, [push,] on|off)</tt><label id="pragma-warn"><p>
 
-  The <tt/#pragma/ understands the push and pop parameters as explained above.
+  Switch compiler warnings on or off. "name" is the name of a warning (see the
+  <tt/<ref name="-W" id="option-W">/ compiler option for a list). The name is
+  either followed by "pop", which restores the last pushed state, or by "on" or
+  "off", optionally preceeded by "push" to push the current state before
+  changing it.
 
 
 <sect1><tt>#pragma zpsym (&lt;name&gt;)</tt><p>
index 108f866142e7d1643f23335a4aaaea0ff069880f..47f4da0afda46fe22ff422e57ccd79c9a2cbc9bd 100644 (file)
@@ -37,6 +37,7 @@
 #include <string.h>
 
 /* common */
+#include "chartype.h"
 #include "segnames.h"
 #include "tgttrans.h"
 
@@ -84,9 +85,9 @@ static const struct Pragma {
     const char*        Key;            /* Keyword */
     pragma_t           Tok;            /* Token */
 } Pragmas[PR_COUNT] = {
-    {  "bssseg",       PR_BSSSEG       },
+    {          "bssseg",       PR_BSSSEG       },
     {   "charmap",      PR_CHARMAP      },
-    {  "checkstack",   PR_CHECKSTACK   },
+    {          "checkstack",   PR_CHECKSTACK   },
     {   "codeseg",     PR_CODESEG      },
     {   "codesize",     PR_CODESIZE     },
     {   "dataseg",     PR_DATASEG      },
@@ -94,16 +95,24 @@ static const struct Pragma {
     {   "regvaraddr",  PR_REGVARADDR   },
     {   "regvars",      PR_REGVARS      },
     {   "rodataseg",   PR_RODATASEG    },
-    {  "signedchars",  PR_SIGNEDCHARS  },
-    {  "staticlocals", PR_STATICLOCALS },
+    {          "signedchars",  PR_SIGNEDCHARS  },
+    {          "staticlocals", PR_STATICLOCALS },
     {   "warn",         PR_WARN         },
     {   "zpsym",               PR_ZPSYM        },
 };
 
+/* Result of ParsePushPop */
+typedef enum {
+    PP_NONE,
+    PP_POP,
+    PP_PUSH,
+    PP_ERROR,
+} PushPopResult;
+
 
 
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                             Helper functions                              */
 /*****************************************************************************/
 
 
@@ -127,29 +136,214 @@ static int CmpKey (const void* Key, const void* Elem)
 
 
 
-static pragma_t FindPragma (const char* Key)
+static pragma_t FindPragma (const StrBuf* Key)
 /* Find a pragma and return the token. Return PR_ILLEGAL if the keyword is
  * not a valid pragma.
  */
 {
     struct Pragma* P;
-    P = bsearch (Key, Pragmas, PR_COUNT, sizeof (Pragmas[0]), CmpKey);
+    P = bsearch (SB_GetConstBuf (Key), Pragmas, PR_COUNT, sizeof (Pragmas[0]), CmpKey);
     return P? P->Tok : PR_ILLEGAL;
 }
 
 
 
+static int GetComma (StrBuf* B)
+/* Expects and skips a comma in B. Prints an error and returns zero if no
+ * comma is found. Return a value <> 0 otherwise.
+ */
+{
+    SB_SkipWhite (B);
+    if (SB_Get (B) != ',') {
+        Error ("Comma expected");
+        return 0;
+    }
+    SB_SkipWhite (B);
+    return 1;
+}
+
+
+
+static int GetString (StrBuf* B, StrBuf* S)
+/* Expects and skips a string in B. Prints an error and returns zero if no
+ * string is found. Returns a value <> 0 otherwise.
+ */
+{
+    if (!SB_GetString (B, S)) {
+       Error ("String literal expected");
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static int GetNumber (StrBuf* B, long* Val)
+/* Expects and skips a number in B. Prints an eror and returns zero if no
+ * number is found. Returns a value <> 0 otherwise.
+ */
+{
+    if (!SB_GetNumber (B, Val)) {
+       Error ("Constant integer expected");
+        return 0;
+    }
+    return 1;
+}
+
+
+
+static IntStack* GetWarning (StrBuf* B)
+/* Get a warning name from the string buffer. Returns a pointer to the intstack
+ * that holds the state of the warning, and NULL in case of errors. The
+ * function will output error messages in case of problems.
+ */
+{
+    IntStack* S = 0;
+    StrBuf W = AUTO_STRBUF_INITIALIZER;
+
+    /* The warning name is a symbol but the '-' char is allowed within */
+    if (SB_GetSym (B, &W, "-")) {
+
+        /* Map the warning name to an IntStack that contains its state */
+        S = FindWarning (SB_GetConstBuf (&W));
+
+        /* Handle errors */
+        if (S == 0) {
+            Error ("Pragma expects a warning name as first argument");
+        }
+    }
+
+    /* Deallocate the string */
+    SB_Done (&W);
+
+    /* Done */
+    return S;
+}
+
+
+
+static int HasStr (StrBuf* B, const char* E)
+/* Checks if E follows in B. If so, skips it and returns true */
+{
+    unsigned Len = strlen (E);
+    if (SB_GetLen (B) - SB_GetIndex (B) >= Len) {
+        if (strncmp (SB_GetConstBuf (B) + SB_GetIndex (B), E, Len) == 0) {
+            /* Found */
+            SB_SkipMultiple (B, Len);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
+
+static PushPopResult ParsePushPop (StrBuf* B)
+/* Check for and parse the "push" and "pop" keywords. In case of "push", a
+ * following comma is expected and skipped.
+ */
+{
+    StrBuf Ident      = AUTO_STRBUF_INITIALIZER;
+    PushPopResult Res = PP_NONE;
+
+
+    /* Try to read an identifier */
+    if (SB_GetSym (B, &Ident, 0)) {
+
+        /* Check if we have a first argument named "pop" */
+        if (SB_CompareStr (&Ident, "pop") == 0) {
+
+            Res = PP_POP;
+
+        /* Check if we have a first argument named "push" */
+        } else if (SB_CompareStr (&Ident, "push") == 0) {
+
+            Res = PP_PUSH;
+
+            /* Skip the following comma */
+            if (!GetComma (B)) {
+                Res = PP_ERROR;
+            }
+
+        } else {
+
+            /* Unknown keyword */
+            Error ("Invalid pragma arguments");
+            Res = PP_ERROR;
+        }
+    }
+
+    /* Free the string buffer and return the result */
+    SB_Done (&Ident);
+    return Res;
+}
+
+
+
+static void PopInt (IntStack* S)
+/* Pops an integer from an IntStack. Prints an error if the stack is empty */
+{
+    if (IS_GetCount (S) < 2) {
+        Error ("Cannot pop, stack is empty");
+    } else {
+        IS_Drop (S);
+    }
+}
+
+
+
+static void PushInt (IntStack* S, long Val)
+/* Pushes an integer onto an IntStack. Prints an error if the stack is full */
+{
+    if (IS_IsFull (S)) {
+        Error ("Cannot push: stack overflow");
+    } else {
+        IS_Push (S, Val);
+    }
+}
+
+
+
+static int BoolKeyword (StrBuf* Ident)
+/* Check if the identifier in Ident is a keyword for a boolean value. Currently
+ * accepted are true/false/on/off.
+ */
+{
+    if (SB_CompareStr (Ident, "true") == 0) {
+        return 1;
+    }
+    if (SB_CompareStr (Ident, "on") == 0) {
+        return 1;
+    }
+    if (SB_CompareStr (Ident, "false") == 0) {
+        return 0;
+    }
+    if (SB_CompareStr (Ident, "off") == 0) {
+        return 0;
+    }
+
+    /* Error */
+    Error ("Pragma argument must be one of `on', `off', `true' or `false'");
+    return 0;
+}
+
+
+
+/*****************************************************************************/
+/*                         Pragma handling functions                         */
+/*****************************************************************************/
+
+
+
 static void StringPragma (StrBuf* B, void (*Func) (const char*))
 /* Handle a pragma that expects a string parameter */
 {
-    StrBuf S;
+    StrBuf S = AUTO_STRBUF_INITIALIZER;
 
     /* We expect a string here */
-    if (SB_GetString (B, &S)) {
+    if (GetString (B, &S)) {
                /* Call the given function with the string argument */
        Func (SB_GetConstBuf (&S));
-    } else {
-       Error ("String literal expected");
     }
 
     /* Call the string buf destructor */
@@ -161,67 +355,64 @@ static void StringPragma (StrBuf* B, void (*Func) (const char*))
 static void SegNamePragma (StrBuf* B, segment_t Seg)
 /* Handle a pragma that expects a segment name parameter */
 {
-    ident       Ident;
-    StrBuf      S;
+    StrBuf      S = AUTO_STRBUF_INITIALIZER;
     const char* Name;
 
-    /* Try to read an identifier */
+    /* Check for the "push" or "pop" keywords */
     int Push = 0;
-    if (SB_GetSym (B, Ident)) {
+    switch (ParsePushPop (B)) {
 
-        /* Check if we have a first argument named "pop" */
-        if (strcmp (Ident, "pop") == 0) {
+        case PP_NONE:
+            break;
 
-            /* Pop the old value */
-            PopSegName (Seg);
+        case PP_PUSH:
+            Push = 1;
+            break;
 
-            /* Set the segment name */
+        case PP_POP:
+            /* Pop the old value and output it */
+            PopSegName (Seg);
             g_segname (Seg);
 
             /* Done */
-            return;
+            goto ExitPoint;
 
-        /* Check if we have a first argument named "push" */
-        } else if (strcmp (Ident, "push") == 0) {
+        case PP_ERROR:
+            /* Bail out */
+            goto ExitPoint;
 
-            Push = 1;
-            SB_SkipWhite (B);
-            if (SB_Get (B) != ',') {
-                Error ("Comma expected");
-                return;
-            }
-            SB_SkipWhite (B);
+        default:
+            Internal ("Invalid result from ParsePushPop");
 
-        } else {
-            Error ("Invalid pragma arguments");
-            return;
-        }
     }
 
     /* A string argument must follow */
-    if (!SB_GetString (B, &S)) {
-       Error ("String literal expected");
-        return;
+    if (!GetString (B, &S)) {
+        goto ExitPoint;
     }
 
     /* Get the string */
     Name = SB_GetConstBuf (&S);
 
     /* Check if the name is valid */
-    if (!ValidSegName (Name)) {
+    if (ValidSegName (Name)) {
+
+        /* Set the new name */
+        if (Push) {
+            PushSegName (Seg, Name);
+        } else {
+            SetSegName (Seg, Name);
+        }
+        g_segname (Seg);
+
+    } else {
+
         /* Segment name is invalid */
         Error ("Illegal segment name: `%s'", Name);
-        return;
-    }
 
-    /* Set the new name */
-    if (Push) {
-        PushSegName (Seg, Name);
-    } else {
-        SetSegName (Seg, Name);
     }
-    g_segname (Seg);
 
+ExitPoint:
     /* Call the string buf destructor */
     SB_Done (&S);
 }
@@ -234,7 +425,7 @@ static void CharMapPragma (StrBuf* B)
     long Index, C;
 
     /* Read the character index */
-    if (!SB_GetNumber (B, &Index)) {
+    if (!GetNumber (B, &Index)) {
         return;
     }
     if (Index < 1 || Index > 255) {
@@ -248,15 +439,12 @@ static void CharMapPragma (StrBuf* B)
     }
 
     /* Comma follows */
-    SB_SkipWhite (B);
-    if (SB_Get (B) != ',') {
-        Error ("Comma expected");
+    if (!GetComma (B)) {
         return;
     }
-    SB_SkipWhite (B);
 
     /* Read the character code */
-    if (!SB_GetNumber (B, &C)) {
+    if (!GetNumber (B, &C)) {
         return;
     }
     if (C < 1 || C > 255) {
@@ -275,65 +463,113 @@ static void CharMapPragma (StrBuf* B)
 
 
 
+static void WarnPragma (StrBuf* B)
+/* Enable/disable warnings */
+{
+    long   Val;
+    int    Push;
+
+    /* A warning name must follow */
+    IntStack* S =GetWarning (B);
+    if (S == 0) {
+        return;
+    }
+
+    /* Comma follows */
+    if (!GetComma (B)) {
+        return;
+    }
+
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
+
+        case PP_NONE:
+            Push = 0;
+            break;
+
+        case PP_PUSH:
+            Push = 1;
+            break;
+
+        case PP_POP:
+            /* Pop the old value and bail out */
+            PopInt (S);
+            return;
+
+        case PP_ERROR:
+            /* Bail out */
+            return;
+
+        default:
+            Internal ("Invalid result from ParsePushPop");
+    }
+
+    /* Boolean argument follows */
+    if (HasStr (B, "true") || HasStr (B, "on")) {
+        Val = 1;
+    } else if (HasStr (B, "false") || HasStr (B, "off")) {
+        Val = 0;
+    } else if (!SB_GetNumber (B, &Val)) {
+        Error ("Invalid pragma argument");
+        return;
+    }
+
+    /* Set/push the new value */
+    if (Push) {
+        PushInt (S, Val);
+    } else {
+        IS_Set (S, Val);
+    }
+}
+
+
+
 static void FlagPragma (StrBuf* B, IntStack* Stack)
 /* Handle a pragma that expects a boolean paramater */
 {
-    ident Ident;
-    long  Val;
-    int   Push;
+    StrBuf Ident = AUTO_STRBUF_INITIALIZER;
+    long   Val;
+    int    Push;
+
 
     /* Try to read an identifier */
-    int IsIdent = SB_GetSym (B, Ident);
+    int IsIdent = SB_GetSym (B, &Ident, 0);
 
     /* Check if we have a first argument named "pop" */
-    if (IsIdent && strcmp (Ident, "pop") == 0) {
-        if (IS_GetCount (Stack) < 2) {
-            Error ("Cannot pop, stack is empty");
-        } else {
-            IS_Drop (Stack);
-        }
+    if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
+        PopInt (Stack);
         /* No other arguments allowed */
         return;
     }
 
     /* Check if we have a first argument named "push" */
-    if (IsIdent && strcmp (Ident, "push") == 0) {
+    if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
         Push = 1;
-        SB_SkipWhite (B);
-        if (SB_Get (B) != ',') {
-            Error ("Comma expected");
-            return;
+        if (!GetComma (B)) {
+            goto ExitPoint;
         }
-        SB_SkipWhite (B);
-        IsIdent = SB_GetSym (B, Ident);
+        IsIdent = SB_GetSym (B, &Ident, 0);
     } else {
         Push = 0;
     }
 
     /* Boolean argument follows */
     if (IsIdent) {
-        if (strcmp (Ident, "true") == 0 || strcmp (Ident, "on") == 0) {
-            Val = 1;
-        } else if (strcmp (Ident, "false") == 0 || strcmp (Ident, "off") == 0) {
-            Val = 0;
-        } else {
-            Error ("Pragma argument must be one of `on', `off', `true' or `false'");
-        }
-    } else if (!SB_GetNumber (B, &Val)) {
-        Error ("Invalid pragma argument");
-        return;
+        Val = BoolKeyword (&Ident);
+    } else if (!GetNumber (B, &Val)) {
+        goto ExitPoint;
     }
 
     /* Set/push the new value */
     if (Push) {
-        if (IS_IsFull (Stack)) {
-            Error ("Cannot push: stack overflow");
-        } else {
-            IS_Push (Stack, Val);
-        }
+        PushInt (Stack, Val);
     } else {
         IS_Set (Stack, Val);
     }
+
+ExitPoint:
+    /* Free the identifier */
+    SB_Done (&Ident);
 }
 
 
@@ -341,41 +577,36 @@ static void FlagPragma (StrBuf* B, IntStack* Stack)
 static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
 /* Handle a pragma that expects an int paramater */
 {
-    ident Ident;
     long  Val;
     int   Push;
 
-    /* Try to read an identifier */
-    int IsIdent = SB_GetSym (B, Ident);
+    /* Check for the "push" or "pop" keywords */
+    switch (ParsePushPop (B)) {
 
-    /* Check if we have a first argument named "pop" */
-    if (IsIdent && strcmp (Ident, "pop") == 0) {
-        if (IS_GetCount (Stack) < 2) {
-            Error ("Cannot pop, stack is empty");
-        } else {
-            IS_Drop (Stack);
-        }
-        /* No other arguments allowed */
-        return;
-    }
+        case PP_NONE:
+            Push = 0;
+            break;
 
-    /* Check if we have a first argument named "push" */
-    if (IsIdent && strcmp (Ident, "push") == 0) {
-        Push = 1;
-        SB_SkipWhite (B);
-        if (SB_Get (B) != ',') {
-            Error ("Comma expected");
+        case PP_PUSH:
+            Push = 1;
+            break;
+
+        case PP_POP:
+            /* Pop the old value and bail out */
+            PopInt (Stack);
             return;
-        }
-        SB_SkipWhite (B);
-        IsIdent = 0;
-    } else {
-        Push = 0;
+
+        case PP_ERROR:
+            /* Bail out */
+            return;
+
+        default:
+            Internal ("Invalid result from ParsePushPop");
+
     }
 
     /* Integer argument follows */
-    if (IsIdent || !SB_GetNumber (B, &Val)) {
-        Error ("Pragma argument must be numeric");
+    if (!GetNumber (B, &Val)) {
         return;
     }
 
@@ -387,11 +618,7 @@ static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
 
     /* Set/push the new value */
     if (Push) {
-        if (IS_IsFull (Stack)) {
-            Error ("Cannot push: stack overflow");
-        } else {
-            IS_Push (Stack, Val);
-        }
+        PushInt (Stack, Val);
     } else {
         IS_Set (Stack, Val);
     }
@@ -403,7 +630,7 @@ static void ParsePragma (void)
 /* Parse the contents of the _Pragma statement */
 {
     pragma_t Pragma;
-    ident    Ident;
+    StrBuf   Ident = AUTO_STRBUF_INITIALIZER;
 
     /* Create a string buffer from the string literal */
     StrBuf B = AUTO_STRBUF_INITIALIZER;
@@ -421,13 +648,13 @@ static void ParsePragma (void)
 
     /* Get the pragma name from the string */
     SB_SkipWhite (&B);
-    if (!SB_GetSym (&B, Ident)) {
+    if (!SB_GetSym (&B, &Ident, "-")) {
         Error ("Invalid pragma");
-        return;
+        goto ExitPoint;
     }
 
     /* Search for the name */
-    Pragma = FindPragma (Ident);
+    Pragma = FindPragma (&Ident);
 
     /* Do we know this pragma? */
     if (Pragma == PR_ILLEGAL) {
@@ -435,15 +662,15 @@ static void ParsePragma (void)
                 * for unknown pragmas, however, we're allowed to warn - and we will
                 * do so. Otherwise one typo may give you hours of bug hunting...
                 */
-               Warning ("Unknown pragma `%s'", Ident);
-               return;
+               Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
+               goto ExitPoint;
     }
 
     /* Check for an open paren */
     SB_SkipWhite (&B);
     if (SB_Get (&B) != '(') {
         Error ("'(' expected");
-        return;
+        goto ExitPoint;
     }
 
     /* Skip white space before the argument */
@@ -501,7 +728,7 @@ static void ParsePragma (void)
            break;
 
         case PR_WARN:
-            FlagPragma (&B, &WarnEnable);
+            WarnPragma (&B);
             break;
 
        case PR_ZPSYM:
@@ -516,7 +743,7 @@ static void ParsePragma (void)
     SB_SkipWhite (&B);
     if (SB_Get (&B) != ')') {
         Error ("')' expected");
-        return;
+        goto ExitPoint;
     }
     SB_SkipWhite (&B);
 
@@ -531,8 +758,10 @@ static void ParsePragma (void)
         Error ("Unexpected input following pragma directive");
     }
 
-    /* Release the StrBuf */
+ExitPoint:
+    /* Release the string buffers */
     SB_Done (&B);
+    SB_Done (&Ident);
 }
 
 
index 219377a76ef621eb2f83de0c5123a53056257b56..d33f88a258f5f40d351fa9786bd6c42ea54eced2 100644 (file)
@@ -162,23 +162,31 @@ void SB_SkipWhite (StrBuf* B)
 
 
 
-int SB_GetSym (StrBuf* B, char* S)
-/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
- * characters. Returns 1 if a symbol was found and 0 otherwise.
+int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars)
+/* Get a symbol from the string buffer. If SpecialChars is not NULL, it
+ * points to a string that contains characters allowed within the string in
+ * addition to letters, digits and the underline. Note: The identifier must
+ * still begin with a letter.
+ * Returns 1 if a symbol was found and 0 otherwise but doesn't output any
+ * errors.
  */
 {
+    /* Handle a NULL argument for SpecialChars transparently */
+    if (SpecialChars == 0) {
+        SpecialChars = "";
+    }
+
+    /* Clear Ident */
+    SB_Clear (Ident);
+
     if (IsIdent (SB_Peek (B))) {
-        unsigned I = 0;
         char C = SB_Peek (B);
         do {
-            if (I < MAX_IDENTLEN) {
-                ++I;
-                *S++ = C;
-            }
+            SB_AppendChar (Ident, C);
             SB_Skip (B);
             C = SB_Peek (B);
-        } while (IsIdent (C) || IsDigit (C));
-        *S = '\0';
+        } while (IsIdent (C) || IsDigit (C) || strchr (SpecialChars, C) != 0);
+        SB_Terminate (Ident);
        return 1;
     } else {
        return 0;
@@ -188,15 +196,17 @@ int SB_GetSym (StrBuf* B, char* S)
 
 
 int SB_GetString (StrBuf* B, StrBuf* S)
-/* Get a string from the string buffer. S will be initialized by the function
- * and will return the correctly terminated string on return. The function
- * returns 1 if a string was found and 0 otherwise.
+/* Get a string from the string buffer. Returns 1 if a string was found and 0
+ * otherwise. Errors are only output in case of invalid strings (missing end
+ * of string).
  */
 {
     char C;
 
-    /* Initialize S */
-    SB_Init (S);
+    /* Clear S */
+    SB_Clear (S);
+
+    /* A string starts with quote marks */
     if (SB_Peek (B) == '\"') {
 
         /* String follows, be sure to concatenate strings */
@@ -241,7 +251,7 @@ int SB_GetNumber (StrBuf* B, long* Val)
 /* Get a number from the string buffer. Accepted formats are decimal, octal,
  * hex and character constants. Numeric constants may be preceeded by a
  * minus or plus sign. The function returns 1 if a number was found and
- * zero otherwise.
+ * zero otherwise. Errors are only output for invalid numbers.
  */
 {
     int      Sign;
@@ -249,83 +259,86 @@ int SB_GetNumber (StrBuf* B, long* Val)
     unsigned Base;
     unsigned DigitVal;
 
+
     /* Initialize Val */
     *Val = 0;
 
-    /* Check for a sign */
+    /* Handle character constants */
+    if (SB_Peek (B) == '\'') {
+
+        /* Character constant */
+        SB_Skip (B);
+        *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
+        if (SB_Peek (B) != '\'') {
+            Error ("`\'' expected");
+            return 0;
+        } else {
+            /* Skip the quote */
+            SB_Skip (B);
+            return 1;
+        }
+    }
+
+    /* Check for a sign. A sign must be followed by a digit, otherwise it's
+     * not a number
+     */
     Sign = 1;
     switch (SB_Peek (B)) {
         case '-':
             Sign = -1;
             /* FALLTHROUGH */
         case '+':
+            if (!IsDigit (SB_LookAt (B, SB_GetIndex (B) + 1))) {
+                return 0;
+            }
             SB_Skip (B);
-            SB_SkipWhite (B);
             break;
     }
 
-    /* Check for the different formats */
+    /* We must have a digit now, otherwise its not a number */
     C = SB_Peek (B);
-    if (IsDigit (C)) {
+    if (!IsDigit (C)) {
+        return 0;
+    }
 
-        if (C == '0') {
-            /* Hex or octal */
+    /* Determine the base */
+    if (C == '0') {
+        /* Hex or octal */
+        SB_Skip (B);
+        if (tolower (SB_Peek (B)) == 'x') {
             SB_Skip (B);
-            if (tolower (SB_Peek (B)) == 'x') {
-                SB_Skip (B);
-                Base = 16;
-                if (!IsXDigit (SB_Peek (B))) {
-                    Error ("Invalid hexadecimal number");
-                    return 0;
-                }
-            } else {
-                Base = 8;
+            Base = 16;
+            if (!IsXDigit (SB_Peek (B))) {
+                Error ("Invalid hexadecimal number");
+                return 0;
             }
         } else {
-            Base = 10;
+            Base = 8;
         }
+    } else {
+        Base = 10;
+    }
 
-        /* Read the number */
-        while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
-            *Val = (*Val * Base) + DigitVal;
-            SB_Skip (B);
-        }
+    /* Read the number */
+    while (IsXDigit (C = SB_Peek (B)) && (DigitVal = HexVal (C)) < Base) {
+        *Val = (*Val * Base) + DigitVal;
+        SB_Skip (B);
+    }
 
-        /* Allow optional 'U' and 'L' modifiers */
+    /* Allow optional 'U' and 'L' modifiers */
+    C = SB_Peek (B);
+    if (C == 'u' || C == 'U') {
+        SB_Skip (B);
         C = SB_Peek (B);
-        if (C == 'u' || C == 'U') {
+        if (C == 'l' || C == 'L') {
             SB_Skip (B);
-            C = SB_Peek (B);
-            if (C == 'l' || C == 'L') {
-                SB_Skip (B);
-            }
-        } else if (C == 'l' || C == 'L') {
-            SB_Skip (B);
-            C = SB_Peek (B);
-            if (C == 'u' || C == 'U') {
-                SB_Skip (B);
-            }
         }
-
-    } else if (C == '\'') {
-
-        /* Character constant */
+    } else if (C == 'l' || C == 'L') {
         SB_Skip (B);
-        *Val = SignExtendChar (TgtTranslateChar (ParseChar (B)));
-        if (SB_Peek (B) != '\'') {
-            Error ("`\'' expected");
-            return 0;
-        } else {
-            /* Skip the quote */
+        C = SB_Peek (B);
+        if (C == 'u' || C == 'U') {
             SB_Skip (B);
         }
-
-    } else {
-
-        /* Invalid number */
-        Error ("Numeric constant expected");
-        return 0;
-
     }
 
     /* Success, value read is in Val */
index 29002052e2468b4bee5c96af147d36e32ce3219b..a49a5f03541400ea08f2e16c42b14792d28b3246 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2002      Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2002-2009, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 void SB_SkipWhite (StrBuf* B);
 /* Skip whitespace in the string buffer */
 
-int SB_GetSym (StrBuf* B, char* S);
-/* Get a symbol from the string buffer. S must be able to hold MAX_IDENTLEN
- * characters. Returns 1 if a symbol was found and 0 otherwise.
+int SB_GetSym (StrBuf* B, StrBuf* Ident, const char* SpecialChars);
+/* Get a symbol from the string buffer. If SpecialChars is not NULL, it
+ * points to a string that contains characters allowed within the string in
+ * addition to letters, digits and the underline. Note: The identifier must
+ * still begin with a letter.
+ * Returns 1 if a symbol was found and 0 otherwise but doesn't output any
+ * errors.
  */
 
 int SB_GetString (StrBuf* B, StrBuf* S);
-/* Get a string from the string buffer. S will be initialized by the function
- * and will return the correctly terminated string on return. The function
- * returns 1 if a string was found and 0 otherwise.
+/* Get a string from the string buffer. Returns 1 if a string was found and 0
+ * otherwise. Errors are only output in case of invalid strings (missing end
+ * of string).
  */
 
 int SB_GetNumber (StrBuf* B, long* Val);
 /* Get a number from the string buffer. Accepted formats are decimal, octal,
- * hex and character constants. Numeric constants may be preceeded by a 
+ * hex and character constants. Numeric constants may be preceeded by a
  * minus or plus sign. The function returns 1 if a number was found and
- * zero otherwise.
+ * zero otherwise. Errors are only output for invalid numbers.
  */