X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fscanner.c;h=360305852c1be7b13e7ad2ee583ae765c6d15b45;hb=35e1184901ca38bdb2e56d154ed3b71f6096eacc;hp=cc98d08fe7e0a45192a1aaa9826e1ed7876b695e;hpb=71ed8810c3b8c170de1fa1cad8f761d3900dacb9;p=cc65 diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index cc98d08fe..360305852 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -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 */ @@ -54,14 +55,14 @@ #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; } }