From bfc3125556b7a8c28e79a44ceaf0a3eb346300b8 Mon Sep 17 00:00:00 2001 From: Alexey Frunze Date: Sat, 16 Jan 2016 22:45:42 -0800 Subject: [PATCH] Floats in Smaller C! double is an alias for float. IOW, only 32-bit single precision floats are supported. This isn't conformant, but OK for some embedded systems (e.g. RetroBSD) and simple compilers like this. Also, the following operators are not supported with floats at the moment: ++, --, +=, -=, *=, /=. But +, -, *, /, =, ||, &&, ?:, !, comparison, casts, if/while/for are OK. --- src/cmd/smlrc/Makefile | 2 +- src/cmd/smlrc/cgmips.c | 5 + src/cmd/smlrc/fp.c | 323 +++++++ src/cmd/smlrc/lb.c | 209 ++++- src/cmd/smlrc/smlrc.c | 2009 +++++++++++++++++++++++++++++++--------- 5 files changed, 2093 insertions(+), 455 deletions(-) create mode 100644 src/cmd/smlrc/fp.c diff --git a/src/cmd/smlrc/Makefile b/src/cmd/smlrc/Makefile index 119d50d..bb3e22a 100644 --- a/src/cmd/smlrc/Makefile +++ b/src/cmd/smlrc/Makefile @@ -32,5 +32,5 @@ install: smlrc clean: rm -f *.o smlrc smlrc.dis smlrc.elf ### -smlrc.o: smlrc.c cgmips.c +smlrc.o: smlrc.c fp.c cgmips.c ${CC} ${CFLAGS} -mips16 smlrc.c -c -o $@ diff --git a/src/cmd/smlrc/cgmips.c b/src/cmd/smlrc/cgmips.c index 2cfde75..685e60f 100644 --- a/src/cmd/smlrc/cgmips.c +++ b/src/cmd/smlrc/cgmips.c @@ -546,6 +546,11 @@ void GenFxnProlog(void) int i, cnt = CurFxnParamCntMax; if (cnt > 4) cnt = 4; + // TBD!!! for structure passing use the cumulative parameter size + // instead of the number of parameters. Currently this bug is masked + // by the subroutine that pushes structures on the stack (it copies + // all words except the first to the stack). But passing structures + // in registers from assembly code won't always work. for (i = 0; i < cnt; i++) GenPrintInstr2Operands(MipsInstrSW, 0, MipsOpRegA0 + i, 0, diff --git a/src/cmd/smlrc/fp.c b/src/cmd/smlrc/fp.c new file mode 100644 index 0000000..585f351 --- /dev/null +++ b/src/cmd/smlrc/fp.c @@ -0,0 +1,323 @@ +/* + Copyright (c) 2016, Alexey Frunze + 2-clause BSD license. +*/ + +// This file implements the basic arithmetic functions on floats and +// expects that the host representation of floats coinsides with the +// target representation of floats and is IEEE 754 single precision. +// It is also expected that the host implementation does not raise +// any signals nor results in undefined behavior when handling +// special cases involving infinities, NaNs and denormal numbers. + +// Make sure float and int are the same size, so they can be +// copied one into another byte by byte with memcpy(). +extern char StAtIcAsSeRt[(sizeof(float) == sizeof(unsigned)) ? 1 : -1]; + +// There can be up to 112 significant digits in a 32-bit single precision +// floating point number (in the maximum positive denormal number). +// We'll ignore any following digits, but convert these 112 with proper +// rounding to even, which is enough for all floats representable exactly, +// which should be enough for most practical purposes. +#define MAX_CONST_DIGITS 112 // must be big enough for decimal/octal ints as well +unsigned char ConstDigits[MAX_CONST_DIGITS]; +#define FP_MANT_BITS 23 // bits in mantissa, excluding the implicit 1 +#define FP_EXP_BITS 8 // bits in exponent +#define FP_MIN_EXP (-46) // from min denormal, ~1.40e-45 + // (-46 is chosen because we need to handle numbers + // like 9e-46 which round up to a non-zero denormal + // number ~1.40e-45) +#define FP_MAX_EXP 38 // from max normal, ~3.40e+38 +#define FP_BUF_SIZE (((((MAX_CONST_DIGITS-FP_MIN_EXP)*10+2)/3+FP_MANT_BITS+2)+7)/8) +unsigned char ConstBinDigits[FP_BUF_SIZE]; + +STATIC +unsigned f2u(unsigned f) +{ + float ff; + memcpy(&ff, &f, sizeof ff); + if (ff != ff || ff <= -1.0f || ff >= (float)0x10000*0x10000/* 2**32 */) + { + warnFloat2Int(); + ff = 0; + } + return ff; +} + +STATIC +unsigned f2i(unsigned f, int opsz) +{ + float ff; + int ovf = 0; + memcpy(&ff, &f, sizeof ff); + if (ff != ff) + { + ovf = 1; + } + else + { + switch (opsz) + { + case 1: // unsigned char + ovf = ff <= -1.0f || ff >= 256.0f; + break; + case 2: // unsigned short + ovf = ff <= -1.0f || ff >= 65536.0f; + break; + case -1: // signed char + ovf = ff <= -129.0f || ff >= 128.0f; + break; + case -2: // signed short + ovf = ff <= -32769.0f || ff >= 32768.0f; + break; + default: // signed int + ovf = ff < -(float)0x8000*0x10000/* -2**31 */ || ff >= (float)0x8000*0x10000/* 2**31 */; + break; + } + } + if (ovf) + { + warnFloat2Int(); + ff = 0; + } + return (int)ff; +} + +STATIC +unsigned u2f(unsigned i) +{ + float f = i; + memcpy(&i, &f, sizeof i); + return i; +} + +STATIC +unsigned i2f(unsigned i) +{ + float f = (int)i; + memcpy(&i, &f, sizeof i); + return i; +} + +STATIC +unsigned fneg(unsigned f) +{ + float ff; + memcpy(&ff, &f, sizeof ff); + ff = -ff; + memcpy(&f, &ff, sizeof f); + return f; +} + +STATIC +unsigned fadd(unsigned fa, unsigned fb) +{ + float ffa, ffb; + memcpy(&ffa, &fa, sizeof ffa); + memcpy(&ffb, &fb, sizeof ffb); + ffa = ffa + ffb; + memcpy(&fa, &ffa, sizeof fa); + return fa; +} + +STATIC +unsigned fsub(unsigned fa, unsigned fb) +{ + return fadd(fa, fneg(fb)); +} + +STATIC +unsigned fmul(unsigned fa, unsigned fb) +{ + float ffa, ffb; + memcpy(&ffa, &fa, sizeof ffa); + memcpy(&ffb, &fb, sizeof ffb); + ffa = ffa * ffb; + memcpy(&fa, &ffa, sizeof fa); + return fa; +} + +STATIC +unsigned fdiv(unsigned fa, unsigned fb) +{ + float ffa, ffb; + memcpy(&ffa, &fa, sizeof ffa); + memcpy(&ffb, &fb, sizeof ffb); + ffa = ffa / ffb; + memcpy(&fa, &ffa, sizeof fa); + return fa; +} + +STATIC +int fcmp(unsigned fa, unsigned fb, int nanRes) +{ + float ffa, ffb; + memcpy(&ffa, &fa, sizeof ffa); + memcpy(&ffb, &fb, sizeof ffb); + if (ffa != ffa || ffb != ffb) + return nanRes; + if (ffa < ffb) + return -1; + if (ffa > ffb) + return +1; + return 0; +} + +STATIC +void ChainMultiplyAdd(unsigned char* pChain, + unsigned ChainLen, + unsigned char Multiplier, + unsigned char Addend) +{ + unsigned carry = Addend; + + while (ChainLen--) + { + carry += *pChain * Multiplier; + *pChain++ = carry & 0xFFu; + carry >>= 8; + } +} + +STATIC +void ChainDivide(unsigned char* pChain, + unsigned ChainLen, + unsigned char Divisor, + unsigned char* pRemainder) +{ + unsigned remainder = 0; + + while (ChainLen) + { + remainder += pChain[ChainLen - 1]; + pChain[ChainLen - 1] = remainder / Divisor; + remainder = (remainder % Divisor) << 8; + ChainLen--; + } + + if (pRemainder != NULL) + *pRemainder = remainder >> 8; +} + +// Multiplies an integer (cnt decimal digits (0 to 9) from digits[]) by +// 10**eexp, converts the product to a float and returns it as unsigned int. +// This is an inefficient but straightforward algorithm with proper rounding. +STATIC +unsigned d2f(unsigned char* digits, int cnt, int eexp) +{ + unsigned numDecDigits; + unsigned denDecDigits; + unsigned numBinDigits; + unsigned numBytes; + int tmp; + unsigned char remainder; + int binExp = 0; + int inexact = 0; + int lastInexact = 0; + unsigned res; + + // 0? + if (cnt == 1 && *digits == 0) + return 0; + // less than the denormalized minimum? + if (eexp < FP_MIN_EXP - (cnt - 1)) + return 0; + + // greater than the normalized maximum? + if (eexp > FP_MAX_EXP - (cnt - 1)) + return 0x7F800000; // +INF + + numDecDigits = cnt + ((eexp >= 0) ? eexp : 0); + denDecDigits = 1 + ((eexp < 0) ? -eexp : 0); + + // 10/3=3.3(3) > log2(10)~=3.32 + if (eexp >= 0) + { + unsigned t1 = (numDecDigits * 10 + 2) / 3; + unsigned t2 = FP_MANT_BITS + 1; + numBinDigits = (t1 >= t2) ? t1 : t2; + } + else + { + unsigned t1 = (numDecDigits * 10 + 2) / 3; + unsigned t2 = (denDecDigits * 10 + 2) / 3 + FP_MANT_BITS + 1 + 1; + numBinDigits = (t1 >= t2) ? t1 : t2; + } + + numBytes = (numBinDigits + 7) / 8; + if (numBytes > (unsigned)FP_BUF_SIZE) + errorInternal(200); + memset(ConstBinDigits, 0, numBytes); + + // Convert the numerator to binary + for (tmp = 0; tmp < cnt; tmp++) + ChainMultiplyAdd(ConstBinDigits, numBytes, 10, ConstDigits[tmp]); + for (tmp = eexp; tmp > 0; tmp--) + ChainMultiplyAdd(ConstBinDigits, numBytes, 10, 0); + + // If the denominator isn't 1, divide the numerator by the denominator + // getting at least FractionBitCnt+2 significant bits of quotient + if (eexp < 0) + { + binExp = -(int)(numBinDigits - (numDecDigits * 10 + 2) / 3); + for (tmp = binExp; tmp < 0; tmp++) + ChainMultiplyAdd(ConstBinDigits, numBytes, 2, 0); + for (tmp = eexp; tmp < 0; tmp++) + ChainDivide(ConstBinDigits, numBytes, 10, &remainder), + lastInexact = inexact, inexact |= !!remainder; + } + + // Find the most significant bit and normalize the mantissa + // by shifting it left + for (tmp = numBytes - 1; tmp >= 0 && !ConstBinDigits[tmp]; tmp--); + if (tmp >= 0) + { + tmp = tmp * 8 + 7; + while (!(ConstBinDigits[tmp / 8] & (1 << tmp % 8))) tmp--; + while (tmp < FP_MANT_BITS) + ChainMultiplyAdd(ConstBinDigits, numBytes, 2, 0), binExp--, tmp++; + } + + // Find the most significant bit and normalize the mantissa + // by shifting it right + do + { + remainder = 0; + for (tmp = numBytes - 1; tmp >= 0 && !ConstBinDigits[tmp]; tmp--); + if (tmp >= 0) + { + tmp = tmp * 8 + 7; + while (!(ConstBinDigits[tmp / 8] & (1 << tmp % 8))) tmp--; + while (tmp > FP_MANT_BITS) + ChainDivide(ConstBinDigits, numBytes, 2, &remainder), + lastInexact = inexact, inexact |= !!remainder, binExp++, tmp--; + while (binExp < 2 - (1 << (FP_EXP_BITS - 1)) - FP_MANT_BITS) + ChainDivide(ConstBinDigits, numBytes, 2, &remainder), + lastInexact = inexact, inexact |= !!remainder, binExp++; + } + // Round to nearest even + remainder &= (lastInexact | (ConstBinDigits[0] & 1)); + if (remainder) + ChainMultiplyAdd(ConstBinDigits, numBytes, 1, 1); + } while (remainder); + + // Collect the result's mantissa + res = 0; + while (tmp >= 0) + { + res <<= 8; + res |= ConstBinDigits[tmp / 8]; + tmp -= 8; + } + + // Collect the result's exponent + binExp += (1 << (FP_EXP_BITS - 1)) - 1 + FP_MANT_BITS; + if (!(res & (1u << FP_MANT_BITS))) binExp = 0; // subnormal or 0 + res &= ~(1u << FP_MANT_BITS); + if (binExp >= (1 << FP_EXP_BITS) - 1) + binExp = (1 << FP_EXP_BITS) - 1, res = 0, inexact |= 1; // +INF + res |= (unsigned)binExp << FP_MANT_BITS; + + return res; +} + diff --git a/src/cmd/smlrc/lb.c b/src/cmd/smlrc/lb.c index e8dd16a..47a9854 100644 --- a/src/cmd/smlrc/lb.c +++ b/src/cmd/smlrc/lb.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2013-2015, Alexey Frunze +Copyright (c) 2013-2016, Alexey Frunze All rights reserved. Redistribution and use in source and binary forms, with or without @@ -66,6 +66,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern int main(int argc, char** argv); void exit(int); +#ifdef __SMALLER_C_32__ +extern void __x87init(void); +#endif + #ifdef _RETROBSD void __start__(int argc, char** argv) { @@ -75,6 +79,7 @@ void __start__(int argc, char** argv) #ifdef _LINUX void __start__(int argc, char** argv) { + __x87init(); exit(main(argc, argv)); } #else @@ -85,6 +90,9 @@ void __start__(void) int argc; char** argv; __setargs__(&argc, &argv); +#ifdef __SMALLER_C_32__ + __x87init(); +#endif exit(main(argc, argv)); } #endif @@ -371,6 +379,22 @@ void* memset(void* s, int c, unsigned n) return s; } +#ifdef __SMALLER_C_32__ +int memcmp(void* s1, void* s2, unsigned n) +{ + if (n) + { + unsigned char *p1 = s1, *p2 = s2; + do + { + if (*p1++ != *p2++) + return (*--p1 - *--p2); + } while (--n); + } + return 0; +} +#endif + int fputc(int c, FILE* stream); int putchar(int c); @@ -1548,4 +1572,187 @@ int fsetpos(FILE* stream, fpos_t* pos) return 0; } + +#ifdef __SMALLER_C_32__ +#ifndef _RETROBSD + +#ifdef __HUGE__ +#define xbp "bp" +#define xsp "sp" +#else +#define xbp "ebp" +#define xsp "esp" +#endif + +void __x87init(void) +{ + // Mask all exceptions, set rounding to nearest even and precision to 64 bits. + // TBD??? Actually check for x87??? + asm("fninit"); +} + +float __floatsisf(int i) +{ + asm + ( + "fild dword ["xbp"+8]\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +float __floatunsisf(unsigned i) +{ + asm + ( + "push dword 0\n" + "push dword ["xbp"+8]\n" + "fild qword ["xbp"-8]\n" // load 32-bit unsigned int as 64-bit signed int + "add "xsp", 8\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +int __fixsfsi(float f) +{ + asm + ( + "sub "xsp", 4\n" + "fnstcw ["xbp"-2]\n" // save rounding + "mov ax, ["xbp"-2]\n" + "mov ah, 0x0c\n" // rounding towards 0 (AKA truncate) since we don't have fisttp + "mov ["xbp"-4], ax\n" + "fld dword ["xbp"+8]\n" + "fldcw ["xbp"-4]\n" // rounding = truncation + "fistp dword ["xbp"+8]\n" + "fldcw ["xbp"-2]\n" // restore rounding + "add "xsp", 4\n" + "mov eax, ["xbp"+8]" + ); +} + +unsigned __fixunssfsi(float f) +{ + asm + ( + "sub "xsp", 12\n" + "fnstcw ["xbp"-2]\n" // save rounding + "mov ax, ["xbp"-2]\n" + "mov ah, 0x0c\n" // rounding towards 0 (AKA truncate) since we don't have fisttp + "mov ["xbp"-4], ax\n" + "fld dword ["xbp"+8]\n" + "fldcw ["xbp"-4]\n" // rounding = truncation + "fistp qword ["xbp"-12]\n" // store 64-bit signed int + "fldcw ["xbp"-2]\n" // restore rounding + "mov eax, ["xbp"-12]\n" // take low 32 bits + "add "xsp", 12" + ); +} + +float __addsf3(float a, float b) +{ + asm + ( + "fld dword ["xbp"+8]\n" + "fadd dword ["xbp"+12]\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +float __subsf3(float a, float b) +{ + asm + ( + "fld dword ["xbp"+8]\n" + "fsub dword ["xbp"+12]\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +float __negsf2(float f) +{ + asm + ( + "mov eax, ["xbp"+8]\n" + "xor eax, 0x80000000" + ); +} + +float __mulsf3(float a, float b) +{ + asm + ( + "fld dword ["xbp"+8]\n" + "fmul dword ["xbp"+12]\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +float __divsf3(float a, float b) +{ + asm + ( + "fld dword ["xbp"+8]\n" + "fdiv dword ["xbp"+12]\n" + "fstp dword ["xbp"+8]\n" + "mov eax, ["xbp"+8]" + ); +} + +float __lesf2(float a, float b) +{ + asm + ( + "fld dword ["xbp"+12]\n" + "fld dword ["xbp"+8]\n" + "fucompp\n" + "fstsw ax\n" // must use these moves since we don't have fucomip + "sahf\n" + "jnp .ordered\n" + "mov eax, +1\n" // return +1 if either a or b (or both) is a NaN + "jmp .done\n" + ".ordered:\n" + "jnz .unequal\n" + "xor eax, eax\n" // return 0 if a == b + "jmp .done\n" + ".unequal:\n" + "sbb eax, eax\n" + "jc .done\n" // return -1 if a < b + "inc eax\n" // return +1 if a > b + ".done:" + ); +} + +float __gesf2(float a, float b) +{ + asm + ( + "fld dword ["xbp"+12]\n" + "fld dword ["xbp"+8]\n" + "fucompp\n" + "fstsw ax\n" // must use these moves since we don't have fucomip + "sahf\n" + "jnp .ordered\n" + "mov eax, -1\n" // return -1 if either a or b (or both) is a NaN + "jmp .done\n" + ".ordered:\n" + "jnz .unequal\n" + "xor eax, eax\n" // return 0 if a == b + "jmp .done\n" + ".unequal:\n" + "sbb eax, eax\n" + "jc .done\n" // return -1 if a < b + "inc eax\n" // return +1 if a > b + ".done:" + ); +} + +#endif +#endif + #endif /*__APPLE__*/ + diff --git a/src/cmd/smlrc/smlrc.c b/src/cmd/smlrc/smlrc.c index d53af7e..5956605 100644 --- a/src/cmd/smlrc/smlrc.c +++ b/src/cmd/smlrc/smlrc.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2012-2015, Alexey Frunze +Copyright (c) 2012-2016, Alexey Frunze All rights reserved. Redistribution and use in source and binary forms, with or without @@ -53,6 +53,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define NO_EXTRA_WARNS #define NO_FOR_DECL #define NO_STRUCT_BY_VAL +#define NO_FP #endif // Passing and returning structures by value is currenly supported @@ -131,6 +132,7 @@ int strncmp(char*, char*, size_t); void* memmove(void*, void*, size_t); void* memcpy(void*, void*, size_t); void* memset(void*, int, size_t); +int memcmp(void*, void*, size_t); int isspace(int); int isdigit(int); @@ -169,6 +171,12 @@ int fsetpos(FILE*, fpos_t*); #endif // #ifndef __SMALLER_C__ +// Floating point requires 32 bits +#ifndef CAN_COMPILE_32BIT +#ifndef NO_FP +#define NO_FP +#endif +#endif //////////////////////////////////////////////////////////////////////////////// @@ -184,15 +192,15 @@ int fsetpos(FILE*, fpos_t*); #define MAX_CHAR_QUEUE_LEN (MAX_STRING_LEN + 1) #ifndef MAX_MACRO_TABLE_LEN -#define MAX_MACRO_TABLE_LEN 4096 +#define MAX_MACRO_TABLE_LEN (4096+1024) #endif #ifndef MAX_IDENT_TABLE_LEN -#define MAX_IDENT_TABLE_LEN (4096+656+64) // must be greater than MAX_IDENT_LEN +#define MAX_IDENT_TABLE_LEN (4096+1024+512) // must be greater than MAX_IDENT_LEN #endif #ifndef SYNTAX_STACK_MAX -#define SYNTAX_STACK_MAX (2048+512+64+32) +#define SYNTAX_STACK_MAX (2048+1024) #endif #ifndef MAX_FILE_NAME_LEN @@ -326,6 +334,7 @@ int fsetpos(FILE*, fpos_t*); #define tokMemberIdent 0x92 #define tokEnumPtr 0x93 #define tokIntr 0x94 +#define tokNumFloat 0x95 //#define FormatFlat 0 #define FormatSegmented 1 @@ -335,7 +344,8 @@ int fsetpos(FILE*, fpos_t*); #define SymVoidSynPtr 0 #define SymIntSynPtr 1 #define SymUintSynPtr 2 -#define SymFuncPtr 3 +#define SymFloatSynPtr 3 +#define SymFuncPtr 4 #ifndef STACK_SIZE #define STACK_SIZE 129 @@ -492,6 +502,10 @@ STATIC void errorNotConst(void); STATIC void errorLongExpr(void); +#ifndef NO_FP +STATIC +void warnFloat2Int(void); +#endif STATIC int FindSymbol(char* s); @@ -982,7 +996,7 @@ unsigned char tktk[] = tokUGreater, tokUGEQ, tokAssignURSh, tokAssignUDiv, tokAssignUMod, // Helper (pseudo-)tokens: tokNumInt, tokLitStr, tokLocalOfs, tokNumUint, tokIdent, tokShortCirc, - tokSChar, tokShort, tokLong, tokUChar, tokUShort, tokULong, + tokSChar, tokShort, tokLong, tokUChar, tokUShort, tokULong, tokNumFloat, }; char* tks[] = @@ -1004,7 +1018,7 @@ char* tks[] = ">u", ">=u", ">>=u", "/=u", "%=u", // Helper (pseudo-)tokens: "", "", "", "", "", "", - "signed char", "short", "long", "unsigned char", "unsigned short", "unsigned long", + "signed char", "short", "long", "unsigned char", "unsigned short", "unsigned long", "float" }; STATIC @@ -1461,91 +1475,230 @@ int popPrep(void) } #endif +#ifndef NO_FP +#include "fp.c" + +#define FXNI2F 0 +#define FXNU2F 1 +#define FXNF2I 2 +#define FXNF2U 3 +#define FXNFADD 4 +#define FXNFSUB 5 +#define FXNFNEG 6 +#define FXNFMUL 7 +#define FXNFDIV 8 +#define FXNFCMPL 9 +#define FXNFCMPG 10 +// Names of external functions for floating point arithmetic +char* FpFxnName[] = +{ + /*FXNI2F */ "__floatsisf", + /*FXNU2F */ "__floatunsisf", + /*FXNF2I */ "__fixsfsi", + /*FXNF2U */ "__fixunssfsi", + /*FXNFADD */ "__addsf3", + /*FXNFSUB */ "__subsf3", + /*FXNFNEG */ "__negsf2", + /*FXNFMUL */ "__mulsf3", + /*FXNFDIV */ "__divsf3", + /*FXNFCMPL*/ "__lesf2", + /*FXNFCMPG*/ "__gesf2" +}; +#endif + STATIC int GetNumber(void) { char* p = CharQueue; int ch = *p; + int leadingZero = (ch == '0'); unsigned n = 0; int type = 0; int uSuffix = 0; #ifdef CAN_COMPILE_32BIT int lSuffix = 0; +#endif +#ifndef NO_FP + int mcnt = 0, eexp = 0; #endif char* eTooBig = "Constant too big\n"; - if (ch == '0') + // First, detect and handle hex constants. Octals can't be detected immediately + // because floating-point constants also may begin with the digit 0. + + if (leadingZero && (p[1] == 'x' || p[1] == 'X')) { - // this is either an octal or a hex constant - type = 'o'; + // this is a hex constant + int cnt = 0; + type = 'h'; ShiftCharN(1); - if ((ch = *p) == 'x' || ch == 'X') + ShiftCharN(1); + while ((ch = *p) != '\0' && (isdigit(ch & 0xFFu) || strchr("abcdefABCDEF", ch))) { - // this is a hex constant - int cnt = 0; - ShiftCharN(1); - while ((ch = *p) != '\0' && (isdigit(ch & 0xFFu) || strchr("abcdefABCDEF", ch))) - { - if (ch >= 'a') ch -= 'a' - 10; - else if (ch >= 'A') ch -= 'A' - 10; - else ch -= '0'; - if (PrepDontSkipTokens && (n * 16 / 16 != n || n * 16 + ch < n * 16)) - error(eTooBig); - n = n * 16 + ch; - ShiftCharN(1); - cnt++; - } - if (!cnt) - error("Invalid hexadecimal constant\n"); - type = 'h'; - } - // this is an octal constant - else while ((ch = *p) >= '0' && ch <= '7') - { - ch -= '0'; - if (PrepDontSkipTokens && (n * 8 / 8 != n || n * 8 + ch < n * 8)) + if (ch >= 'a') ch -= 'a' - 10; + else if (ch >= 'A') ch -= 'A' - 10; + else ch -= '0'; + if (PrepDontSkipTokens && (n * 16 / 16 != n || n * 16 + ch < n * 16)) error(eTooBig); - n = n * 8 + ch; + n = n * 16 + ch; ShiftCharN(1); + cnt++; } + if (!cnt) + error("Invalid hexadecimal constant\n"); } - // this is a decimal constant +#ifndef NO_FP else { + // this is a decimal (possibly floating-point) or an octal constant, parse as decimal + int mexp = 0, dot = 0; + int ecnt = 0; type = 'd'; - while ((ch = *p) >= '0' && ch <= '9') + // skip leading zeroes, if any + while (*p == '0') + ShiftCharN(1); + // get digits of integral part, if any + while (isdigit((ch = *p) & 0xFFu)) + { + if (mcnt < MAX_CONST_DIGITS) + ConstDigits[mcnt++] = ch - '0'; + else + mexp++; // TBD??? overflow + ShiftCharN(1); + } + // get dot and digits of fractional part, if any + if (*p == '.') + { + dot = 1; + ShiftCharN(1); + // if the integral part is 0, skip leading zeroes in the fractional part, if any + if (!mcnt) + while (*p == '0') + ShiftCharN(1), mexp--; // TBD??? overflow + while (isdigit((ch = *p) & 0xFFu)) + { + if (mcnt < MAX_CONST_DIGITS) + ConstDigits[mcnt++] = ch - '0'; + mexp--; // TBD??? overflow + ShiftCharN(1); + } + } + // get exponent part, if any + if (*p == 'e' || *p == 'E') + { + int esign = '+'; + ShiftCharN(1); + if (*p == '+' || *p == '-') + esign = *p, ShiftCharN(1); + while (isdigit((ch = *p) & 0xFFu)) + { + ch -= '0'; + if (n * 10 / 10 != n || + n * 10 + ch < n * 10 || + n * 10 + ch > UINT_MAX / 2) + { + if (PrepDontSkipTokens) + error(eTooBig); + n = 0; + } + n = n * 10 + ch; + ShiftCharN(1); + ecnt++; + } + if (!ecnt) + error("Invalid float constant\n"); + eexp = n; + if (esign == '-') + eexp = -eexp; + } + if (dot || ecnt) + { + // this is a float constant (has either a dot or an exponent) + // get float suffix, if any + type = 'f'; + if (*p == 'f' || *p == 'F') + ShiftCharN(1); + // also drop trailing zeroes, if any + while (mcnt) + { + if (ConstDigits[mcnt - 1]) + break; + mexp++; // TBD??? overflow + mcnt--; + } + if (!mcnt) + ConstDigits[mcnt++] = 0, mexp = 0; + if ((mexp >= 0 && eexp > INT_MAX - mexp) || + (mexp < 0 && eexp <= INT_MIN - (mexp + 1))) + { + if (PrepDontSkipTokens) + error(eTooBig); + } + else + eexp += mexp; + } + else + { + // handle decimal and octal integers + int base = leadingZero ? 8 : 10; + int i; + type = leadingZero ? 'o' : 'd'; + for (i = 0; i < mcnt; i++) + { + ch = ConstDigits[i]; + if (ch >= base) + error("Invalid octal constant\n"); + if (PrepDontSkipTokens && (n * base / base != n || n * base + ch < n * base)) + error(eTooBig); + n = n * base + ch; + } + } + } +#else + else + { + // handle decimal and octal integers + int base = leadingZero ? 8 : 10; + type = leadingZero ? 'o' : 'd'; + while ((ch = *p) >= '0' && ch < base + '0') { ch -= '0'; - if (PrepDontSkipTokens && (n * 10 / 10 != n || n * 10 + ch < n * 10)) + if (PrepDontSkipTokens && (n * base / base != n || n * base + ch < n * base)) error(eTooBig); - n = n * 10 + ch; + n = n * base + ch; ShiftCharN(1); } } +#endif - // possible combinations of suffixes: + // possible combinations of integer suffixes: // none // U // UL // L // LU - if ((ch = *p) == 'u' || ch == 'U') +#ifndef NO_FP + if (type != 'f') +#endif { - uSuffix = 1; - ShiftCharN(1); - } -#ifdef CAN_COMPILE_32BIT - if ((ch = *p) == 'l' || ch == 'L') - { - lSuffix = 1; - ShiftCharN(1); - if (!uSuffix && ((ch = *p) == 'u' || ch == 'U')) + if ((ch = *p) == 'u' || ch == 'U') { uSuffix = 1; ShiftCharN(1); } - } +#ifdef CAN_COMPILE_32BIT + if ((ch = *p) == 'l' || ch == 'L') + { + lSuffix = 1; + ShiftCharN(1); + if (!uSuffix && ((ch = *p) == 'u' || ch == 'U')) + { + uSuffix = 1; + ShiftCharN(1); + } + } #endif + } if (!PrepDontSkipTokens) { @@ -1554,6 +1707,14 @@ int GetNumber(void) return tokNumInt; } +#ifndef NO_FP + if (type == 'f') + { + TokenValueInt = d2f(ConstDigits, mcnt, eexp); + return tokNumFloat; + } +#endif + // Ensure the constant fits into 16(32) bits if ( (SizeOfWord == 2 && n >> 8 >> 8) // equiv. to SizeOfWord == 2 && n > 0xFFFF @@ -1642,6 +1803,9 @@ int GetTokenInner(void) ShiftCharN(1); return ch; case '.': if (p[1] == '.' && p[2] == '.') { ShiftCharN(3); return tokEllipsis; } +#ifndef NO_FP + if (isdigit(p[1] & 0xFFu)) { return GetNumber(); } +#endif ShiftCharN(1); return ch; case '*': if (p[1] == '=') { ShiftCharN(2); return tokAssignMul; } @@ -1651,7 +1815,6 @@ int GetTokenInner(void) ShiftCharN(1); return ch; case '/': if (p[1] == '=') { ShiftCharN(2); return tokAssignDiv; } - // if (p[1] == '/' || p[1] == '*') { SkipSpace(1); continue; } // already taken care of ShiftCharN(1); return ch; } @@ -2175,6 +2338,33 @@ void del(int pos, int cnt) sp -= cnt; } +#ifndef NO_FP +STATIC +void rev(int pos, int cnt) +{ + // reverse cnt items at pos on the stack + int (*p1)[2] = stack + pos, (*p2)[2] = p1 + cnt - 1; + while (p1 < p2) + { + int t0 = **p1; + int t1 = (*p1)[1]; + **p1 = **p2; + (*p1++)[1] = (*p2)[1]; + **p2 = t0; + (*p2--)[1] = t1; + } +} + +STATIC +void swap(int pos, int cntlo, int cnthi) +{ + // swap cntlo items at pos with cnthi items at pos + cntlo + rev(pos, cntlo); + rev(pos + cntlo, cnthi); + rev(pos, cntlo + cnthi); +} +#endif + STATIC void pushop2(int v, int v2) { @@ -2367,7 +2557,11 @@ int exprUnary(int tok, int* gotUnary, int commaSeparator, int argOfSizeOf) { int inspos = sp; - if (tok == tokNumInt || tok == tokNumUint) + if (tok == tokNumInt || +#ifndef NO_FP + tok == tokNumFloat || +#endif + tok == tokNumUint) { push2(tok, TokenValueInt); *gotUnary = 1; @@ -2678,49 +2872,95 @@ int expr(int tok, int* gotUnary, int commaSeparator) return tok; } +STATIC +int isAnyPtr(int ExprTypeSynPtr) +{ + if (ExprTypeSynPtr < 0) + return 1; + switch (SyntaxStack0[ExprTypeSynPtr]) + { + case '*': + case '[': + case '(': + return 1; + } + return 0; +} + +STATIC +int derefAnyPtr(int ExprTypeSynPtr) +{ + if (ExprTypeSynPtr < 0) + return -ExprTypeSynPtr; + switch (SyntaxStack0[ExprTypeSynPtr]) + { + case '*': + return ExprTypeSynPtr + 1; + case '[': + return ExprTypeSynPtr + 3; + case '(': + return ExprTypeSynPtr; + } + errorInternal(666); // TBD!!! code + return -1; +} + STATIC void decayArray(int* ExprTypeSynPtr, int arithmetic) { - // Dacay arrays to pointers to their first elements in - // binary + and - operators + // Dacay arrays to pointers to their first elements if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '[') { - while (SyntaxStack0[*ExprTypeSynPtr] != ']') - ++*ExprTypeSynPtr; - ++*ExprTypeSynPtr; - *ExprTypeSynPtr = -*ExprTypeSynPtr; - } - // Also, to simplify code, return all other pointers as - // negative expression stack syntax indices/pointers - else if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '*') - { - ++*ExprTypeSynPtr; + (*ExprTypeSynPtr) += 3; + // we cannot insert another '*' into the type to make it a pointer + // to the first element, so make the index into the type negative *ExprTypeSynPtr = -*ExprTypeSynPtr; } // DONE: disallow arithmetic on pointers to void // DONE: disallow function pointers - if (arithmetic) + if (arithmetic && isAnyPtr(*ExprTypeSynPtr)) { - if (*ExprTypeSynPtr < 0) + int pointee = derefAnyPtr(*ExprTypeSynPtr); + switch (SyntaxStack0[pointee]) { - if (SyntaxStack0[-*ExprTypeSynPtr] == tokVoid) - //error("decayArray(): cannot do pointer arithmetic on a pointer to 'void'\n"); - errorUnexpectedVoid(); - if (SyntaxStack0[-*ExprTypeSynPtr] == '(' || - !GetDeclSize(-*ExprTypeSynPtr, 0)) + case tokVoid: + //error("decayArray(): cannot do pointer arithmetic on a pointer to 'void'\n"); + errorUnexpectedVoid(); + default: + //error("decayArray(): cannot do pointer arithmetic on a pointer to an incomplete type\n"); + if (!GetDeclSize(pointee, 0)) + // "fallthrough" + case '(': //error("decayArray(): cannot do pointer arithmetic on a pointer to a function\n"); errorOpType(); } - else - { - if (SyntaxStack0[*ExprTypeSynPtr] == '(') - //error("decayArray(): cannot do arithmetic on a function\n"); - errorOpType(); - } } } +STATIC +void lvalueCheck(int ExprTypeSynPtr, int pos) +{ + if (ExprTypeSynPtr >= 0 && + (SyntaxStack0[ExprTypeSynPtr] == '[' || SyntaxStack0[ExprTypeSynPtr] == '(')) + { + // we can have arrays formed by dereference, e.g. + // char (*pac)[1]; // *pac is array of 1 char + // // ++*pac or (*pac)-- are not allowed + // and likewise functions, e.g. + // int (*pf)(int); // *pf is a function taking int and returning int + // // *pf = 0; is not allowed + // and that dereference shouldn't be confused for lvalue, + // hence explicitly checking for array and function types + //error("exprval(): lvalue expected\n"); + errorNotLvalue(); + } + // lvalue is a dereferenced address, check for a dereference + if (stack[pos][0] != tokUnaryStar) + //error("exprval(): lvalue expected\n"); + errorNotLvalue(); +} + STATIC void nonVoidTypeCheck(int ExprTypeSynPtr) { @@ -2741,21 +2981,60 @@ void scalarTypeCheck(int ExprTypeSynPtr) STATIC void numericTypeCheck(int ExprTypeSynPtr) { - if (ExprTypeSynPtr >= 0 && - (SyntaxStack0[ExprTypeSynPtr] == tokChar || - SyntaxStack0[ExprTypeSynPtr] == tokSChar || - SyntaxStack0[ExprTypeSynPtr] == tokUChar || + if (ExprTypeSynPtr >= 0) + switch (SyntaxStack0[ExprTypeSynPtr]) + { + case tokChar: + case tokSChar: + case tokUChar: #ifdef CAN_COMPILE_32BIT - SyntaxStack0[ExprTypeSynPtr] == tokShort || - SyntaxStack0[ExprTypeSynPtr] == tokUShort || + case tokShort: + case tokUShort: #endif - SyntaxStack0[ExprTypeSynPtr] == tokInt || - SyntaxStack0[ExprTypeSynPtr] == tokUnsigned)) - return; + case tokInt: + case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif + return; + } //error("numericTypeCheck(): unexpected operand type for operator '%s', numeric type expected\n", GetTokenName(tok)); errorOpType(); } +#ifndef NO_FP +STATIC +void nonFloatTypeCheck(int ExprTypeSynPtr) +{ + if (ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokFloat) + errorOpType(); +} +#endif + +STATIC +void anyIntTypeCheck(int ExprTypeSynPtr) +{ + // Check for any integer type + numericTypeCheck(ExprTypeSynPtr); +#ifndef NO_FP + nonFloatTypeCheck(ExprTypeSynPtr); +#endif +} + +#ifndef NO_FP +STATIC +int isFloat(int ExprTypeSynPtr) +{ + return ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokFloat; +} +#endif + +STATIC +int isUint(int ExprTypeSynPtr) +{ + return ExprTypeSynPtr >= 0 && SyntaxStack0[ExprTypeSynPtr] == tokUnsigned; +} + STATIC void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[2], int lidx, int ridx) { @@ -2763,17 +3042,42 @@ void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[ int c = 0; int lptr, rptr, lnum, rnum; - // convert functions to pointers to functions - if (exprTypeSynPtr >= 0 && SyntaxStack0[exprTypeSynPtr] == '(') - *ExprTypeSynPtr = exprTypeSynPtr = -exprTypeSynPtr; - if (TheOtherExprTypeSynPtr >= 0 && SyntaxStack0[TheOtherExprTypeSynPtr] == '(') - TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr; - + // (un)decay/convert functions to pointers to functions + // and to simplify matters convert all '*' pointers to negative type indices + if (exprTypeSynPtr >= 0) + { + switch (SyntaxStack0[exprTypeSynPtr]) + { + case '*': + exprTypeSynPtr++; + // fallthrough + case '(': + exprTypeSynPtr = -exprTypeSynPtr; + } + *ExprTypeSynPtr = exprTypeSynPtr; + } + if (TheOtherExprTypeSynPtr >= 0) + { + switch (SyntaxStack0[TheOtherExprTypeSynPtr]) + { + case '*': + TheOtherExprTypeSynPtr++; + // fallthrough + case '(': + TheOtherExprTypeSynPtr = -TheOtherExprTypeSynPtr; + } + } lptr = exprTypeSynPtr < 0; rptr = TheOtherExprTypeSynPtr < 0; lnum = !lptr && (SyntaxStack0[exprTypeSynPtr] == tokInt || +#ifndef NO_FP + SyntaxStack0[exprTypeSynPtr] == tokFloat || +#endif SyntaxStack0[exprTypeSynPtr] == tokUnsigned); rnum = !rptr && (SyntaxStack0[TheOtherExprTypeSynPtr] == tokInt || +#ifndef NO_FP + SyntaxStack0[TheOtherExprTypeSynPtr] == tokFloat || +#endif SyntaxStack0[TheOtherExprTypeSynPtr] == tokUnsigned); // both operands have arithmetic type @@ -2786,21 +3090,20 @@ void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[ !rptr && SyntaxStack0[TheOtherExprTypeSynPtr] == tokVoid) return; - // TBD??? check for exact 0? // one operand is a pointer and the other is NULL constant // ((void*)0 is also a valid null pointer constant), // the type of the expression is that of the pointer: if (lptr && - ((rnum && ConstExpr[1]) || + ((rnum && ConstExpr[1] && truncInt(stack[ridx][1]) == 0) || (rptr && SyntaxStack0[-TheOtherExprTypeSynPtr] == tokVoid && - stack[ridx][0] == tokUnaryPlus && // "(type*)constant" appears as "constant +(unary)" - (stack[ridx - 1][0] == tokNumInt || stack[ridx - 1][0] == tokNumUint)))) + (stack[ridx][0] == tokNumInt || stack[ridx][0] == tokNumUint) && + truncInt(stack[ridx][1]) == 0))) return; if (rptr && - ((lnum && ConstExpr[0]) || + ((lnum && ConstExpr[0] && truncInt(stack[lidx][1]) == 0) || (lptr && SyntaxStack0[-exprTypeSynPtr] == tokVoid && - stack[lidx][0] == tokUnaryPlus && // "(type*)constant" appears as "constant +(unary)" - (stack[lidx - 1][0] == tokNumInt || stack[lidx - 1][0] == tokNumUint)))) + (stack[lidx][0] == tokNumInt || stack[lidx][0] == tokNumUint) && + truncInt(stack[lidx][1]) == 0))) { *ExprTypeSynPtr = TheOtherExprTypeSynPtr; return; @@ -2811,7 +3114,7 @@ void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[ errorOpType(); // one operand is a pointer and the other is a pointer to void - // (except (void*)0, which is different from other pointers to void), + // (except (void*)0 (AKA NULL), which is different from other pointers to void), // the type of the expression is pointer to void: if (SyntaxStack0[-exprTypeSynPtr] == tokVoid) return; @@ -2851,6 +3154,9 @@ void compatCheck(int* ExprTypeSynPtr, int TheOtherExprTypeSynPtr, int ConstExpr[ case tokShort: case tokUShort: #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif case tokStructPtr: return; } @@ -2944,50 +3250,60 @@ int divCheckAndCalc(int tok, int* psl, int sr, int Unsigned, int ConstExpr[2]) STATIC void promoteType(int* ExprTypeSynPtr, int* TheOtherExprTypeSynPtr) { - // chars must be promoted to ints in expressions as the very first thing - if (*ExprTypeSynPtr >= 0 && - (SyntaxStack0[*ExprTypeSynPtr] == tokChar || + // Integer promotion to signed int or unsigned int from smaller types + // (all kinds of char and short). Promotion to unsigned int occurs + // only if the other operand (of a binary operator) is already an + // unsigned int. Effectively, this promotion to unsigned int performs + // usual arithmetic conversion for integers. + if (*ExprTypeSynPtr >= 0) + { + // chars must be promoted to ints in expressions as the very first thing + switch (SyntaxStack0[*ExprTypeSynPtr]) + { + case tokChar: #ifdef CAN_COMPILE_32BIT - SyntaxStack0[*ExprTypeSynPtr] == tokShort || - SyntaxStack0[*ExprTypeSynPtr] == tokUShort || + case tokShort: + case tokUShort: #endif - SyntaxStack0[*ExprTypeSynPtr] == tokSChar || - SyntaxStack0[*ExprTypeSynPtr] == tokUChar)) - *ExprTypeSynPtr = SymIntSynPtr; - - // ints must be converted to unsigned ints if they are used in binary - // operators whose other operand is unsigned int (except <<,>>,<<=,>>=) - if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokInt && - *TheOtherExprTypeSynPtr >= 0 && SyntaxStack0[*TheOtherExprTypeSynPtr] == tokUnsigned) - *ExprTypeSynPtr = SymUintSynPtr; + case tokSChar: + case tokUChar: + *ExprTypeSynPtr = SymIntSynPtr; + } + if (*TheOtherExprTypeSynPtr >= 0) + { + // ints must be converted to unsigned ints if they are used in binary + // operators whose other operand is unsigned int (except <<,>>,<<=,>>=) + if (SyntaxStack0[*ExprTypeSynPtr] == tokInt && + SyntaxStack0[*TheOtherExprTypeSynPtr] == tokUnsigned) + *ExprTypeSynPtr = SymUintSynPtr; + } + } } STATIC int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnExprTypeSynPtr, int* FirstParamSynPtr) { - int ptr = 0; - *MaxParams = *MinParams = 0; if (ExprTypeSynPtr < 0) { - ptr = 1; ExprTypeSynPtr = -ExprTypeSynPtr; } + else + { + while (SyntaxStack0[ExprTypeSynPtr] == tokIdent || SyntaxStack0[ExprTypeSynPtr] == tokLocalOfs) + ExprTypeSynPtr++; + if (SyntaxStack0[ExprTypeSynPtr] == '*') + ExprTypeSynPtr++; + } - while (SyntaxStack0[ExprTypeSynPtr] == tokIdent || SyntaxStack0[ExprTypeSynPtr] == tokLocalOfs) - ExprTypeSynPtr++; - - if (!(SyntaxStack0[ExprTypeSynPtr] == '(' || - (!ptr && SyntaxStack0[ExprTypeSynPtr] == '*' && SyntaxStack0[ExprTypeSynPtr + 1] == '('))) + if (SyntaxStack0[ExprTypeSynPtr] != '(') return 0; // DONE: return syntax pointer to the function's return type // Count params - while (SyntaxStack0[ExprTypeSynPtr] != '(') - ExprTypeSynPtr++; ExprTypeSynPtr++; if (FirstParamSynPtr) @@ -3052,9 +3368,13 @@ int GetFxnInfo(int ExprTypeSynPtr, int* MinParams, int* MaxParams, int* ReturnEx STATIC void simplifyConstExpr(int val, int isConst, int* ExprTypeSynPtr, int top, int bottom) { + // If non-const, nothing to do. + // If const and already a number behind the scenes, nothing to do + // (val must not differ from the number!). if (!isConst || stack[top][0] == tokNumInt || stack[top][0] == tokNumUint) return; + // Const, but not a number yet. Reduce to a number equal val. if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned) stack[top][0] = tokNumUint; else @@ -3123,6 +3443,15 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) *ExprTypeSynPtr = SymUintSynPtr; *ConstExpr = 1; break; +#ifndef NO_FP + case tokNumFloat: + // recode tokNumFloat to tokNumInt to minimize changes in the CGs + stack[*idx + 1][0] = tokNumInt; + // return the constant's type: float + *ExprTypeSynPtr = SymFloatSynPtr; + *ConstExpr = 1; + break; +#endif // Identifiers case tokIdent: @@ -3182,6 +3511,10 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // DONE: this declaration is actually a type cast if (!strncmp(IdentTable + SyntaxStack1[synPtr], "(something", sizeof "(something)" - 1 - 1)) { +#ifndef NO_FP + int fmask; + int ptrmask; +#endif int castSize; if (SyntaxStack0[++synPtr] == tokLocalOfs) // TBD!!! is this really needed??? @@ -3202,6 +3535,13 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) SyntaxStack0[synPtr] == tokStructPtr) errorOpType(); +#ifndef NO_FP + ptrmask = isAnyPtr(synPtr) * 2 + isAnyPtr(*ExprTypeSynPtr); + fmask = isFloat(synPtr) * 2 + isFloat(*ExprTypeSynPtr); + if (ptrmask && fmask) // pointers and floats don't mix + errorOpType(); +#endif + // will try to propagate constants through casts if (!*ConstExpr && (stack[oldIdxRight - (oldSpRight - sp)][0] == tokNumInt || @@ -3211,7 +3551,29 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) *ConstExpr = 1; } - castSize = GetDeclSize(synPtr, 1); + castSize = GetDeclSize(synPtr, 1); // 0 for cast to void + +#ifndef NO_FP + if (castSize && fmask == 1) + { + // cast from float to any int + int u = isUint(synPtr); + if (*ConstExpr) + { + s = u ? f2u(s) : f2i(s, castSize); + } + else + { + // insert a call to convert float to [unsigned] int + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNF2U : FXNF2I])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } +#endif // insertion of tokUChar, tokSChar and tokUnaryPlus transforms // lvalues (values formed by dereferences) into rvalues @@ -3233,6 +3595,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) #ifdef CAN_COMPILE_32BIT if (castSize && castSize != SizeOfWord) { + // cast not to void and not to word-sized type (int/unsigned/pointer/float) if (castSize == 2) { // cast to unsigned short @@ -3250,17 +3613,45 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) else // fallthrough #endif { - // cast to int/unsigned/pointer + // cast to void or word-sized type (int/unsigned/pointer/float) +#ifndef NO_FP + if (fmask == 2) + { + // cast from any int to float + int u = isUint(*ExprTypeSynPtr); + if (*ConstExpr) + { + s = u ? u2f(s) : i2f(s); + } + else + { + // insert a call to convert [unsigned] int to float + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } +#endif if (stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar) // hide the dereference stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUnaryPlus; - else - // nothing to hide, remove the cast - del(oldIdxRight + 1 - (oldSpRight - sp), 1); } break; } + if (*ConstExpr) + stack[oldIdxRight - (oldSpRight - sp)][1] = s; + + *ExprTypeSynPtr = synPtr; + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); + + if (!*ConstExpr && stack[oldIdxRight + 1 - (oldSpRight - sp)][0] == tokIdent) + // nothing to hide, remove the cast + del(oldIdxRight + 1 - (oldSpRight - sp), 1); + switch (SyntaxStack0[synPtr]) { case tokChar: @@ -3272,17 +3663,21 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif break; default: + // only numeric types can be const *ConstExpr = 0; break; } - *ExprTypeSynPtr = synPtr; - simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); break; } + // Finally, not __func__, not enum, not cast. + type = SymType(synPtr); if (type == SymLocalVar || type == SymLocalArr) @@ -3308,12 +3703,8 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // sizeof operator case tokSizeof: - s = exprval(idx, ExprTypeSynPtr, ConstExpr); - - if (*ExprTypeSynPtr >= 0) - s = GetDeclSize(*ExprTypeSynPtr, 0); - else - s = SizeOfWord; + exprval(idx, ExprTypeSynPtr, ConstExpr); + s = GetDeclSize(*ExprTypeSynPtr, 0); if (s == 0) error("sizeof of incomplete type\n"); @@ -3332,34 +3723,30 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) case tokUnaryAnd: exprval(idx, ExprTypeSynPtr, ConstExpr); - if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '[') + if (*ExprTypeSynPtr >= 0 && + (SyntaxStack0[*ExprTypeSynPtr] == '[' || SyntaxStack0[*ExprTypeSynPtr] == '(')) { // convert an array into a pointer to the array, - // remove the reference - *ExprTypeSynPtr = -*ExprTypeSynPtr; - del(oldIdxRight + 1 - (oldSpRight - sp), 1); - } - else if (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == '(') - { // convert a function into a pointer to the function, // remove the reference - *ExprTypeSynPtr = -*ExprTypeSynPtr; del(oldIdxRight + 1 - (oldSpRight - sp), 1); } else if (*ExprTypeSynPtr >= 0 && - oldIdxRight - (oldSpRight - sp) >= 0 && stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar) { // it's an lvalue (with implicit or explicit dereference), - // convert it into its address, - // collapse/remove the reference and the dereference - *ExprTypeSynPtr = -*ExprTypeSynPtr; + // convert it into its address by + // collapsing/removing the reference and the dereference del(oldIdxRight - (oldSpRight - sp), 2); } else //error("exprval(): lvalue expected after '&'\n"); errorNotLvalue(); + // we cannot insert another '*' into the type to make it a pointer + // to an array/function/etc, so make the index into the type negative + *ExprTypeSynPtr = -*ExprTypeSynPtr; + *ConstExpr = 0; break; @@ -3383,7 +3770,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) if (SyntaxStack0[*ExprTypeSynPtr] == '[' || SyntaxStack0[*ExprTypeSynPtr] == '(') del(oldIdxRight + 1 - (oldSpRight - sp), 1); - // else add dereference size in bytes + // else attach dereference size in bytes else stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1); } @@ -3392,13 +3779,11 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // type is an array, // transform it into the array's first element // (a subarray, if type is a multidimensional array) - while (SyntaxStack0[*ExprTypeSynPtr] != ']') - ++*ExprTypeSynPtr; - ++*ExprTypeSynPtr; + (*ExprTypeSynPtr) += 3; // remove the dereference if that element is an array if (SyntaxStack0[*ExprTypeSynPtr] == '[') del(oldIdxRight + 1 - (oldSpRight - sp), 1); - // else add dereference size in bytes + // else attach dereference size in bytes else stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = GetDeclSize(*ExprTypeSynPtr, 1); } @@ -3416,6 +3801,9 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // WRONG: DONE: replace postfix ++/-- with (+=1)-1/(-=1)+1 { int ptrmask; +#ifndef NO_FP + int fmask; +#endif int oldIdxLeft, oldSpLeft; int sl, sr; int incSize; @@ -3424,24 +3812,27 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) oldSpLeft = sp; sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); - if (tok == '+') - s = (int)((unsigned)sl + sr); - else - s = (int)((unsigned)sl - sr); - - scalarTypeCheck(RightExprTypeSynPtr); - scalarTypeCheck(*ExprTypeSynPtr); - // Decay arrays to pointers to their first elements + // and ensure that the pointers are suitable for pointer arithmetic + // (not pointers to functions, sizes of pointees are known and non-zero) decayArray(&RightExprTypeSynPtr, 1); decayArray(ExprTypeSynPtr, 1); - ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; + // Bar void and struct/union + scalarTypeCheck(RightExprTypeSynPtr); + scalarTypeCheck(*ExprTypeSynPtr); + + ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2; +#ifndef NO_FP + fmask = isFloat(RightExprTypeSynPtr) + isFloat(*ExprTypeSynPtr) * 2; + if (ptrmask && fmask) // pointers and floats don't mix + errorOpType(); +#endif // DONE: index/subscript scaling if (ptrmask == 1 && tok == '+') // pointer in right-hand expression { - incSize = GetDeclSize(-RightExprTypeSynPtr, 0); + incSize = GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0); if (constExpr[0]) // integer constant in left-hand expression { @@ -3475,7 +3866,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) } else if (ptrmask == 2) // pointer in left-hand expression { - incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0); if (constExpr[1]) // integer constant in right-hand expression { s = (int)((unsigned)sr * incSize); @@ -3507,9 +3898,9 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) } else if (ptrmask == 3 && tok == '-') // pointers in both expressions { - incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0); // TBD!!! "ptr1-ptr2": better pointer type compatibility test needed, like compatCheck()? - if (incSize != GetDeclSize(-RightExprTypeSynPtr, 0)) + if (incSize != GetDeclSize(derefAnyPtr(RightExprTypeSynPtr), 0)) //error("exprval(): incompatible pointers\n"); errorOpType(); if (incSize != 1) @@ -3527,6 +3918,88 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); *ConstExpr = constExpr[0] && constExpr[1]; + +#ifndef NO_FP + if (fmask) + { + if (fmask == 2) + { + int u = isUint(RightExprTypeSynPtr); + if (constExpr[1]) + { + // convert int constant to float + sr = u ? u2f(sr) : i2f(sr); + stack[oldIdxRight - (oldSpRight - sp)][1] = sr; + } + else + { + // insert a call to convert int to float + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = oldIdxLeft + 1 - (oldSpLeft - sp); + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + oldSpLeft += 4; + } + } + if (fmask == 1) + { + int u = isUint(*ExprTypeSynPtr); + if (constExpr[0]) + { + // convert int constant to float + sl = u ? u2f(sl) : i2f(sl); + stack[oldIdxLeft - (oldSpLeft - sp)][1] = sl; + } + else + { + // insert a call to convert int to float + int above = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } + if (*ConstExpr) + { + if (tok == '+') + s = fadd(sl, sr); + else + s = fsub(sl, sr); + } + else + { + // insert a call to add/subtract floats + int above = oldIdxRight + 1 - (oldSpRight - sp); + int mid = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + if (tok == '-') + { + // minuend must be the first argument, swap + swap(below, mid - below, above - mid); + mid = above - mid + below; + } + stack[above][0] = ')'; // replace '+'/'-' with function call + stack[above][1] = SizeOfWord * 2; + ins2(above, tokIdent, FindIdent(FpFxnName[(tok == '+') ? FXNFADD : FXNFSUB])); + ins(above, ','); + ins(mid, ','); + ins2(below, '(', SizeOfWord * 2); + } + *ExprTypeSynPtr = SymFloatSynPtr; + } + else +#endif + { + if (tok == '+') + s = (int)((unsigned)sl + sr); + else + s = (int)((unsigned)sl - sr); + } + simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); } break; @@ -3544,25 +4017,30 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) exprval(idx, ExprTypeSynPtr, ConstExpr); + lvalueCheck(*ExprTypeSynPtr, oldIdxRight - (oldSpRight - sp)); + + // if it's a pointer, ensure that it's suitable for pointer arithmetic + // (not pointer to function, pointee size is known and non-zero) + decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check + + // Bar void and struct/union scalarTypeCheck(*ExprTypeSynPtr); - decayArray(ExprTypeSynPtr, 1); - - // lvalue check for ++, -- - if (!(oldIdxRight - (oldSpRight - sp) >= 0 && - stack[oldIdxRight - (oldSpRight - sp)][0] == tokUnaryStar)) - //error("exprval(): lvalue expected for '++' or '--'\n"); - errorNotLvalue(); +#ifndef NO_FP + // TBD!!! support floats with these operators + if (isFloat(*ExprTypeSynPtr)) + error("Increment/decrement not supported with floats\n"); +#endif // "remove" the lvalue dereference as we don't need - // to read the value and forget its location. We need to - // keep the lvalue location. + // to read the value while forgetting its location. + // We need to keep the lvalue location. // Remember the operand size. opSize = stack[oldIdxRight - (oldSpRight - sp)][1]; del(oldIdxRight - (oldSpRight - sp), 1); - if (*ExprTypeSynPtr < 0) - incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + if (isAnyPtr(*ExprTypeSynPtr)) + incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0); if (incSize == 1) { @@ -3572,23 +4050,11 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) else { // replace ++/-- with "postfix" +=/-= incSize when incSize != 1 - if (inc) - { - if (post) - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokPostAdd; - else - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokAssignAdd; - } - else - { - if (post) - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokPostSub; - else - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokAssignSub; - } + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = + inc ? (post ? tokPostAdd : tokAssignAdd) : + (post ? tokPostSub : tokAssignSub); // store the operand size in the operator stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; - ins2(oldIdxRight + 1 - (oldSpRight - sp), tokNumInt, incSize); } @@ -3602,25 +4068,30 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) int oldIdxLeft, oldSpLeft; int opSize; int structs; - - exprval(idx, &RightExprTypeSynPtr, ConstExpr); +#ifndef NO_FP + int ptrmask; + int fmask; + int sr = +#endif + exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); oldIdxLeft = *idx; oldSpLeft = sp; - exprval(idx, ExprTypeSynPtr, ConstExpr); + exprval(idx, ExprTypeSynPtr, &constExpr[0]); + + lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp)); nonVoidTypeCheck(RightExprTypeSynPtr); nonVoidTypeCheck(*ExprTypeSynPtr); - decayArray(&RightExprTypeSynPtr, 0); - decayArray(ExprTypeSynPtr, 0); + structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 + + (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr); +#ifndef NO_FP + ptrmask = isAnyPtr(*ExprTypeSynPtr) * 2 + isAnyPtr(RightExprTypeSynPtr); + fmask = isFloat(*ExprTypeSynPtr) * 2 + isFloat(RightExprTypeSynPtr); + if (fmask && (structs | ptrmask)) // floats don't mix with pointers or structs/unions + errorOpType(); +#endif - if (!(oldIdxLeft - (oldSpLeft - sp) >= 0 && - stack[oldIdxLeft - (oldSpLeft - sp)][0] == tokUnaryStar)) - //error("exprval(): lvalue expected before '='\n"); - errorNotLvalue(); - - structs = (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr) + - (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2; if (structs) { int sz; @@ -3659,9 +4130,37 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) } else { +#ifndef NO_FP + if (fmask == 1 || fmask == 2) + { + int u = isUint((fmask == 1) ? *ExprTypeSynPtr : RightExprTypeSynPtr); + if (constExpr[1]) + { + // convert between float and [unsigned] int + if (fmask == 1) + sr = u ? f2u(sr) : f2i(sr, GetDeclSize(*ExprTypeSynPtr, 1)); + else + sr = u ? u2f(sr) : i2f(sr); + stack[oldIdxRight - (oldSpRight - sp)][1] = sr; + } + else + { + // insert a call to convert between float and [unsigned] int + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = oldIdxLeft + 1 - (oldSpLeft - sp); + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[(fmask == 1) ? (u ? FXNF2U : FXNF2I) : + (u ? FXNU2F : FXNI2F)])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + oldSpLeft += 4; + } + } +#endif // "remove" the lvalue dereference as we don't need - // to read the value and forget its location. We need to - // keep the lvalue location. + // to read the value while forgetting its location. + // We need to keep the lvalue location. + // Remember the operand size. opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1]; // store the operand size in the operator stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; @@ -3679,15 +4178,45 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) case tokUnaryPlus: case tokUnaryMinus: s = exprval(idx, ExprTypeSynPtr, ConstExpr); - scalarTypeCheck(*ExprTypeSynPtr); numericTypeCheck(*ExprTypeSynPtr); + promoteType(ExprTypeSynPtr, ExprTypeSynPtr); switch (tok) { - case '~': s = ~s; break; - case tokUnaryPlus: s = +s; break; - case tokUnaryMinus: s = (int)~(s - 1u); break; + case '~': +#ifndef NO_FP + nonFloatTypeCheck(*ExprTypeSynPtr); +#endif + s = ~s; + break; + case tokUnaryPlus: + break; + case tokUnaryMinus: +#ifndef NO_FP + if (isFloat(*ExprTypeSynPtr)) + { + if (*ConstExpr) + { + s = fneg(s); + } + else + { + // insert a call to float negate + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = *idx + 1; + stack[above][0] = ')'; // replace tokUnaryMinus with function call + stack[above][1] = SizeOfWord; + ins2(above, tokIdent, FindIdent(FpFxnName[FXNFNEG])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } + else +#endif + { + s = (int)~(s - 1u); + } + break; } - promoteType(ExprTypeSynPtr, ExprTypeSynPtr); simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); break; @@ -3701,98 +4230,184 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) case '^': case '|': { - // int oldIdxLeft, oldSpLeft; +#ifndef NO_FP + int fmask; + int oldIdxLeft, oldSpLeft; +#endif int sr, sl; int Unsigned; sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); - // oldIdxLeft = *idx; - // oldSpLeft = sp; +#ifndef NO_FP + oldIdxLeft = *idx; + oldSpLeft = sp; +#endif sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); - scalarTypeCheck(RightExprTypeSynPtr); - scalarTypeCheck(*ExprTypeSynPtr); - numericTypeCheck(RightExprTypeSynPtr); numericTypeCheck(*ExprTypeSynPtr); +#ifndef NO_FP + if (tok != '*' && tok != '/') + { + nonFloatTypeCheck(RightExprTypeSynPtr); + nonFloatTypeCheck(*ExprTypeSynPtr); + } +#endif *ConstExpr = constExpr[0] && constExpr[1]; Unsigned = SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned || SyntaxStack0[RightExprTypeSynPtr] == tokUnsigned; - switch (tok) +#ifndef NO_FP + fmask = isFloat(RightExprTypeSynPtr) + isFloat(*ExprTypeSynPtr) * 2; + + if (fmask) { - // DONE: check for division overflows - case '/': - case '%': - *ConstExpr &= divCheckAndCalc(tok, &sl, sr, Unsigned, constExpr); - - if (Unsigned) + if (fmask == 2) { - if (tok == '/') - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUDiv; + int u = isUint(RightExprTypeSynPtr); + if (constExpr[1]) + { + // convert int constant to float + sr = u ? u2f(sr) : i2f(sr); + stack[oldIdxRight - (oldSpRight - sp)][1] = sr; + } else - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUMod; + { + // insert a call to convert int to float + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = oldIdxLeft + 1 - (oldSpLeft - sp); + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + oldSpLeft += 4; + } } - break; - - case '*': - sl = (int)((unsigned)sl * sr); - break; - - case tokLShift: - case tokRShift: - if (constExpr[1]) + if (fmask == 1) { - if (SyntaxStack0[RightExprTypeSynPtr] != tokUnsigned) - sr = truncInt(sr); + int u = isUint(*ExprTypeSynPtr); + if (constExpr[0]) + { + // convert int constant to float + sl = u ? u2f(sl) : i2f(sl); + stack[oldIdxLeft - (oldSpLeft - sp)][1] = sl; + } else - sr = (int)truncUint(sr); - shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr); + { + // insert a call to convert int to float + int above = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } } if (*ConstExpr) { - if (tok == tokLShift) - { - // left shift is the same for signed and unsigned ints - sl = (int)((unsigned)sl << sr); - } + if (tok == '*') + s = fmul(sl, sr); else + s = fdiv(sl, sr); + } + else + { + // insert a call to multiply/divide floats + int above = oldIdxRight + 1 - (oldSpRight - sp); + int mid = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + if (tok == '/') { - if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned) + // dividend must be the first argument, swap + swap(below, mid - below, above - mid); + mid = above - mid + below; + } + stack[above][0] = ')'; // replace '*'/'/' with function call + stack[above][1] = SizeOfWord * 2; + ins2(above, tokIdent, FindIdent(FpFxnName[(tok == '*') ? FXNFMUL : FXNFDIV])); + ins(above, ','); + ins(mid, ','); + ins2(below, '(', SizeOfWord * 2); + } + *ExprTypeSynPtr = SymFloatSynPtr; + } + else +#endif + { + switch (tok) + { + // DONE: check for division overflows + case '/': + case '%': + *ConstExpr &= divCheckAndCalc(tok, &sl, sr, Unsigned, constExpr); + + if (Unsigned) + { + if (tok == '/') + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUDiv; + else + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokUMod; + } + break; + + case '*': + sl = (int)((unsigned)sl * sr); + break; + + case tokLShift: + case tokRShift: + if (constExpr[1]) + { + if (SyntaxStack0[RightExprTypeSynPtr] != tokUnsigned) + sr = truncInt(sr); + else + sr = (int)truncUint(sr); + shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr); + } + if (*ConstExpr) + { + if (tok == tokLShift) { - // right shift for unsigned ints - sl = (int)(truncUint(sl) >> sr); + // left shift is the same for signed and unsigned ints + sl = (int)((unsigned)sl << sr); } - else if (sr) + else { - // right shift for signed ints is arithmetic, sign-bit-preserving - // don't depend on the compiler's implementation, do it "manually" - sl = truncInt(sl); - sl = (int)((truncUint(sl) >> sr) | - ((sl < 0) * (~0u << (8 * SizeOfWord - sr)))); + if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned) + { + // right shift for unsigned ints + sl = (int)(truncUint(sl) >> sr); + } + else if (sr) + { + // right shift for signed ints is arithmetic, sign-bit-preserving + // don't depend on the compiler's implementation, do it "manually" + sl = truncInt(sl); + sl = (int)((truncUint(sl) >> sr) | + ((sl < 0) * (~0u << (8 * SizeOfWord - sr)))); + } } } + + if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned && tok == tokRShift) + stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokURShift; + + // ignore RightExprTypeSynPtr for the purpose of promotion/conversion of the result of <> + RightExprTypeSynPtr = SymIntSynPtr; + break; + + case '&': sl &= sr; break; + case '^': sl ^= sr; break; + case '|': sl |= sr; break; } - - if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned && tok == tokRShift) - stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = tokURShift; - - // ignore RightExprTypeSynPtr for the purpose of promotion/conversion of the result of <> - RightExprTypeSynPtr = SymIntSynPtr; - break; - - case '&': sl &= sr; break; - case '^': sl ^= sr; break; - case '|': sl |= sr; break; + s = sl; } - - s = sl; promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); } break; - // Relational binary operators + // Relational and equality binary operators // DONE: add (sub)tokens for unsigned >, >=, <, <= for pointers case '<': case '>': @@ -3802,75 +4417,179 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) case tokNEQ: { int ptrmask; +#ifndef NO_FP + int fmask; + int oldIdxLeft, oldSpLeft; +#endif int sr, sl; - int Unsigned; sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[1]); +#ifndef NO_FP + oldIdxLeft = *idx; + oldSpLeft = sp; +#endif sl = exprval(idx, ExprTypeSynPtr, &constExpr[0]); + // Bar void and struct/union scalarTypeCheck(RightExprTypeSynPtr); scalarTypeCheck(*ExprTypeSynPtr); - decayArray(&RightExprTypeSynPtr, 0); - decayArray(ExprTypeSynPtr, 0); - - ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; - - // Disallow >, <, >=, <= between a pointer and a number - if (ptrmask >= 1 && ptrmask <= 2 && - tok != tokEQ && tok != tokNEQ) - //error("exprval(): Invalid/unsupported combination of compared operands\n"); + ptrmask = isAnyPtr(RightExprTypeSynPtr) + isAnyPtr(*ExprTypeSynPtr) * 2; +#ifndef NO_FP + fmask = isFloat(RightExprTypeSynPtr) + isFloat(*ExprTypeSynPtr) * 2; + if (ptrmask && fmask) // pointers and floats don't mix errorOpType(); +#endif + + // TBD??? stricter type checks??? + if (tok != tokEQ && tok != tokNEQ) + { + // Disallow >, <, >=, <= between a pointer and a number + if (ptrmask == 1 || ptrmask == 2) + //error("exprval(): Invalid/unsupported combination of compared operands\n"); + errorOpType(); + // Disallow >, <, >=, <= with pointers to functions + if (((ptrmask & 1) && SyntaxStack0[derefAnyPtr(RightExprTypeSynPtr)] == '(') || + ((ptrmask & 2) && SyntaxStack0[derefAnyPtr(*ExprTypeSynPtr)] == '(')) + errorOpType(); + } + else + { + // Disallow == and != between a pointer and a number other than constant 0 (AKA NULL) + if ((ptrmask == 1 && !(constExpr[0] && !truncInt(sl))) || + (ptrmask == 2 && !(constExpr[1] && !truncInt(sr)))) + errorOpType(); + } *ConstExpr = constExpr[0] && constExpr[1]; - Unsigned = !ptrmask && - (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned || SyntaxStack0[RightExprTypeSynPtr] == tokUnsigned); - - if (*ConstExpr) +#ifndef NO_FP + if (fmask) { - if (!Unsigned) + if (fmask == 2) { - sl = truncInt(sl); - sr = truncInt(sr); + int u = isUint(RightExprTypeSynPtr); + if (constExpr[1]) + { + // convert int constant to float + sr = u ? u2f(sr) : i2f(sr); + stack[oldIdxRight - (oldSpRight - sp)][1] = sr; + } + else + { + // insert a call to convert int to float + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = oldIdxLeft + 1 - (oldSpLeft - sp); + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + oldSpLeft += 4; + } + } + if (fmask == 1) + { + int u = isUint(*ExprTypeSynPtr); + if (constExpr[0]) + { + // convert int constant to float + sl = u ? u2f(sl) : i2f(sl); + stack[oldIdxLeft - (oldSpLeft - sp)][1] = sl; + } + else + { + // insert a call to convert int to float + int above = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } + if (*ConstExpr) + { + sl = fcmp(sl, sr, (tok == tokGEQ || tok == '>') ? -1 : +1); switch (tok) { - case '<': sl = sl < sr; break; - case '>': sl = sl > sr; break; - case tokLEQ: sl = sl <= sr; break; - case tokGEQ: sl = sl >= sr; break; - case tokEQ: sl = sl == sr; break; - case tokNEQ: sl = sl != sr; break; + case '<': sl = sl < 0; break; + case '>': sl = sl > 0; break; + case tokLEQ: sl = sl <= 0; break; + case tokGEQ: sl = sl >= 0; break; + case tokEQ: sl = sl == 0; break; + case tokNEQ: sl = sl != 0; break; } } else { - sl = (int)truncUint(sl); - sr = (int)truncUint(sr); - switch (tok) - { - case '<': sl = (unsigned)sl < (unsigned)sr; break; - case '>': sl = (unsigned)sl > (unsigned)sr; break; - case tokLEQ: sl = (unsigned)sl <= (unsigned)sr; break; - case tokGEQ: sl = (unsigned)sl >= (unsigned)sr; break; - case tokEQ: sl = sl == sr; break; - case tokNEQ: sl = sl != sr; break; - } + // insert a call to compare floats + int above = oldIdxRight + 1 - (oldSpRight - sp); + int mid = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + // left operand must be the first argument, swap + swap(below, mid - below, above - mid); + mid = above - mid + below; + // we'll compare the returned value against 0: + // -1 if left < right + // 0 if left == right + // +1 if left > right + ins2(above, tokNumInt, 0); + ins2(above, ')', SizeOfWord * 2); + ins2(above, tokIdent, FindIdent(FpFxnName[(tok == tokGEQ || tok == '>') ? FXNFCMPG : FXNFCMPL])); + ins(above, ','); + ins(mid, ','); + ins2(below, '(', SizeOfWord * 2); } } - - if (ptrmask || Unsigned) + else +#endif { - // Pointer comparison should be unsigned - int t = tok; - switch (tok) + int Unsigned = isUint(*ExprTypeSynPtr) || isUint(RightExprTypeSynPtr); + + if (*ConstExpr) { - case '<': t = tokULess; break; - case '>': t = tokUGreater; break; - case tokLEQ: t = tokULEQ; break; - case tokGEQ: t = tokUGEQ; break; + if (!Unsigned) + { + sl = truncInt(sl); + sr = truncInt(sr); + switch (tok) + { + case '<': sl = sl < sr; break; + case '>': sl = sl > sr; break; + case tokLEQ: sl = sl <= sr; break; + case tokGEQ: sl = sl >= sr; break; + case tokEQ: sl = sl == sr; break; + case tokNEQ: sl = sl != sr; break; + } + } + else + { + sl = (int)truncUint(sl); + sr = (int)truncUint(sr); + switch (tok) + { + case '<': sl = (unsigned)sl < (unsigned)sr; break; + case '>': sl = (unsigned)sl > (unsigned)sr; break; + case tokLEQ: sl = (unsigned)sl <= (unsigned)sr; break; + case tokGEQ: sl = (unsigned)sl >= (unsigned)sr; break; + case tokEQ: sl = sl == sr; break; + case tokNEQ: sl = sl != sr; break; + } + } } - if (t != tok) + + if (ptrmask || Unsigned) + { + // Pointer comparison should be unsigned + int t = tok; + switch (tok) + { + case '<': t = tokULess; break; + case '>': t = tokUGreater; break; + case tokLEQ: t = tokULEQ; break; + case tokGEQ: t = tokUGEQ; break; + } stack[oldIdxRight + 1 - (oldSpRight - sp)][0] = t; + } } s = sl; @@ -3882,9 +4601,36 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // implicit pseudo-conversion to _Bool of operands of && and || case tok_Bool: s = exprval(idx, ExprTypeSynPtr, ConstExpr); - s = truncInt(s) != 0; + // Bar void and struct/union scalarTypeCheck(*ExprTypeSynPtr); - decayArray(ExprTypeSynPtr, 0); +#ifndef NO_FP + if (isFloat(*ExprTypeSynPtr)) + { + if (*ConstExpr) + { + s = fcmp(s, i2f(0), -1) != 0; + } + else + { + // insert a call to compare the float with 0.0 + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = *idx + 1; + // the returned value will be one of -1,0,+1, we need its least significant bit + stack[above][0] = '&'; + ins2(above, tokNumInt, 1); + ins2(above, ')', SizeOfWord * 2); + ins2(above, tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + ins(above, ','); + ins(below, ','); + ins2(below, tokNumInt, i2f(0)); + ins2(below, '(', SizeOfWord * 2); + } + } + else +#endif + { + s = truncInt(s) != 0; + } *ExprTypeSynPtr = SymIntSynPtr; simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); break; @@ -3984,8 +4730,8 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) int tmpSynPtr, c; int minParams, maxParams; int firstParamSynPtr; -#ifndef NO_STRUCT_BY_VAL int oldIdx, oldSp; +#ifndef NO_STRUCT_BY_VAL unsigned structSize = 0; int retStruct = 0; int retOfs = 0; @@ -4022,28 +4768,100 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) c = 0; while (stack[*idx][0] != '(') { +#ifndef NO_FP + int fmask; +#endif + int ptrmask; #ifndef NO_STRUCT_BY_VAL int gotStructs; #endif + // add a comma after the first (last to be pushed) argument, // so all arguments can be pushed whenever a comma is encountered if (!c) ins(*idx + 1, ','); -#ifndef NO_STRUCT_BY_VAL oldIdx = *idx; oldSp = sp; -#endif + (void)oldIdx; + (void)oldSp; + exprval(idx, &tmpSynPtr, ConstExpr); //error("exprval(): function arguments cannot be of type 'void'\n"); -#ifdef NO_STRUCT_BY_VAL - scalarTypeCheck(tmpSynPtr); -#else - nonVoidTypeCheck(tmpSynPtr); + if (c >= maxParams) + error("Too many function arguments\n"); + // Find the type of the formal parameter in the function declaration + if (c < minParams) + { + int t; + while ((t = SyntaxStack0[firstParamSynPtr]) != tokIdent) + { + if (t == '(') + { + // skip parameters in parameters + int c = 1; + while (c) + { + t = SyntaxStack0[++firstParamSynPtr]; + c += (t == '(') - (t == ')'); + } + } + firstParamSynPtr++; + } + firstParamSynPtr++; + } + else + { + firstParamSynPtr = SymVoidSynPtr; + } + + ptrmask = isAnyPtr(firstParamSynPtr) * 2 + isAnyPtr(tmpSynPtr); + (void)ptrmask; +#ifndef NO_FP + fmask = isFloat(firstParamSynPtr) * 2 + isFloat(tmpSynPtr); +#endif +#ifndef NO_STRUCT_BY_VAL + gotStructs = (SyntaxStack0[firstParamSynPtr] == tokStructPtr) * 2 + + (tmpSynPtr >= 0 && SyntaxStack0[tmpSynPtr] == tokStructPtr); +#endif + +#ifndef NO_STRUCT_BY_VAL + // Bar void + nonVoidTypeCheck(tmpSynPtr); +#else + // Bar void and struct/union + scalarTypeCheck(tmpSynPtr); +#endif + // if there's a formal parameter for this argument, check the types + if (c < minParams) + { +#ifndef NO_FP + // floats don't mix with pointers + if (fmask && ptrmask) + errorOpType(); +#endif +#ifndef NO_STRUCT_BY_VAL + // Structures must be of the same type + if (gotStructs && + (gotStructs != 3 || SyntaxStack1[tmpSynPtr] != SyntaxStack1[firstParamSynPtr])) + errorOpType(); +#endif +#ifndef NO_EXTRA_WARNS + // Issue a warning if the argument has to be a pointer but isn't and vice versa. + // TBD??? Compare pointer types deeply as in compatCheck()??? + // TBD??? Issue a similar warning for return values and initializers??? + if (ptrmask == 1 || + (ptrmask == 2 && + // Make an exception for integer constants equal to 0, treat them as NULL pointers + !(*ConstExpr && !truncInt(stack[*idx + 1][1])))) + warning("Expected %spointer in argument %d\n", (ptrmask == 2) ? "" : "non-", c + 1); +#endif + } + +#ifndef NO_STRUCT_BY_VAL // If the argument is a structure, push it by calling a dedicated function - gotStructs = tmpSynPtr >= 0 && SyntaxStack0[tmpSynPtr] == tokStructPtr; if (gotStructs) { unsigned sz = GetDeclSize(tmpSynPtr, 0); @@ -4088,78 +4906,36 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) } #endif - if (++c > maxParams) - error("Too many function arguments\n"); - -#ifndef NO_STRUCT_BY_VAL -#ifndef CHECK_FXN_ARGS -#define CHECK_FXN_ARGS -#endif -#endif - -#ifndef NO_EXTRA_WARNS -#ifndef CHECK_FXN_ARGS -#define CHECK_FXN_ARGS -#endif -#endif - -#ifdef CHECK_FXN_ARGS - // Issue a warning if the argument has to be a pointer but isn't and vice versa. - // DONE: struct type compat checks - // TBD??? Compare pointer types deeply as in compatCheck()??? - // TBD??? Issue a similar warning for return values and initializers??? - if (c <= minParams) +#ifndef NO_FP + // if there's a formal parameter for this argument, we may need to convert from/to float + if (c < minParams && (fmask == 1 || fmask == 2)) { - int t; -#ifndef NO_EXTRA_WARNS - int gotPtr = tmpSynPtr < 0; - int needPtr; - if (!gotPtr) + int u = isUint((fmask == 1) ? firstParamSynPtr : tmpSynPtr); + if (*ConstExpr) { - t = SyntaxStack0[tmpSynPtr]; - gotPtr = (t == '*') | (t == '[') | (t == '('); // arrays and functions decay to pointers + int val = stack[*idx + 1][1]; + // convert between float and [unsigned] int + if (fmask == 1) + val = u ? f2u(val) : f2i(val, GetDeclSize(firstParamSynPtr, 1)); + else + val = u ? u2f(val) : i2f(val); + stack[*idx + 1][1] = val; } -#endif - // Find the type of the formal parameter in the function declaration - while ((t = SyntaxStack0[firstParamSynPtr]) != tokIdent) + else { - if (t == '(') - { - // skip parameters in parameters - int c = 1; - while (c) - { - t = SyntaxStack0[++firstParamSynPtr]; - c += (t == '(') - (t == ')'); - } - } - firstParamSynPtr++; + // insert a call to convert between float and [unsigned] int + int above = oldIdx + 1 - (oldSp - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[(fmask == 1) ? (u ? FXNF2U : FXNF2I) : + (u ? FXNU2F : FXNI2F)])); + ins(above, ','); + ins2(below, '(', SizeOfWord); } - firstParamSynPtr++; -#ifndef NO_STRUCT_BY_VAL - gotStructs += (SyntaxStack0[firstParamSynPtr] == tokStructPtr) * 2; - if (gotStructs) - { - // Structures must be of the same type - if (gotStructs != 3 || - SyntaxStack1[tmpSynPtr] != SyntaxStack1[firstParamSynPtr]) - errorOpType(); - } -#endif -#ifndef NO_EXTRA_WARNS - needPtr = SyntaxStack0[firstParamSynPtr] == '*'; - if (needPtr != gotPtr && - // Make an exception for integer constants equal to 0, treat them as NULL pointers - !( - needPtr && - *ConstExpr && - !stack[*idx + 1][1] - ) - ) - warning("Expected %spointer in argument %d\n", needPtr ? "" : "non-", c); -#endif } -#endif // CHECK_FXN_ARGS +#endif + + c++; if (stack[*idx][0] == ',') --*idx; @@ -4261,29 +5037,45 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) oldSpLeft = sp; exprval(idx, ExprTypeSynPtr, &constExpr[0]); + lvalueCheck(*ExprTypeSynPtr, oldIdxLeft - (oldSpLeft - sp)); + + // if it's a pointer, ensure that it's suitable for pointer arithmetic + // (not pointer to function, pointee size is known and non-zero) + decayArray(ExprTypeSynPtr, 1); // no actual decay here, just a type check + + // Bar void and struct/union scalarTypeCheck(RightExprTypeSynPtr); scalarTypeCheck(*ExprTypeSynPtr); - decayArray(&RightExprTypeSynPtr, 1); - decayArray(ExprTypeSynPtr, 1); - - if (!(oldIdxLeft - (oldSpLeft - sp) >= 0 && - stack[oldIdxLeft - (oldSpLeft - sp)][0] == tokUnaryStar)) - //error("exprval(): lvalue expected before %s\n", GetTokenName(tok)); - errorNotLvalue(); +#ifndef NO_FP + // TBD!!! tokAssignMul, tokAssignDiv, tokAssignAdd, tokAssignSub with floats + if (isFloat(RightExprTypeSynPtr) || isFloat(*ExprTypeSynPtr)) + { + switch (tok) + { + case tokAssignMul: + case tokAssignDiv: + case tokAssignAdd: + case tokAssignSub: + error("Compound assignment not supported with floats\n"); + default: + errorOpType(); + } + } +#endif // "remove" the lvalue dereference as we don't need - // to read the value and forget its location. We need to - // keep the lvalue location. + // to read the value while forgetting its location. + // We need to keep the lvalue location. + // Remember the operand size. opSize = stack[oldIdxLeft - (oldSpLeft - sp)][1]; // store the operand size in the operator stack[oldIdxRight + 1 - (oldSpRight - sp)][1] = opSize; del(oldIdxLeft - (oldSpLeft - sp), 1); - ptrmask = (RightExprTypeSynPtr < 0) + (*ExprTypeSynPtr < 0) * 2; + ptrmask = isAnyPtr(*ExprTypeSynPtr) * 2 + isAnyPtr(RightExprTypeSynPtr); - Unsigned = !ptrmask && - (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned || SyntaxStack0[RightExprTypeSynPtr] == tokUnsigned); + Unsigned = isUint(*ExprTypeSynPtr) * 2 + isUint(RightExprTypeSynPtr); if (tok != tokAssignAdd && tok != tokAssignSub) { @@ -4303,10 +5095,10 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) { if (constExpr[1]) { - if (SyntaxStack0[RightExprTypeSynPtr] != tokUnsigned) - sr = truncInt(sr); - else + if (Unsigned & 1) sr = (int)truncUint(sr); + else + sr = truncInt(sr); shiftCountCheck(&sr, oldIdxRight - (oldSpRight - sp), RightExprTypeSynPtr); } } @@ -4324,7 +5116,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // TBD??? replace +=/-= with prefix ++/-- if incSize == 1 if (ptrmask == 2) // left-hand expression { - incSize = GetDeclSize(-*ExprTypeSynPtr, 0); + incSize = GetDeclSize(derefAnyPtr(*ExprTypeSynPtr), 0); if (constExpr[1]) { int t = (int)(stack[oldIdxRight - (oldSpRight - sp)][1] * (unsigned)incSize); @@ -4344,7 +5136,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) case tokAssignDiv: t = tokAssignUDiv; break; case tokAssignMod: t = tokAssignUMod; break; case tokAssignRSh: - if (SyntaxStack0[*ExprTypeSynPtr] == tokUnsigned) + if (Unsigned & 2) t = tokAssignURSh; break; } @@ -4363,35 +5155,86 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) int condTypeSynPtr; int sc = (LabelCnt += 2) - 2; int structs; +#ifndef NO_FP + int ptrmask; + int fmask; +#endif // "exprL ? exprMID : exprR" appears on the stack as // "exprL exprR exprMID ?" + // label at the end of ?: stack[*idx + 1][0] = tokLogAnd; // piggyback on && for CG (ugly, but simple) stack[*idx + 1][1] = sc + 1; + smid = exprval(idx, ExprTypeSynPtr, &constExpr[1]); - ins2(*idx + 1, tokLogAnd, sc); // piggyback on && for CG (ugly, but simple) - - ins2(*idx + 1, tokGoto, sc + 1); // jump to end of ?: oldIdxLeft = *idx; oldSpLeft = sp; sr = exprval(idx, &RightExprTypeSynPtr, &constExpr[2]); - ins2(*idx + 1, tokShortCirc, -sc); // jump to mid if left is non-zero - sl = exprval(idx, &condTypeSynPtr, &constExpr[0]); - - scalarTypeCheck(condTypeSynPtr); - decayArray(&RightExprTypeSynPtr, 0); decayArray(ExprTypeSynPtr, 0); promoteType(&RightExprTypeSynPtr, ExprTypeSynPtr); promoteType(ExprTypeSynPtr, &RightExprTypeSynPtr); + structs = (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2 + + (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr); +#ifndef NO_FP + ptrmask = isAnyPtr(*ExprTypeSynPtr) * 2 + isAnyPtr(RightExprTypeSynPtr); + fmask = isFloat(*ExprTypeSynPtr) * 2 + isFloat(RightExprTypeSynPtr); + if (fmask && (structs | ptrmask)) // floats don't mix with pointers or structs/unions + errorOpType(); + + if (fmask) + { + if (fmask == 1) + { + int u = isUint(*ExprTypeSynPtr); + if (constExpr[1]) + { + // convert int constant to float + smid = u ? u2f(smid) : i2f(smid); + stack[oldIdxRight - (oldSpRight - sp)][1] = smid; + } + else + { + // insert a call to convert int to float + int above = oldIdxRight + 1 - (oldSpRight - sp); + int below = oldIdxLeft + 1 - (oldSpLeft - sp); + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + oldSpLeft += 4; + } + } + if (fmask == 2) + { + int u = isUint(RightExprTypeSynPtr); + if (constExpr[2]) + { + // convert int constant to float + sr = u ? u2f(sr) : i2f(sr); + stack[oldIdxLeft - (oldSpLeft - sp)][1] = sr; + } + else + { + // insert a call to convert int to float + int above = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + ins2(above, ')', SizeOfWord); + ins2(above, tokIdent, FindIdent(FpFxnName[u ? FXNU2F : FXNI2F])); + ins(above, ','); + ins2(below, '(', SizeOfWord); + } + } + *ExprTypeSynPtr = SymFloatSynPtr; + } +#endif + // TBD??? move struct/union-related checks into compatChecks() - structs = (RightExprTypeSynPtr >= 0 && SyntaxStack0[RightExprTypeSynPtr] == tokStructPtr) + - (*ExprTypeSynPtr >= 0 && SyntaxStack0[*ExprTypeSynPtr] == tokStructPtr) * 2; if (structs) { if (structs != 3 || @@ -4407,6 +5250,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) del(oldIdxLeft - (oldSpLeft - sp), 1); // delete '*' del(oldIdxRight - (oldSpRight - sp), 1); // delete '*' ins2(oldIdxRight + 2 - (oldSpRight - sp), tokUnaryStar, 0); // use 0 deref size to drop meaningless dereferences + oldSpRight--; } else { @@ -4417,21 +5261,57 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) oldIdxLeft - (oldSpLeft - sp)); } + // label at the start of exprMID + ins2(oldIdxLeft + 1 - (oldSpLeft - sp), tokLogAnd, sc); // piggyback on && for CG (ugly, but simple) + // jump from the end of exprR over exprMID to the end of ?: + ins2(oldIdxLeft - (oldSpLeft - sp), tokGoto, sc + 1); + // jump to exprMID if exprL is non-zero + ins2(*idx + 1, tokShortCirc, -sc); + + oldIdxLeft = *idx; + oldSpLeft = sp; + sl = exprval(idx, &condTypeSynPtr, &constExpr[0]); + + // Bar void and struct/union + scalarTypeCheck(condTypeSynPtr); + +#ifndef NO_FP + if (isFloat(condTypeSynPtr)) + { + // insert a call to compare the float with 0.0 + int above = oldIdxLeft + 1 - (oldSpLeft - sp); + int below = *idx + 1; + // the returned value will be one of -1,0,+1, that is, 0 if 0, +/-1 otherwise, + // IOW, suitable for conditional jump on zero/non-zero + ins2(above, ')', SizeOfWord * 2); + ins2(above, tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + ins(above, ','); + ins(below, ','); + ins2(below, tokNumInt, i2f(0)); + ins2(below, '(', SizeOfWord * 2); + } +#endif + *ConstExpr = s = 0; if (constExpr[0]) { - if (truncUint(sl)) + if ( +#ifndef NO_FP + isFloat(condTypeSynPtr) ? + fcmp(sl, i2f(0), -1) != 0 : +#endif + (truncUint(sl) != 0)) { if (constExpr[1]) *ConstExpr = 1, s = smid; - // TBD??? else can drop LHS and RHS expressions + // TBD??? else can drop exprL and exprR subexpressions } else { if (constExpr[2]) *ConstExpr = 1, s = sr; - // TBD??? else can drop LHS and MID expressions + // TBD??? else can drop exprL and exprMID subexpressions } } simplifyConstExpr(s, *ConstExpr, ExprTypeSynPtr, oldIdxRight + 1 - (oldSpRight - sp), *idx + 1); @@ -4441,7 +5321,7 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) // Postfix indirect structure/union member selection operator case tokArrow: { - int member, i, j = 0, c = 1, ofs = 0; + int member, i = 0, j = 0, c = 1, ofs = 0; stack[*idx + 1][0] = '+'; // replace -> with + member = stack[*idx][1]; // keep the member name, it will be replaced with member offset @@ -4450,13 +5330,11 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) --*idx; exprval(idx, ExprTypeSynPtr, ConstExpr); - decayArray(ExprTypeSynPtr, 0); - - if (*ExprTypeSynPtr >= 0 || - SyntaxStack0[-*ExprTypeSynPtr] != tokStructPtr) + if (!isAnyPtr(*ExprTypeSynPtr) || + SyntaxStack0[i = derefAnyPtr(*ExprTypeSynPtr)] != tokStructPtr) error("Pointer to or structure or union expected\n"); - i = SyntaxStack1[-*ExprTypeSynPtr]; + i = SyntaxStack1[i]; if (i + 2 > SyntaxStackCnt || (SyntaxStack0[i] != tokStruct && SyntaxStack0[i] != tokUnion) || SyntaxStack0[i + 1] != tokTag) @@ -4484,6 +5362,8 @@ int exprval(int* idx, int* ExprTypeSynPtr, int* ConstExpr) error("Undefined structure or union member '%s'\n", IdentTable + member); j += 2; + // we cannot insert another '*' into the type to make it a pointer, + // so make the index into the type negative *ExprTypeSynPtr = -j; // type: pointer to member's type stack[oldIdxRight - (oldSpRight - sp)][1] = ofs; // member offset within structure/union @@ -4575,6 +5455,11 @@ int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* case tokNumUint: printf2("%uu", truncUint(stack[i][1])); break; +#ifndef NO_FP + case tokNumFloat: + printf2("%df", truncInt(stack[i][1])); + break; +#endif case tokIdent: { char* p = IdentTable + stack[i][1]; @@ -4662,6 +5547,11 @@ int ParseExpr(int tok, int* GotUnary, int* ExprTypeSynPtr, int* ConstExpr, int* case tokInt: printf2("Expression value: %d\n", truncInt(*ConstVal)); break; +#ifndef NO_FP + case tokFloat: + printf2("Expression value: %df\n", truncInt(*ConstVal)); + break; +#endif default: case tokUnsigned: printf2("Expression value: %uu\n", truncUint(*ConstVal)); @@ -5011,10 +5901,21 @@ void errorLongExpr(void) error("Expression too long\n"); } +#ifndef NO_FP +STATIC +void warnFloat2Int(void) +{ + warning("Float constant non-convertible to integer\n"); +} +#endif + int tsd[] = { tokVoid, tokChar, tokInt, tokSigned, tokUnsigned, tokShort, +#ifndef NO_FP + tokFloat, tokDouble, +#endif tokStruct, tokUnion, }; @@ -5245,8 +6146,8 @@ int GetDeclSize(int SyntaxPtr, int SizeForDeref) unsigned size = 1; int arr = 0; - if (SyntaxPtr < 0) - errorInternal(10); + if (SyntaxPtr < 0) // pointer? + return SizeOfWord; for (i = SyntaxPtr; i < SyntaxStackCnt; i++) { @@ -5280,6 +6181,9 @@ int GetDeclSize(int SyntaxPtr, int SizeForDeref) #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif case '*': case '(': // size of fxn = size of ptr for now if (size * SizeOfWord / SizeOfWord != size) @@ -5337,8 +6241,8 @@ int GetDeclAlignment(int SyntaxPtr) { int i; - if (SyntaxPtr < 0) - errorInternal(14); + if (SyntaxPtr < 0) // pointer? + return SizeOfWord; for (i = SyntaxPtr; i < SyntaxStackCnt; i++) { @@ -5359,6 +6263,9 @@ int GetDeclAlignment(int SyntaxPtr) #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif case '*': case '(': return SizeOfWord; @@ -5519,6 +6426,9 @@ void DumpDecl(int SyntaxPtr, int IsParam) #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif case tokEllipsis: printf2("%s\n", GetTokenName(tok)); break; @@ -5587,6 +6497,7 @@ int ParseArrayDimension(int AllowEmptyDimension) exprVal = truncInt(exprVal); promoteType(&synPtr, &synPtr); + anyIntTypeCheck(synPtr); if ((SyntaxStack0[synPtr] == tokInt && exprVal < 1) || (SyntaxStack0[synPtr] == tokUnsigned && exprValU < 1)) error("Array dimension less than 1\n"); @@ -5615,6 +6526,12 @@ int ParseBase(int tok, int base[2]) switch (tok) { +#ifndef NO_FP + case tokDouble: // double is an alias for float + tok = tokFloat; + // fallthrough + case tokFloat: +#endif case tokVoid: *base = tok; tok = GetToken(); @@ -5790,6 +6707,7 @@ lcont: if (!gotUnary) errorUnexpectedToken(tok); + anyIntTypeCheck(synPtr); // TBD!!! check that the value is in the range of signed int if (!constExpr) errorNotConst(); } @@ -6118,6 +7036,9 @@ void PushBase(int base[2]) case tokShort: case tokUShort: #endif case tokInt: case tokUnsigned: +#ifndef NO_FP + case tokFloat: +#endif case tokStructPtr: copying = 0; } @@ -6194,6 +7115,10 @@ int InitScalar(int synPtr, int tok) int undoIdents = IdentTableLen; int ttop; int braces = 0; +#ifndef NO_FP + int ptrmask; + int fmask; +#endif // Initializers for scalars can be optionally enclosed in braces if (tok == '{') @@ -6214,14 +7139,34 @@ int InitScalar(int synPtr, int tok) tok = GetToken(); } + // Bar void and struct/union scalarTypeCheck(synPtr2); +#ifndef NO_FP + ptrmask = isAnyPtr(synPtr) * 2 + isAnyPtr(synPtr2); + fmask = isFloat(synPtr) * 2 + isFloat(synPtr2); + if (ptrmask && fmask) // pointers and floats don't mix + errorOpType(); +#endif + ttop = stack[sp - 1][0]; if (ttop == tokNumInt || ttop == tokNumUint) { + int val = stack[sp - 1][1]; +#ifndef NO_FP + if (fmask == 1 || fmask == 2) + { + int u = isUint((fmask == 1) ? synPtr : synPtr2); + // convert between float and [unsigned] int + if (fmask == 1) + val = u ? f2u(val) : f2i(val, GetDeclSize(synPtr, 1)); + else + val = u ? u2f(val) : i2f(val); + } +#endif // TBD??? truncate values for types smaller than int (e.g. char and short), - // so they are always in range? - GenIntData(elementSz, stack[0][1]); + // so they are always in range for the assembler? + GenIntData(elementSz, val); } else if (elementSz == (unsigned)SizeOfWord) { @@ -6472,6 +7417,8 @@ int ParseDecl(int tok, unsigned structInfo[4], int cast, int label) int Static = tok == tokStatic; #ifndef NO_TYPEDEF_ENUM int typeDef = tok == tokTypedef; +#else + (void)label; #endif if (external | @@ -7359,8 +8306,6 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) else if (tok == tokReturn) { // DONE: functions returning void vs non-void - // TBD??? functions returning void should be able to return void - // return values from other functions returning void int retVoid = CurFxnReturnExprTypeSynPtr >= 0 && SyntaxStack0[CurFxnReturnExprTypeSynPtr] == tokVoid; #ifndef NO_ANNOTATIONS @@ -7385,15 +8330,31 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) if (gotUnary) //error("ParseStatement(): cannot return a value of type 'void'\n"); #ifdef NO_STRUCT_BY_VAL + // Bar void and struct/union scalarTypeCheck(synPtr); #else + // Bar void nonVoidTypeCheck(synPtr); #endif } if (gotUnary) { +#ifndef NO_FP + int ptrmask; + int fmask; +#endif #ifndef NO_STRUCT_BY_VAL - int structs = (synPtr >= 0 && SyntaxStack0[synPtr] == tokStructPtr) + + int structs; +#endif + decayArray(&synPtr, 0); +#ifndef NO_FP + ptrmask = isAnyPtr(CurFxnReturnExprTypeSynPtr) * 2 + isAnyPtr(synPtr); + fmask = isFloat(CurFxnReturnExprTypeSynPtr) * 2 + isFloat(synPtr); + if (fmask && ptrmask) // floats don't mix with pointers + errorOpType(); +#endif +#ifndef NO_STRUCT_BY_VAL + structs = (synPtr >= 0 && SyntaxStack0[synPtr] == tokStructPtr) + (CurFxnReturnExprTypeSynPtr >= 0 && SyntaxStack0[CurFxnReturnExprTypeSynPtr] == tokStructPtr) * 2; if (structs) @@ -7427,32 +8388,82 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) else // fallthrough #endif { + int castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1); +#ifndef NO_FP + if (fmask == 1 || fmask == 2) + { + int u = isUint((fmask == 1) ? CurFxnReturnExprTypeSynPtr : synPtr); + if (constExpr) + { + // convert between float and [unsigned] int + if (fmask == 1) + exprVal = u ? f2u(exprVal) : f2i(exprVal, castSize); + else + exprVal = u ? u2f(exprVal) : i2f(exprVal); + } + else + { + // insert a call to convert between float and [unsigned] int + ins2(0, '(', SizeOfWord); + push(','); + push2(tokIdent, FindIdent(FpFxnName[(fmask == 1) ? (u ? FXNF2U : FXNF2I) : + (u ? FXNU2F : FXNI2F)])); + push2(')', SizeOfWord); + } + } +#endif + // If return value (per function declaration) is a scalar type smaller than machine word, // properly zero- or sign-extend the returned value to machine word size. // TBD??? Move this cast to the caller? - int castSize = GetDeclSize(CurFxnReturnExprTypeSynPtr, 1); - if (castSize != SizeOfWord && - (synPtr < 0 || castSize != GetDeclSize(synPtr, 1))) + if (castSize != SizeOfWord && castSize != GetDeclSize(synPtr, 1)) { - switch (castSize) + if (constExpr) { - case 1: - push(tokUChar); - break; - case -1: - push(tokSChar); - break; + switch (castSize) + { + case 1: + exprVal &= 0xFFu; + break; + case -1: + if ((exprVal &= 0xFFu) >= 0x80) + exprVal -= 0x100; + break; #ifdef CAN_COMPILE_32BIT - case 2: - push(tokUShort); - break; - case -2: - push(tokShort); - break; + case 2: + exprVal &= 0xFFFFu; + break; + case -2: + if ((exprVal &= 0xFFFFu) >= 0x8000) + exprVal -= 0x10000; + break; #endif + } + } + else + { + switch (castSize) + { + case 1: + push(tokUChar); + break; + case -1: + push(tokSChar); + break; +#ifdef CAN_COMPILE_32BIT + case 2: + push(tokUShort); + break; + case -2: + push(tokShort); + break; +#endif + } } } } + if (constExpr) + stack[0][1] = exprVal; push(tokReturn); // value produced by generated code is used GenExpr(); } @@ -7487,12 +8498,17 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) // DONE: void control expressions //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n"); + // Bar void and struct/union scalarTypeCheck(synPtr); GenNumLabel(labelBefore); if (constExpr) { +#ifndef NO_FP + if (isFloat(synPtr)) + exprVal = fcmp(exprVal, i2f(0), -1); +#endif // Special cases for while(0) and while(1) if (!(forever = truncInt(exprVal))) GenJumpUncond(labelAfter); @@ -7515,6 +8531,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) GenExpr(); break; default: +#ifndef NO_FP + if (isFloat(synPtr)) + { + // insert a call to compare the float with 0.0 + // the returned value will be one of -1,0,+1, that is, 0 if 0, +/-1 otherwise, + // IOW, suitable for conditional jump on zero/non-zero + ins(0, ','); + ins2(0, tokNumInt, i2f(0)); + ins2(0, '(', SizeOfWord * 2); + push(','); + push2(tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + push2(')', SizeOfWord * 2); + } +#endif push(tokReturn); // value produced by generated code is used GenExpr(); GenJumpIfZero(labelAfter); @@ -7574,12 +8604,17 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) // DONE: void control expressions //error("ParseStatement(): unexpected 'void' expression in 'while ( expression )'\n"); + // Bar void and struct/union scalarTypeCheck(synPtr); GenNumLabel(labelWhile); if (constExpr) { +#ifndef NO_FP + if (isFloat(synPtr)) + exprVal = fcmp(exprVal, i2f(0), -1); +#endif // Special cases for while(0) and while(1) if (truncInt(exprVal)) GenJumpUncond(labelBefore); @@ -7602,6 +8637,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) GenExpr(); break; default: +#ifndef NO_FP + if (isFloat(synPtr)) + { + // insert a call to compare the float with 0.0 + // the returned value will be one of -1,0,+1, that is, 0 if 0, +/-1 otherwise, + // IOW, suitable for conditional jump on zero/non-zero + ins(0, ','); + ins2(0, tokNumInt, i2f(0)); + ins2(0, '(', SizeOfWord * 2); + push(','); + push2(tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + push2(')', SizeOfWord * 2); + } +#endif push(tokReturn); // value produced by generated code is used GenExpr(); GenJumpIfNotZero(labelBefore); @@ -7637,10 +8686,15 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) // DONE: void control expressions //error("ParseStatement(): unexpected 'void' expression in 'if ( expression )'\n"); + // Bar void and struct/union scalarTypeCheck(synPtr); if (constExpr) { +#ifndef NO_FP + if (isFloat(synPtr)) + exprVal = fcmp(exprVal, i2f(0), -1); +#endif // Special cases for if(0) and if(1) if (!truncInt(exprVal)) GenJumpUncond(labelAfterIf); @@ -7663,6 +8717,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) GenExpr(); break; default: +#ifndef NO_FP + if (isFloat(synPtr)) + { + // insert a call to compare the float with 0.0 + // the returned value will be one of -1,0,+1, that is, 0 if 0, +/-1 otherwise, + // IOW, suitable for conditional jump on zero/non-zero + ins(0, ','); + ins2(0, tokNumInt, i2f(0)); + ins2(0, '(', SizeOfWord * 2); + push(','); + push2(tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + push2(')', SizeOfWord * 2); + } +#endif push(tokReturn); // value produced by generated code is used GenExpr(); GenJumpIfZero(labelAfterIf); @@ -7748,10 +8816,15 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) { // DONE: void control expressions //error("ParseStatement(): unexpected 'void' expression in 'for ( ; expression ; )'\n"); + // Bar void and struct/union scalarTypeCheck(synPtr); if (constExpr) { +#ifndef NO_FP + if (isFloat(synPtr)) + exprVal = fcmp(exprVal, i2f(0), -1); +#endif // Special cases for for(...; 0; ...) and for(...; 1; ...) cond = truncInt(exprVal) != 0; } @@ -7773,6 +8846,20 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) GenExpr(); break; default: +#ifndef NO_FP + if (isFloat(synPtr)) + { + // insert a call to compare the float with 0.0 + // the returned value will be one of -1,0,+1, that is, 0 if 0, +/-1 otherwise, + // IOW, suitable for conditional jump on zero/non-zero + ins(0, ','); + ins2(0, tokNumInt, i2f(0)); + ins2(0, '(', SizeOfWord * 2); + push(','); + push2(tokIdent, FindIdent(FpFxnName[FXNFCMPL])); + push2(')', SizeOfWord * 2); + } +#endif push(tokReturn); // value produced by generated code is used GenExpr(); GenJumpIfZero(labelAfter); @@ -7908,7 +8995,7 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) // DONE: void control expressions //error("ParseStatement(): unexpected 'void' expression in 'switch ( expression )'\n"); - scalarTypeCheck(synPtr); + anyIntTypeCheck(synPtr); push(tokReturn); // value produced by generated code is used GenExpr(); @@ -7966,7 +9053,11 @@ int ParseStatement(int tok, int BrkCntTarget[2], int casesIdx) //error("ParseStatement(): ':' expected after 'case expression'\n"); errorUnexpectedToken(tok); - if (!gotUnary || !constExpr || (synPtr >= 0 && SyntaxStack0[synPtr] == tokVoid)) // TBD??? + if (!gotUnary) + errorUnexpectedToken(tok); + + anyIntTypeCheck(synPtr); + if (!constExpr) //error("ParseStatement(): constant integer expression expected in 'case expression :'\n"); errorNotConst(); @@ -8135,6 +9226,7 @@ int main(int argc, char** argv) tokVoid, // SymVoidSynPtr tokInt, // SymIntSynPtr tokUnsigned, // SymUintSynPtr + tokFloat, // SymFloatSynPtr tokIdent, // SymFuncPtr '[', tokNumUint, @@ -8149,6 +9241,17 @@ int main(int argc, char** argv) #endif #endif +#ifndef NO_FP + { + static float testFloat = -5915522.0f * 1.5f; + static unsigned testUint = 0xCB076543; // expected representation of the above + if (memcmp(&testFloat, &testUint, sizeof testFloat)) + error("IEEE 754 floating point required on host\n"); + } + for (i = 0; (unsigned)i < sizeof FpFxnName / sizeof FpFxnName[0]; i++) + AddIdent(FpFxnName[i]); +#endif + GenInit(); // Parse the command line arguments