]> git.sur5r.net Git - cc65/blobdiff - src/cc65/scanstrbuf.c
Reverted part of change 4108 that prevented an optimization step to find
[cc65] / src / cc65 / scanstrbuf.c
index 82418f763d456b5852879e66df2d118a98dbba6d..f55f52a6454d791172b6d6f68a8a3b1c6b588ff6 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       */
 
 /* common */
 #include "chartype.h"
+#include "tgttrans.h"
 
 /* cc65 */
+#include "datatype.h"
 #include "error.h"
 #include "hexval.h"
 #include "ident.h"
 
 
 
-static char ParseChar (StrBuf* B)
+static int ParseChar (StrBuf* B)
 /* Parse a character. Converts \n into EOL, etc. */
 {
     unsigned I;
+    unsigned Val;
     int C;
 
     /* Check for escape chars */
     if ((C = SB_Get (B)) == '\\') {
-       switch (SB_Get (B)) {
+               switch (SB_Peek (B)) {
+                   case '?':
+               C = '?';
+                SB_Skip (B);
+               break;
+           case 'a':
+               C = '\a';
+                SB_Skip (B);
+               break;
            case 'b':
                C = '\b';
+                SB_Skip (B);
                break;
            case 'f':
                C = '\f';
+                SB_Skip (B);
                break;
            case 'r':
                C = '\r';
+                SB_Skip (B);
                break;
            case 'n':
                C = '\n';
+                SB_Skip (B);
                break;
            case 't':
                C = '\t';
+                SB_Skip (B);
+               break;
+           case 'v':
+               C = '\v';
+                SB_Skip (B);
                break;
            case '\"':
                C = '\"';
+                SB_Skip (B);
                break;
            case '\'':
                C = '\'';
+                SB_Skip (B);
                break;
            case '\\':
                C = '\\';
+                SB_Skip (B);
                break;
            case 'x':
            case 'X':
                /* Hex character constant */
+                SB_Skip (B);
                        C = HexVal (SB_Get (B)) << 4;
                        C |= HexVal (SB_Get (B));
-               break;
+               break;
            case '0':
-               /* Octal constant */
-                C = 0;
-                goto Octal;
            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
                 /* Octal constant */
-                C = 1;
-Octal:          I = 0;
-                       while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && I++ < 4) {
-                    C = (C << 3) | (SB_Get (B) - '0');
-               }
+                I = 0;
+                Val = SB_Get (B) - '0';
+                       while (SB_Peek (B) >= '0' && SB_Peek (B) <= '7' && ++I <= 3) {
+                    Val = (Val << 3) | (SB_Get (B) - '0');
+               }
+                C = (int) Val;
+                if (Val > 256) {
+                    Error ("Character constant out of range");
+                    C = ' ';
+                }
                break;
            default:
-               Error ("Illegal character constant");
-               C = ' ';
-               break;
+               Error ("Illegal character constant 0x%02X", SB_Get (B));
+               C = ' ';
+               break;
        }
     }
 
@@ -114,12 +146,8 @@ Octal:          I = 0;
 
 
 
-
-
-
-
 /*****************************************************************************/
-/*                                  Code                                    */
+/*                                  Code                                    */
 /*****************************************************************************/
 
 
@@ -134,23 +162,32 @@ 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) || 
+                 (C != '\0' && strchr (SpecialChars, C) != 0));
+        SB_Terminate (Ident);
        return 1;
     } else {
        return 0;
@@ -160,15 +197,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 */
-    *S = AUTO_STRBUF_INITIALIZER;
+    /* Clear S */
+    SB_Clear (S);
+
+    /* A string starts with quote marks */
     if (SB_Peek (B) == '\"') {
 
         /* String follows, be sure to concatenate strings */
@@ -209,3 +248,104 @@ int SB_GetString (StrBuf* B, StrBuf* S)
 
 
 
+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. Errors are only output for invalid numbers.
+ */
+{
+    int      Sign;
+    char     C;
+    unsigned Base;
+    unsigned DigitVal;
+
+
+    /* Initialize Val */
+    *Val = 0;
+
+    /* 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);
+            break;
+    }
+
+    /* We must have a digit now, otherwise its not a number */
+    C = SB_Peek (B);
+    if (!IsDigit (C)) {
+        return 0;
+    }
+
+    /* Determine the base */
+    if (C == '0') {
+        /* Hex or octal */
+        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;
+        }
+    } else {
+        Base = 10;
+    }
+
+    /* 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 */
+    C = SB_Peek (B);
+    if (C == 'u' || C == 'U') {
+        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);
+        }
+    }
+
+    /* Success, value read is in Val */
+    *Val *= Sign;
+    return 1;
+}
+
+
+