]> git.sur5r.net Git - cc65/blobdiff - src/cc65/scanner.c
Removed unneeded include files.
[cc65] / src / cc65 / scanner.c
index cc98d08fe7e0a45192a1aaa9826e1ed7876b695e..360305852c1be7b13e7ad2ee583ae765c6d15b45 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -42,6 +42,7 @@
 
 /* common */
 #include "chartype.h"
+#include "fp.h"
 #include "tgttrans.h"
 
 /* cc65 */
 #include "input.h"
 #include "litpool.h"
 #include "preproc.h"
-#include "symtab.h"
-#include "util.h"
 #include "scanner.h"
+#include "standard.h"
+#include "symtab.h"
 
 
 
 /*****************************************************************************/
-/*                                  data                                    */
+/*                                  data                                    */
 /*****************************************************************************/
 
 
@@ -72,63 +73,70 @@ Token NextTok;              /* The next token */
 
 
 /* Token types */
-#define TT_C   0               /* ANSI C token */
-#define TT_EXT 1               /* cc65 extension */
+enum {
+    TT_C89      = 0x01 << STD_C89,      /* Token valid in C89 */
+    TT_C99      = 0x01 << STD_C99,      /* Token valid in C99 */
+    TT_CC65     = 0x01 << STD_CC65      /* Token valid in cc65 */
+};
 
 /* Token table */
 static const struct Keyword {
     char*          Key;        /* Keyword name */
     unsigned char   Tok;       /* The token */
-    unsigned char   Type;              /* Token type */
+    unsigned char   Std;        /* Token supported in which standards? */
 } Keywords [] = {
-    { "_Pragma",        TOK_PRAGMA,     TT_C    },
-    { "__AX__",                TOK_AX,         TT_C    },
-    { "__A__",         TOK_A,          TT_C    },
-    { "__EAX__",               TOK_EAX,        TT_C    },
-    { "__X__",                 TOK_X,          TT_C    },
-    { "__Y__",                 TOK_Y,          TT_C    },
-    { "__asm__",               TOK_ASM,        TT_C    },
-    { "__attribute__", TOK_ATTRIBUTE,  TT_C    },
-    { "__far__",       TOK_FAR,        TT_C    },
-    { "__fastcall__",          TOK_FASTCALL,   TT_C    },
-    { "__near__",              TOK_NEAR,       TT_C    },
-    { "asm",                   TOK_ASM,        TT_EXT  },
-    { "auto",                  TOK_AUTO,       TT_C    },
-    { "break",                 TOK_BREAK,      TT_C    },
-    { "case",                  TOK_CASE,       TT_C    },
-    { "char",                  TOK_CHAR,       TT_C    },
-    { "const",                 TOK_CONST,      TT_C    },
-    { "continue",              TOK_CONTINUE,   TT_C    },
-    { "default",               TOK_DEFAULT,    TT_C    },
-    { "do",                    TOK_DO,         TT_C    },
-    { "double",                TOK_DOUBLE,     TT_C    },
-    { "else",                  TOK_ELSE,       TT_C    },
-    { "enum",                  TOK_ENUM,       TT_C    },
-    { "extern",                TOK_EXTERN,     TT_C    },
-    { "far",           TOK_FAR,        TT_EXT  },
-    { "fastcall",              TOK_FASTCALL,   TT_EXT  },
-    { "float",                 TOK_FLOAT,      TT_C    },
-    { "for",                   TOK_FOR,        TT_C    },
-    { "goto",                  TOK_GOTO,       TT_C    },
-    { "if",                    TOK_IF,         TT_C    },
-    { "int",                   TOK_INT,        TT_C    },
-    { "long",                  TOK_LONG,       TT_C    },
-    { "near",                  TOK_NEAR,       TT_EXT  },
-    { "register",              TOK_REGISTER,   TT_C    },
-    { "restrict",              TOK_RESTRICT,   TT_C    },
-    { "return",                TOK_RETURN,     TT_C    },
-    { "short",                 TOK_SHORT,      TT_C    },
-    { "signed",                TOK_SIGNED,     TT_C    },
-    { "sizeof",                TOK_SIZEOF,     TT_C    },
-    { "static",                TOK_STATIC,     TT_C    },
-    { "struct",                TOK_STRUCT,     TT_C    },
-    { "switch",                TOK_SWITCH,     TT_C    },
-    { "typedef",               TOK_TYPEDEF,    TT_C    },
-    { "union",                 TOK_UNION,      TT_C    },
-    { "unsigned",              TOK_UNSIGNED,   TT_C    },
-    { "void",                  TOK_VOID,       TT_C    },
-    { "volatile",              TOK_VOLATILE,   TT_C    },
-    { "while",                 TOK_WHILE,      TT_C    },
+    { "_Pragma",        TOK_PRAGMA,     TT_C89 | TT_C99 | TT_CC65  },   /* !! */
+    { "__AX__",                TOK_AX,         TT_C89 | TT_C99 | TT_CC65  },
+    { "__A__",                 TOK_A,          TT_C89 | TT_C99 | TT_CC65  },
+    { "__EAX__",               TOK_EAX,        TT_C89 | TT_C99 | TT_CC65  },
+    { "__X__",                 TOK_X,          TT_C89 | TT_C99 | TT_CC65  },
+    { "__Y__",                 TOK_Y,          TT_C89 | TT_C99 | TT_CC65  },
+    { "__asm__",               TOK_ASM,        TT_C89 | TT_C99 | TT_CC65  },
+    { "__attribute__",         TOK_ATTRIBUTE,  TT_C89 | TT_C99 | TT_CC65  },
+    { "__cdecl__",             TOK_CDECL,      TT_C89 | TT_C99 | TT_CC65  },
+    { "__far__",               TOK_FAR,        TT_C89 | TT_C99 | TT_CC65  },
+    { "__fastcall__",          TOK_FASTCALL,   TT_C89 | TT_C99 | TT_CC65  },
+    { "__inline__",     TOK_INLINE,            TT_C89 | TT_C99 | TT_CC65  },
+    { "__near__",              TOK_NEAR,       TT_C89 | TT_C99 | TT_CC65  },
+    { "asm",                   TOK_ASM,                          TT_CC65  },
+    { "auto",                  TOK_AUTO,       TT_C89 | TT_C99 | TT_CC65  },
+    { "break",                 TOK_BREAK,      TT_C89 | TT_C99 | TT_CC65  },
+    { "case",                  TOK_CASE,       TT_C89 | TT_C99 | TT_CC65  },
+    { "cdecl",                 TOK_CDECL,                        TT_CC65  },
+    { "char",                  TOK_CHAR,       TT_C89 | TT_C99 | TT_CC65  },
+    { "const",                 TOK_CONST,      TT_C89 | TT_C99 | TT_CC65  },
+    { "continue",              TOK_CONTINUE,   TT_C89 | TT_C99 | TT_CC65  },
+    { "default",               TOK_DEFAULT,    TT_C89 | TT_C99 | TT_CC65  },
+    { "do",                    TOK_DO,         TT_C89 | TT_C99 | TT_CC65  },
+    { "double",                TOK_DOUBLE,     TT_C89 | TT_C99 | TT_CC65  },
+    { "else",                  TOK_ELSE,       TT_C89 | TT_C99 | TT_CC65  },
+    { "enum",                  TOK_ENUM,       TT_C89 | TT_C99 | TT_CC65  },
+    { "extern",                TOK_EXTERN,     TT_C89 | TT_C99 | TT_CC65  },
+    { "far",           TOK_FAR,                          TT_CC65  },
+    { "fastcall",              TOK_FASTCALL,                     TT_CC65  },
+    { "float",                 TOK_FLOAT,      TT_C89 | TT_C99 | TT_CC65  },
+    { "for",                   TOK_FOR,        TT_C89 | TT_C99 | TT_CC65  },
+    { "goto",                  TOK_GOTO,       TT_C89 | TT_C99 | TT_CC65  },
+    { "if",                    TOK_IF,         TT_C89 | TT_C99 | TT_CC65  },
+    { "inline",         TOK_INLINE,              TT_C99 | TT_CC65  },
+    { "int",                   TOK_INT,        TT_C89 | TT_C99 | TT_CC65  },
+    { "long",                  TOK_LONG,       TT_C89 | TT_C99 | TT_CC65  },
+    { "near",                  TOK_NEAR,                         TT_CC65  },
+    { "register",              TOK_REGISTER,   TT_C89 | TT_C99 | TT_CC65  },
+    { "restrict",              TOK_RESTRICT,            TT_C99 | TT_CC65  },
+    { "return",                TOK_RETURN,     TT_C89 | TT_C99 | TT_CC65  },
+    { "short",                 TOK_SHORT,      TT_C89 | TT_C99 | TT_CC65  },
+    { "signed",                TOK_SIGNED,     TT_C89 | TT_C99 | TT_CC65  },
+    { "sizeof",                TOK_SIZEOF,     TT_C89 | TT_C99 | TT_CC65  },
+    { "static",                TOK_STATIC,     TT_C89 | TT_C99 | TT_CC65  },
+    { "struct",                TOK_STRUCT,     TT_C89 | TT_C99 | TT_CC65  },
+    { "switch",                TOK_SWITCH,     TT_C89 | TT_C99 | TT_CC65  },
+    { "typedef",               TOK_TYPEDEF,    TT_C89 | TT_C99 | TT_CC65  },
+    { "union",                 TOK_UNION,      TT_C89 | TT_C99 | TT_CC65  },
+    { "unsigned",              TOK_UNSIGNED,   TT_C89 | TT_C99 | TT_CC65  },
+    { "void",                  TOK_VOID,       TT_C89 | TT_C99 | TT_CC65  },
+    { "volatile",              TOK_VOLATILE,   TT_C89 | TT_C99 | TT_CC65  },
+    { "while",                 TOK_WHILE,      TT_C89 | TT_C99 | TT_CC65  },
 };
 #define KEY_COUNT      (sizeof (Keywords) / sizeof (Keywords [0]))
 
