From f500a641c56aff59c076aa50e6ed9addb92fee86 Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 6 Jun 2004 15:59:44 +0000 Subject: [PATCH] Added support for floating point constants in the scanner and Primary() git-svn-id: svn://svn.cc65.org/cc65/trunk@3108 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/expr.c | 20 ++- src/cc65/make/gcc.mak | 2 +- src/cc65/scanner.c | 379 +++++++++++++++++++++++++++++------------- 3 files changed, 281 insertions(+), 120 deletions(-) diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 7a3aacde0..8c14817de 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -766,21 +766,31 @@ static void Primary (ExprDesc* E) /* Character and integer constants. */ if (CurTok.Tok == TOK_ICONST || CurTok.Tok == TOK_CCONST) { + E->IVal = CurTok.IVal; E->Flags = E_LOC_ABS | E_RTYPE_RVAL; E->Type = CurTok.Type; - E->IVal = CurTok.IVal; NextToken (); return; } + /* Floating point constant */ + if (CurTok.Tok == TOK_FCONST) { + E->FVal = CurTok.FVal; + E->Flags = E_LOC_ABS | E_RTYPE_RVAL; + E->Type = CurTok.Type; + printf ("Floating point constant: %f\n", E->FVal); + NextToken (); + return; + } + /* Process parenthesized subexpression by calling the whole parser * recursively. */ if (CurTok.Tok == TOK_LPAREN) { - NextToken (); + NextToken (); hie0 (E); ConsumeRParen (); - return; + return; } /* If we run into an identifier in preprocessing mode, we assume that this @@ -1475,7 +1485,7 @@ static void PreInc (ExprDesc* Expr) ED_MakeRValExpr (Expr); } - + static void PreDec (ExprDesc* Expr) /* Handle the predecrement operators */ @@ -1547,7 +1557,7 @@ static void PreDec (ExprDesc* Expr) } - + static void PostIncDec (ExprDesc* Expr, void (*inc) (unsigned, unsigned long)) /* Handle i-- and i++ */ { diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index 18219a337..d5b3d7f42 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -20,7 +20,7 @@ COMMON = ../common CFLAGS = -O2 -g -Wall -W -I$(COMMON) $(CDEFS) CC=gcc EBIND=emxbind -LDFLAGS= +LDFLAGS=-lm # ------------------------------------------------------------------------------ # Object files and libraries to link diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 73ce35aed..1640e5c5c 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -38,6 +38,7 @@ #include #include #include +#include /* common */ #include "chartype.h" @@ -391,7 +392,7 @@ static void StringConst (void) } /* Skip closing quote char if there was one */ - NextChar (); + NextChar (); /* Skip white space, read new input */ SkipWhite (); @@ -404,6 +405,252 @@ static void StringConst (void) +static void NumericConst (void) +/* Parse a numeric constant */ +{ + unsigned Base; /* Temporary number base */ + unsigned Prefix; /* Base according to prefix */ + StrBuf S; + int IsFloat; + char C; + unsigned DigitVal; + unsigned long IVal; /* Value */ + + /* Check for a leading hex or octal prefix and determine the possible + * integer types. + */ + if (CurC == '0') { + /* Gobble 0 and examine next char */ + NextChar (); + if (toupper (CurC) == 'X') { + Base = Prefix = 16; + NextChar (); /* gobble "x" */ + } else { + Base = 10; /* Assume 10 for now - see below */ + Prefix = 8; /* Actual prefix says octal */ + } + } else { + Base = Prefix = 10; + } + + /* Because floating point numbers don't have octal prefixes (a number + * with a leading zero is decimal), we first have to read the number + * 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 (); + } + SB_Terminate (&S); + + /* The following character tells us if we have an integer or floating + * point constant. + */ + IsFloat = (CurC == '.' || + (Base == 10 && toupper (CurC) == 'E') || + (Base == 16 && toupper (CurC) == 'P')); + + /* If we don't have a floating point type, an octal prefix results in an + * octal base. + */ + if (!IsFloat && Prefix == 8) { + Base = 8; + } + + /* Since we do now know the correct base, convert the remembered input + * into a number. + */ + SB_Reset (&S); + IVal = 0; + while ((C = SB_Get (&S)) != '\0') { + DigitVal = HexVal (C); + if (DigitVal >= Base) { + Error ("Numeric constant contains digits beyond the radix"); + } + IVal = (IVal * Base) + DigitVal; + } + + /* We don't need the string buffer any longer */ + DoneStrBuf (&S); + + /* Distinguish between integer and floating point constants */ + if (!IsFloat) { + + unsigned Types; + int HaveSuffix; + + /* Check for a suffix and determine the possible types */ + HaveSuffix = 1; + if (toupper (CurC) == 'U') { + /* Unsigned type */ + NextChar (); + if (toupper (CurC) != 'L') { + Types = IT_UINT | IT_ULONG; + } else { + NextChar (); + Types = IT_ULONG; + } + } else if (toupper (CurC) == 'L') { + /* Long type */ + NextChar (); + if (toupper (CurC) != 'U') { + Types = IT_LONG | IT_ULONG; + } else { + NextChar (); + Types = IT_ULONG; + } + } else { + HaveSuffix = 0; + if (Prefix == 10) { + /* Decimal constants are of any type but uint */ + Types = IT_INT | IT_LONG | IT_ULONG; + } else { + /* Octal or hex constants are of any type */ + Types = IT_INT | IT_UINT | IT_LONG | IT_ULONG; + } + } + + /* Check the range to determine the type */ + if (IVal > 0x7FFF) { + /* Out of range for int */ + Types &= ~IT_INT; + /* If the value is in the range 0x8000..0xFFFF, unsigned int is not + * allowed, and we don't have a type specifying suffix, emit a + * warning, because the constant is of type long. + */ + if (IVal <= 0xFFFF && (Types & IT_UINT) == 0 && !HaveSuffix) { + Warning ("Constant is long"); + } + } + if (IVal > 0xFFFF) { + /* Out of range for unsigned int */ + Types &= ~IT_UINT; + } + if (IVal > 0x7FFFFFFF) { + /* Out of range for long int */ + Types &= ~IT_LONG; + } + + /* Now set the type string to the smallest type in types */ + if (Types & IT_INT) { + NextTok.Type = type_int; + } else if (Types & IT_UINT) { + NextTok.Type = type_uint; + } else if (Types & IT_LONG) { + NextTok.Type = type_long; + } else { + NextTok.Type = type_ulong; + } + + /* Set the value and the token */ + NextTok.IVal = IVal; + NextTok.Tok = TOK_ICONST; + + } else { + + /* Float constant */ + double FVal = IVal; /* Convert to float */ + + /* Check for a fractional part and read it */ + if (CurC == '.') { + + unsigned Digits; + unsigned long Frac; + unsigned long 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; + while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) { + if (Digits < 8) { + Frac = Frac * Base + DigitVal; + ++Digits; + Scale *= Base; + } + NextChar (); + } + + /* Scale the fractional part and add it */ + if (Frac) { + FVal += ((double) Frac) / ((double) Scale); + } + } + + /* Check for an exponent and read it */ + if ((Base == 16 && toupper (CurC) == 'F') || + (Base == 10 && toupper (CurC) == 'E')) { + + int Sign; + unsigned Digits; + unsigned Exp; + + /* Skip the exponent notifier */ + NextChar (); + + /* Read an optional sign */ + Sign = 1; + if (CurC == '-') { + Sign = -1; + NextChar (); + } + + /* Read exponent digits. Since we support only 32 bit floats + * with a maximum exponent of +-/127, we read the exponent + * part as integer with up to 3 digits and drop the remainder. + * This avoids an overflow of Exp. The exponent is always + * decimal, even for hex float consts. + */ + Digits = 0; + Exp = 0; + while (IsDigit (CurC)) { + if (++Digits <= 3) { + Exp = Exp * 10 + HexVal (CurC); + } + NextChar (); + } + + /* Check for errors: We must have exponent digits, and not more + * than three. + */ + if (Digits == 0) { + Error ("Floating constant exponent has no digits"); + } else if (Digits > 3) { + Warning ("Floating constant exponent is too large"); + } + + /* Scale the exponent and adjust the value accordingly */ + if (Exp) { + FVal *= pow (10, Exp); + } + } + + /* Check for a suffix and determine the type of the constant */ + if (toupper (CurC) == 'F') { + NextChar (); + NextTok.Type = type_float; + } else { + NextTok.Type = type_double; + } + + /* Set the value and the token */ + NextTok.FVal = FVal; + NextTok.Tok = TOK_FCONST; + + } +} + + + void NextToken (void) /* Get next token from input stream */ { @@ -442,108 +689,8 @@ void NextToken (void) /* Determine the next token from the lookahead */ if (IsDigit (CurC)) { - /* A number */ - int HaveSuffix; /* True if we have a type suffix */ - unsigned types; /* Possible types */ - unsigned Base; - unsigned DigitVal; - unsigned long k; /* Value */ - - k = 0; - Base = 10; - types = IT_INT | IT_LONG | IT_ULONG; - - if (CurC == '0') { - /* Octal or hex constants may also be of type unsigned int */ - types = IT_INT | IT_UINT | IT_LONG | IT_ULONG; - /* gobble 0 and examin next char */ - NextChar (); - if (toupper (CurC) == 'X') { - Base = 16; - NextTok.Type = type_uint; - NextChar (); /* gobble "x" */ - } else { - Base = 8; - } - } - while (IsXDigit (CurC) && (DigitVal = HexVal (CurC)) < Base) { - k = k * Base + DigitVal; - NextChar (); - } - /* Check for errorneous digits */ - if (Base == 8 && IsDigit (CurC)) { - Error ("Numeric constant contains digits beyond the radix"); - /* Do error recovery */ - do { - NextChar (); - } while (IsDigit (CurC)); - } else if (Base != 16 && IsXDigit (CurC)) { - Error ("Nondigits in number and not hexadecimal"); - do { - NextChar (); - } while (IsXDigit (CurC)); - } - - /* Check for a suffix */ - HaveSuffix = 1; - if (CurC == 'u' || CurC == 'U') { - /* Unsigned type */ - NextChar (); - if (toupper (CurC) != 'L') { - types = IT_UINT | IT_ULONG; - } else { - NextChar (); - types = IT_ULONG; - } - } else if (CurC == 'l' || CurC == 'L') { - /* Long type */ - NextChar (); - if (toupper (CurC) != 'U') { - types = IT_LONG | IT_ULONG; - } else { - NextChar (); - types = IT_ULONG; - } - } else { - HaveSuffix = 0; - } - - /* Check the range to determine the type */ - if (k > 0x7FFF) { - /* Out of range for int */ - types &= ~IT_INT; - /* If the value is in the range 0x8000..0xFFFF, unsigned int is not - * allowed, and we don't have a type specifying suffix, emit a - * warning. - */ - if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) { - Warning ("Constant is long"); - } - } - if (k > 0xFFFF) { - /* Out of range for unsigned int */ - types &= ~IT_UINT; - } - if (k > 0x7FFFFFFF) { - /* Out of range for long int */ - types &= ~IT_LONG; - } - - /* Now set the type string to the smallest type in types */ - if (types & IT_INT) { - NextTok.Type = type_int; - } else if (types & IT_UINT) { - NextTok.Type = type_uint; - } else if (types & IT_LONG) { - NextTok.Type = type_long; - } else { - NextTok.Type = type_ulong; - } - - /* Set the value and the token */ - NextTok.IVal = k; - NextTok.Tok = TOK_ICONST; + NumericConst (); return; } @@ -677,18 +824,22 @@ void NextToken (void) } break; - case '.': - NextChar (); - if (CurC == '.') { - NextChar (); - if (CurC == '.') { - SetTok (TOK_ELLIPSIS); - } else { - UnknownChar (CurC); - } - } else { - NextTok.Tok = TOK_DOT; - } + case '.': + if (IsDigit (NextC)) { + NumericConst (); + } else { + NextChar (); + if (CurC == '.') { + NextChar (); + if (CurC == '.') { + SetTok (TOK_ELLIPSIS); + } else { + UnknownChar (CurC); + } + } else { + NextTok.Tok = TOK_DOT; + } + } break; case '/':