@@ -143,7 +151,7 @@ static const struct Keyword {
 
 
 /*****************************************************************************/
-/*                                  code                                    */
+/*                                  code                                    */
 /*****************************************************************************/
 
 
@@ -156,14 +164,14 @@ static int CmpKey (const void* Key, const void* Elem)
 
 
 
-static int FindKey (const char* Key)
+static token_t FindKey (const char* Key)
 /* Find a keyword and return the token. Return IDENT if the token is not a
  * keyword.
  */
 {
     struct Keyword* K;
     K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
-    if (K && (K->Type != TT_EXT || ANSI == 0)) {
+    if (K && (K->Std & (0x01 << IS_Get (&Standard))) != 0) {
        return K->Tok;
     } else {
        return TOK_IDENT;
@@ -178,7 +186,7 @@ static int SkipWhite (void)
  */
 {
     while (1) {
-               while (CurC == 0) {
+               while (CurC == '\0') {
            if (NextLine () == 0) {
                return 0;
            }
@@ -194,27 +202,40 @@ static int SkipWhite (void)
 
 
 
-void SymName (char* s)
-/* Get symbol from input stream */
+int TokIsFuncSpec (const Token* T)
+/* Return true if the token is a function specifier */
 {
-    unsigned k = 0;
+    return (T->Tok == TOK_INLINE)   ||
+           (T->Tok == TOK_FASTCALL) || (T->Tok == TOK_CDECL) ||
+           (T->Tok == TOK_NEAR)     || (T->Tok == TOK_FAR);
+}
+
+
+
+void SymName (char* S)
+/* Read a symbol from the input stream. The first character must have been
+ * checked before calling this function. The buffer is expected to be at
+ * least of size MAX_IDENTLEN+1.
+ */
+{
+    unsigned Len = 0;
     do {
-               if (k != MAX_IDENTLEN) {
-                   ++k;
-                   *s++ = CurC;
-       }
+               if (Len < MAX_IDENTLEN) {
+                   ++Len;
+                   *S++ = CurC;
+       }
                NextChar ();
     } while (IsIdent (CurC) || IsDigit (CurC));
-    *s = '\0';
+    *S = '\0';
 }
 
 
 
-int IsSym (char *s)
-/* Get symbol from input stream or return 0 if not a symbol. */
+int IsSym (char* S)
+/* If a symbol follows, read it and return 1, otherwise return 0 */
 {
     if (IsIdent (CurC)) {
-       SymName (s);
+       SymName (S);
        return 1;
     } else {
        return 0;
@@ -242,11 +263,10 @@ static void SetTok (int tok)
 
 
 static int ParseChar (void)
-/* Parse a character. Converts \n into EOL, etc. */
+/* Parse a character. Converts escape chars into character codes. */
 {
-    int I;
-    unsigned Val;
     int C;
+    int HadError;
 
     /* Check for escape chars */
     if (CurC == '\\') {
@@ -262,7 +282,7 @@ static int ParseChar (void)
                C = '\b';
                break;
            case 'f':
-               C = '\f';
+               C = '\f';
                break;
            case 'r':
                C = '\r';
@@ -288,10 +308,24 @@ static int ParseChar (void)
            case 'x':
            case 'X':
                /* Hex character constant */
-               NextChar ();
-               Val = HexVal (CurC) << 4;
-               NextChar ();
-                       C = Val | HexVal (CurC);        /* Do not translate */
+                if (!IsXDigit (NextC)) {
+                    Error ("\\x used with no following hex digits");
+                    C = ' ';
+                } else {
+                    HadError = 0;
+                    C = 0;
+                    while (IsXDigit (NextC)) {
+                        if ((C << 4) >= 256) {
+                            if (!HadError) {
+                                Error ("Hex character constant out of range");
+                                HadError = 1;
+                            }
+                        } else {
+                            C = (C << 4) | HexVal (NextC);
+                        }
+                        NextChar ();
+                    }
+                }
                break;
            case '0':
            case '1':
@@ -301,22 +335,24 @@ static int ParseChar (void)
            case '5':
            case '6':
            case '7':
-               /* Octal constant */
-               I = 0;
-                       Val = CurC - '0';
-                       while (NextC >= '0' && NextC <= '7' && ++I <= 3) {
-                   NextChar ();
-                   Val = (Val << 3) | (CurC - '0');
-               }
-                C = (int) Val;
-                if (Val >= 256) {
-                    Error ("Character constant out of range");
-                    C = ' ';
-                }
-               break;
+               /* Octal constant */
+                HadError = 0;
+                       C = HexVal (CurC);
+                       while (IsODigit (NextC)) {
+                    if ((C << 3) >= 256) {
+                        if (!HadError) {
+                            Error ("Octal character constant out of range");
+                            HadError = 1;
+                        }
+                    } else {
+                        C = (C << 3) | HexVal (NextC);
+                    }
+                   NextChar ();
+               }
+               break;
            default:
-               Error ("Illegal character constant");
-               C = ' ';
+               Error ("Illegal character constant");
+               C = ' ';
                 /* Try to do error recovery, otherwise the compiler will spit
                  * out thousands of errors in this place and abort.
                  */
@@ -374,24 +410,42 @@ static void CharConst (void)
 static void StringConst (void)
 /* Parse a quoted string */
 {
-    NextTok.IVal = GetLiteralPoolOffs ();
+    /* String buffer */
+    StrBuf S = AUTO_STRBUF_INITIALIZER;
+
+    /* Assume next token is a string constant */
     NextTok.Tok  = TOK_SCONST;
 
-    /* Be sure to concatenate strings */
-    while (CurC == '\"') {
+    /* Concatenate strings. If at least one of the concenated strings is a wide
+     * character literal, the whole string is a wide char literal, otherwise
+     * it's a normal string literal.
+     */
+    while (1) {
 
-       /* Skip the quote char */
-       NextChar ();
+        /* Check if this is a normal or a wide char string */
+        if (CurC == 'L' && NextC == '\"') {
+            /* Wide character literal */
+            NextTok.Tok = TOK_WCSCONST;
+            NextChar ();
+            NextChar ();
+        } else if (CurC == '\"') {
+            /* Skip the quote char */
+           NextChar ();
+        } else {
+            /* No string */
+            break;
+        }
 
-       while (CurC != '\"') {
-           if (CurC == '\0') {
-               Error ("Unexpected newline");
-               break;
-           }
-           AddLiteralChar (ParseChar ());
-       }
+        /* Read until end of string */
+       while (CurC != '\"') {
+           if (CurC == '\0') {
+               Error ("Unexpected newline");
+               break;
+           }
+                   SB_AppendChar (&S, ParseChar ());
+       }
 
-       /* Skip closing quote char if there was one */
+       /* Skip closing quote char if there was one */
        NextChar ();
 
        /* Skip white space, read new input */
@@ -400,7 +454,13 @@ static void StringConst (void)
     }
 
     /* Terminate the string */
-    AddLiteralChar ('\0');
+    SB_AppendChar (&S, '\0');
+
+    /* Add the whole string to the literal pool */
+    NextTok.SVal = AddLiteralStr (&S);
+
+    /* Free the buffer */
+    SB_Done (&S);
 }
 
 
@@ -410,7 +470,7 @@ static void NumericConst (void)
 {
     unsigned Base;              /* Temporary number base */
     unsigned Prefix;            /* Base according to prefix */
-    StrBuf   S;
+    StrBuf   S = STATIC_STRBUF_INITIALIZER;
     int      IsFloat;
     char     C;
     unsigned DigitVal;
@@ -438,7 +498,6 @@ static void NumericConst (void)
      * before converting it, so we can determine if it's a float or an
      * integer.
      */
-    InitStrBuf (&S);
     while (IsXDigit (CurC) && HexVal (CurC) < Base) {
         SB_AppendChar (&S, CurC);
         NextChar ();
@@ -446,11 +505,12 @@ static void NumericConst (void)
     SB_Terminate (&S);
 
     /* The following character tells us if we have an integer or floating
-     * point constant.
+     * point constant. Note: Hexadecimal floating point constants aren't
+     * supported in C89.
      */
     IsFloat = (CurC == '.' ||
                (Base == 10 && toupper (CurC) == 'E') ||
-               (Base == 16 && toupper (CurC) == 'P'));
+               (Base == 16 && toupper (CurC) == 'P' && IS_Get (&Standard) >= STD_C99));
 
     /* If we don't have a floating point type, an octal prefix results in an
      * octal base.
@@ -473,7 +533,7 @@ static void NumericConst (void)
     }
 
     /* We don't need the string buffer any longer */
-    DoneStrBuf (&S);
+    SB_Done (&S);
 
     /* Distinguish between integer and floating point constants */
     if (!IsFloat) {
@@ -551,39 +611,28 @@ static void NumericConst (void)
     } else {
 
         /* Float constant */
-        double FVal = IVal;             /* Convert to float */
+        Double FVal = FP_D_FromInt (IVal);      /* Convert to double */
 
         /* Check for a fractional part and read it */
         if (CurC == '.') {
 
-            unsigned Digits;
-            unsigned long Frac;
-            unsigned long Scale;
+            Double Scale;
 
             /* Skip the dot */
             NextChar ();
 
-            /* Read fractional digits. Since we support only 32 bit floats
-             * with a maximum of 7 fractional digits, we read the fractional
-             * part as integer with up to 8 digits and drop the remainder.
-             * This avoids an overflow of Frac and Scale.
-             */
-            Digits = 0;
-            Frac   = 0;
-            Scale  = 1;
+            /* Read fractional digits */
+            Scale  = FP_D_Make (1.0);
             while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) {
-                if (Digits < 8) {
-                    Frac = Frac * Base + DigitVal;
-                    ++Digits;
-                    Scale *= Base;
-                }
+                /* Get the value of this digit */
+                Double FracVal = FP_D_Div (FP_D_FromInt (DigitVal * Base), Scale);
+                /* Add it to the float value */
+                FVal = FP_D_Add (FVal, FracVal);
+                /* Scale base */
+                Scale = FP_D_Mul (Scale, FP_D_FromInt (DigitVal));
+                /* Skip the digit */
                 NextChar ();
             }
-
-            /* Scale the fractional part and add it */
-            if (Frac) {
-                FVal += ((double) Frac) / ((double) Scale);
-            }
         }
 
         /* Check for an exponent and read it */
@@ -602,6 +651,8 @@ static void NumericConst (void)
             if (CurC == '-') {
                 Sign = -1;
                 NextChar ();
+            } else if (CurC == '+') {
+                NextChar ();
             }
 
             /* Read exponent digits. Since we support only 32 bit floats
@@ -630,7 +681,7 @@ static void NumericConst (void)
 
             /* Scale the exponent and adjust the value accordingly */
             if (Exp) {
-                FVal *= pow (10, Exp);
+                FVal = FP_D_Mul (FVal, FP_D_Make (pow (10, Exp)));
             }
         }
 
@@ -694,6 +745,13 @@ void NextToken (void)
        return;
     }
 
+    /* Check for wide character literals */
+    if (CurC == 'L' && NextC == '\"') {
+        StringConst ();
+        return;
+    }
+
+    /* Check for keywords and identifiers */
     if (IsSym (token)) {
 
        /* Check for a keyword */
@@ -702,21 +760,21 @@ void NextToken (void)
            return;
        }
        /* No reserved word, check for special symbols */
-       if (token [0] == '_') {
+       if (token[0] == '_' && token[1] == '_') {
            /* Special symbols */
-            if (strcmp (token, "__FILE__") == 0) {
-               NextTok.IVal = AddLiteral (GetCurrentFile());
+            if (strcmp (token+2, "FILE__") == 0) {
+               NextTok.SVal = AddLiteral (GetCurrentFile());
                NextTok.Tok  = TOK_SCONST;
                return;
-           } else if (strcmp (token, "__LINE__") == 0) {
+           } else if (strcmp (token+2, "LINE__") == 0) {
                NextTok.Tok  = TOK_ICONST;
                NextTok.IVal = GetCurrentLine();
                NextTok.Type = type_int;
                return;
-           } else if (strcmp (token, "__func__") == 0) {
+                   } else if (strcmp (token+2, "func__") == 0) {
                /* __func__ is only defined in functions */
                if (CurrentFunc) {
-                   NextTok.IVal = AddLiteral (F_GetFuncName (CurrentFunc));
+                   NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc));
                    NextTok.Tok  = TOK_SCONST;
                    return;
                }
@@ -991,7 +1049,7 @@ int Consume (token_t Token, const char* ErrorMsg)
        NextToken ();
         return 1;
     } else {
-               Error (ErrorMsg);
+               Error ("%s", ErrorMsg);
         return 0;
     }
 }