X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=expr.c;h=a0f6f9f49494d8ea96f55aee4a6f831ba50a348e;hp=84018bd209f5c0ad5e5daa1b85e63bbb839bf282;hb=582df8950c285e1746d0c4a9e3ead6545c962dc8;hpb=49cce96fba11282e4244187f15be418d5ae5bb8d diff --git a/expr.c b/expr.c index 84018bd..a0f6f9f 100644 --- a/expr.c +++ b/expr.c @@ -1,65 +1,71 @@ // -// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// RMAC - Reboot's Macro Assembler for all Atari computers // EXPR.C - Expression Analyzer -// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 -// Source Utilised with the Kind Permission of Landon Dyer +// Source utilised with the kind permission of Landon Dyer // #include "expr.h" -#include "token.h" -#include "listing.h" +#include "direct.h" #include "error.h" +#include "listing.h" +#include "mach.h" #include "procln.h" -#include "symbol.h" +#include "riscasm.h" #include "sect.h" -#include "mach.h" -#include "risca.h" +#include "symbol.h" +#include "token.h" -#define DEF_KW // Declare keyword values -#include "kwtab.h" // Incl generated keyword tables & defs +#define DEF_KW // Declare keyword values +#include "kwtab.h" // Incl generated keyword tables & defs -static char tokcl[128]; // Generated table of token classes -static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack -static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack +// N.B.: The size of tokenClass should be identical to the largest value of +// a token; we're assuming 256 but not 100% sure! +static char tokenClass[256]; // Generated table of token classes +static uint64_t evstk[EVSTACKSIZE]; // Evaluator value stack +static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack // Token-class initialization list char itokcl[] = { - 0, // END - CONST, SYMBOL, 0, // ID - '(', '[', '{', 0, // OPAR - ')', ']', '}', 0, // CPAR - CR_DEFINED, CR_REFERENCED, // SUNARY (special unary) + 0, // END + CONST, FCONST, SYMBOL, 0, // ID + '(', '[', '{', 0, // OPAR + ')', ']', '}', 0, // CPAR + CR_DEFINED, CR_REFERENCED, // SUNARY (special unary) CR_STREQ, CR_MACDEF, - CR_DATE, CR_TIME, 0, - '!', '~', UNMINUS, 0, // UNARY - '*', '/', '%', 0, // MULT - '+', '-', 0, // ADD - SHL, SHR, 0, // SHIFT - LE, GE, '<', '>', NE, '=', 0, // REL - '&', 0, // AND - '^', 0, // XOR - '|', 0, // OR - 1 // (the end) + CR_DATE, CR_TIME, + CR_ABSCOUNT, 0, + '!', '~', UNMINUS, 0, // UNARY + '*', '/', '%', 0, // MULT + '+', '-', 0, // ADD + SHL, SHR, 0, // SHIFT + LE, GE, '<', '>', NE, '=', 0, // REL + '&', 0, // AND + '^', 0, // XOR + '|', 0, // OR + 1 // (the end) }; -char missym_error[] = "missing symbol"; -char * str_error = "missing symbol or string"; +const char missym_error[] = "missing symbol"; +const char str_error[] = "missing symbol or string"; // Convert expression to postfix -static TOKEN * tk; // Deposit tokens here -SYM * lookup(); -SYM * newsym(); +static TOKEN * evalTokenBuffer; // Deposit tokens here (this is really a + // pointer to exprbuf from direct.c) + // (Can also be from others, like + // riscasm.c) +static int symbolNum; // Pointer to the entry in symbolPtr[] // -// Obtain a String Value +// Obtain a string value // -static VALUE str_value(char * p) +static uint32_t str_value(char * p) { - VALUE v; + uint32_t v; - for(v=0; *p; ++p) + for(v=0; *p; p++) v = (v << 8) | (*p & 0xFF); return v; @@ -67,24 +73,25 @@ static VALUE str_value(char * p) // -// Initialize Expression Analyzer +// Initialize expression analyzer // -void init_expr(void) +void InitExpression(void) { - int i; // Iterator - char * p; // Token pointer + // Initialize token-class table (all set to END) + for(int i=0; i<256; i++) + tokenClass[i] = END; - // Initialize token-class table - for(i=0; i<128; ++i) // Mark all entries END - tokcl[i] = END; + int i = 0; - for(i=0, p=itokcl; *p!=1; p++) + for(char * p=itokcl; *p!=1; p++) { if (*p == 0) i++; - else - tokcl[(int)(*p)] = (char)i; + else + tokenClass[(int)(*p)] = (char)i; } + + symbolNum = 0; } @@ -97,15 +104,15 @@ int expr0(void) if (expr1() != OK) return ERROR; - - while (tokcl[*tok] >= MULT) + + while (tokenClass[*tok] >= MULT) { t = *tok++; if (expr1() != OK) return ERROR; - *tk++ = t; + *evalTokenBuffer++ = t; } return OK; @@ -114,6 +121,9 @@ int expr0(void) // // Unary operators (detect unary '-') +// ggn: If expression starts with a plus then also eat it up. +// For some reason the parser gets confused when this happens and +// emits a "bad expression". // int expr1(void) { @@ -123,10 +133,11 @@ int expr1(void) char * p, * p2; WORD w; int j; + uint64_t * evalTokenBuffer64; - class = tokcl[*tok]; + class = tokenClass[*tok]; - if (*tok == '-' || class == UNARY) + if (*tok == '-' || *tok == '+' || class == UNARY) { t = *tok++; @@ -136,33 +147,44 @@ int expr1(void) if (t == '-') t = UNMINUS; - *tk++ = t; + // With leading + we don't have to deposit + // anything to the buffer because there's + // no unary '+' nor we have to do anything about it + if (t != '+') + *evalTokenBuffer++ = t; } else if (class == SUNARY) { switch ((int)*tok++) { + case CR_ABSCOUNT: + *evalTokenBuffer++ = CONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = (LONG)sect[ABS].sloc; + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + break; case CR_TIME: - *tk++ = CONST; - *tk++ = dos_time(); + *evalTokenBuffer++ = CONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = dos_time(); + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; break; case CR_DATE: - *tk++ = CONST; - *tk++ = dos_date(); + *evalTokenBuffer++ = CONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = dos_date(); + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; break; case CR_MACDEF: // ^^macdef if (*tok++ != SYMBOL) return error(missym_error); - p = (char *)*tok++; - - if (lookup(p, MACRO, 0) == NULL) - w = 0; - else - w = 1; - - *tk++ = CONST; - *tk++ = (TOKEN)w; + p = string[*tok++]; + w = (lookup(p, MACRO, 0) == NULL ? 0 : 1); + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = (TOKEN)w; + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer++ = (TOKEN)w; break; case CR_DEFINED: w = DEFINED; @@ -173,25 +195,19 @@ getsym: if (*tok++ != SYMBOL) return error(missym_error); - p = (char *)*tok++; - j = 0; - - if (*p == '.') - j = curenv; - - if ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w)) - w = 1; - else - w = 0; - - *tk++ = CONST; - *tk++ = (TOKEN)w; + p = string[*tok++]; + j = (*p == '.' ? curenv : 0); + w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0); + *evalTokenBuffer++ = CONST; + uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = (TOKEN)w; + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; break; case CR_STREQ: if (*tok != SYMBOL && *tok != STRING) return error(str_error); - p = (char *)tok[1]; + p = string[tok[1]]; tok +=2; if (*tok++ != ',') @@ -200,16 +216,18 @@ getsym: if (*tok != SYMBOL && *tok != STRING) return error(str_error); - p2 = (char *)tok[1]; + p2 = string[tok[1]]; tok += 2; w = (WORD)(!strcmp(p, p2)); - *tk++ = CONST; - *tk++ = (TOKEN)w; + *evalTokenBuffer++ = CONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = (TOKEN)w; + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; break; } } - else + else return expr2(); return OK; @@ -224,48 +242,62 @@ int expr2(void) char * p; SYM * sy; int j; + uint64_t * evalTokenBuffer64; + uint64_t * tok64; switch ((int)*tok++) { case CONST: - *tk++ = CONST; - *tk++ = *tok++; + *evalTokenBuffer++ = CONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + tok64 = (uint64_t *)tok; + *evalTokenBuffer64++ = *tok64++; + tok = (TOKEN *)tok64; + evalTokenBuffer = (TOKEN *)evalTokenBuffer64; + break; + case FCONST: + *evalTokenBuffer++ = FCONST; + evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + tok64 = (uint64_t *)tok; + *evalTokenBuffer64++ = *tok64++; + tok = (TOKEN *)tok64; + evalTokenBuffer = (TOKEN *)evalTokenBuffer64; break; case SYMBOL: - p = (char *)*tok++; - j = 0; - - if (*p == '.') - j = curenv; - + p = string[*tok++]; + j = (*p == '.' ? curenv : 0); sy = lookup(p, LABEL, j); if (sy == NULL) - sy = newsym(p, LABEL, j); + sy = NewSymbol(p, LABEL, j); // Check register bank usage if (sy->sattre & EQUATEDREG) { - if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok) - warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname); + if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok) + warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname); if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok) - warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname); + warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname); } - *tk++ = SYMBOL; - *tk++ = (TOKEN)sy; + *evalTokenBuffer++ = SYMBOL; + *evalTokenBuffer++ = symbolNum; + symbolPtr[symbolNum] = sy; + symbolNum++; break; case STRING: - *tk++ = CONST; - *tk++ = str_value((char *)*tok++); + *evalTokenBuffer++ = CONST; + uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = str_value(string[*tok++]); + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; break; case '(': if (expr0() != OK) return ERROR; if (*tok++ != ')') - return error("missing close parenthesis ')'"); + return error("missing closing parenthesis ')'"); break; case '[': @@ -273,23 +305,35 @@ int expr2(void) return ERROR; if (*tok++ != ']') - return error("missing close parenthesis ']'"); + return error("missing closing bracket ']'"); break; case '$': - *tk++ = ACONST; // Attributed const - *tk++ = sloc; // Current location - *tk++ = cursect | DEFINED; // Store attribs + *evalTokenBuffer++ = ACONST; // Attributed const + *evalTokenBuffer++ = sloc; // Current location + *evalTokenBuffer++ = cursect | DEFINED; // Store attribs break; case '*': - *tk++ = ACONST; // Attributed const + *evalTokenBuffer++ = ACONST; // Attributed const - if (orgactive) - *tk++ = orgaddr; - else - *tk++ = pcloc; // Location at start of line + // pcloc == location at start of line + *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc); + // '*' takes attributes of current section, not ABS! + *evalTokenBuffer++ = cursect | DEFINED; + break; + case '{': + if (expr0() != OK) // Eat up first parameter (register or immediate) + return ERROR; + + if (*tok++ != ':') // Demand a ':' there + return error("missing colon ':'"); + + if (expr0() != OK) // Eat up second parameter (register or immediate) + return ERROR; + + if (*tok++ != '}') + return error("missing closing brace '}'"); - *tk++ = ABS | DEFINED; // Store attribs break; default: return error("bad expression"); @@ -302,109 +346,187 @@ int expr2(void) // // Recursive-descent expression analyzer (with some simple speed hacks) // -int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym) +int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) { - SYM * sy; + // Passed in values (once derefenced, that is) can all be zero. They are + // there so that the expression analyzer can fill them in as needed. The + // expression analyzer gets its input from the global token pointer "tok", + // and not from anything passed in by the user. + SYM * symbol; char * p; int j; - tk = otk; + evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c) + // Also set in various other places too (riscasm.c, + // e.g.) +//printf("expr(): tokens 0-2: %i %i %i (%c %c %c); tc[2] = %i\n", tok[0], tok[1], tok[2], tok[0], tok[1], tok[2], tokenClass[tok[2]]); // Optimize for single constant or single symbol. - if ((tok[1] == EOL) - || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31)) - && (tokcl[tok[2]] < UNARY))) + // Shamus: Subtle bug here. EOL token is 101; if you have a constant token + // followed by the value 101, it will trigger a bad evaluation here. + // This is probably a really bad assumption to be making here...! + // (assuming tok[1] == EOL is a single token that is) + // Seems that even other tokens (SUNARY type) can fuck this up too. +// if ((tok[1] == EOL) + if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY)) +// || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31)) +// && (tokenClass[tok[2]] < UNARY))) + || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31)) + && (tokenClass[tok[2]] < UNARY)) + || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY)) + ) { if (*tok >= KW_R0 && *tok <= KW_R31) { - *tk++ = CONST; - *tk++ = *a_value = (*tok - KW_R0); + *evalTokenBuffer++ = CONST; + uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer64++ = *a_value = (*tok - KW_R0); + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; *a_attr = ABS | DEFINED; if (a_esym != NULL) *a_esym = NULL; tok++; - *tk++ = ENDEXPR; - return OK; } else if (*tok == CONST) { - *tk++ = CONST; - *tk++ = *a_value = tok[1]; + *evalTokenBuffer++ = CONST; + uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + uint64_t *tok64 = (uint64_t *)&tok[1]; + *evalTokenBuffer64++ = *tok64++; + evalTokenBuffer = (TOKEN *)evalTokenBuffer64; + *a_value = tok[1]; *a_attr = ABS | DEFINED; if (a_esym != NULL) *a_esym = NULL; + + tok += 3; +//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]); + } + else if (*tok == FCONST) + { + *evalTokenBuffer++ = FCONST; + *((double *)evalTokenBuffer) = *((double *)&tok[1]); + evalTokenBuffer += 2; + //*(double *)evalTokenBuffer++ = tok[2]; + *a_value = *((uint64_t *)&tok[1]); + *a_attr = ABS | DEFINED | FLOAT; + + if (a_esym != NULL) + *a_esym = NULL; + + tok += 3; +//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]); } else if (*tok == '*') { - *tk++ = CONST; + *evalTokenBuffer++ = CONST; + uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; if (orgactive) - *tk++ = *a_value = orgaddr; + *evalTokenBuffer64++ = *a_value = orgaddr; else - *tk++ = *a_value = pcloc; + *evalTokenBuffer64++ = *a_value = pcloc; + evalTokenBuffer = (uint32_t *)evalTokenBuffer64; - *a_attr = ABS | DEFINED; - //*tk++ = + // '*' takes attributes of current section, not ABS! + *a_attr = cursect | DEFINED; if (a_esym != NULL) *a_esym = NULL; - tok--; + tok++; } - else + else if (*tok == STRING || *tok == SYMBOL) { - p = (char *)tok[1]; - j = 0; - - if (*p == '.') - j = curenv; - - sy = lookup(p, LABEL, j); - - if (sy == NULL) - sy = newsym(p, LABEL, j); - - sy->sattr |= REFERENCED; + p = string[tok[1]]; + j = (*p == '.' ? curenv : 0); + symbol = lookup(p, LABEL, j); +#if 0 +printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol); +if (symbol) + printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname); +#endif + + if (symbol == NULL) + symbol = NewSymbol(p, LABEL, j); + + symbol->sattr |= REFERENCED; + + // Check for undefined register equates, but only if it's not part + // of a # construct, as it could be that the label that's + // been undefined may later be used as an address label--which + // means it will be fixed up later, and thus, not an error. + if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen) + { + error("undefined register equate '%s'", symbol->sname); +//if we return right away, it returns some spurious errors... +// return ERROR; + } // Check register bank usage - if (sy->sattre & EQUATEDREG) + if (symbol->sattre & EQUATEDREG) { - if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok) - warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname); + if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok) + warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname); - if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok) - warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname); + if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok) + warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname); } - *tk++ = SYMBOL; - *tk++ = (TOKEN)sy; - - if (sy->sattr & DEFINED) - *a_value = sy->svalue; + *evalTokenBuffer++ = SYMBOL; +#if 0 + *evalTokenBuffer++ = (TOKEN)symbol; +#else +/* +While this approach works, it's wasteful. It would be better to use something +that's already available, like the symbol "order defined" table (which needs to +be converted from a linked list into an array). +*/ + *evalTokenBuffer++ = symbolNum; + symbolPtr[symbolNum] = symbol; + symbolNum++; +#endif + + if (symbol->sattr & DEFINED) + *a_value = symbol->svalue; else *a_value = 0; - if (sy->sattre & EQUATEDREG) +/* +All that extra crap that was put into the svalue when doing the equr stuff is +thrown away right here. What the hell is it for? +*/ + if (symbol->sattre & EQUATEDREG) *a_value &= 0x1F; - *a_attr = (WORD)(sy->sattr & ~GLOBAL); + *a_attr = (WORD)(symbol->sattr & ~GLOBAL); - if ((sy->sattr & (GLOBAL|DEFINED)) == GLOBAL && a_esym != NULL) - *a_esym = sy; + if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL + && a_esym != NULL) + *a_esym = symbol; + + tok += 2; + } + else + { + // Unknown type here... Alert the user!, + error("undefined RISC register in expression"); + // Prevent spurious error reporting... + tok++; + return ERROR; } - tok += 2; - *tk++ = ENDEXPR; + *evalTokenBuffer++ = ENDEXPR; return OK; } if (expr0() != OK) return ERROR; - *tk++ = ENDEXPR; + *evalTokenBuffer++ = ENDEXPR; return evexpr(otk, a_value, a_attr, a_esym); } @@ -415,38 +537,36 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym) // UNDEFINED, but it's value includes everything but the symbol value, and // `a_esym' is set to the external symbol. // -int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym) +int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) { - WORD * sattr; - VALUE * sval; - WORD attr; + WORD attr, attr2; SYM * sy; - SYM * esym; - WORD sym_seg; - - sval = evstk; // (Empty) initial stack - sattr = evattr; - esym = NULL; // No external symbol involved - sym_seg = 0; + uint64_t * sval = evstk; // (Empty) initial stack + WORD * sattr = evattr; + SYM * esym = NULL; // No external symbol involved + WORD sym_seg = 0; + uint64_t *tk64; while (*tk != ENDEXPR) { switch ((int)*tk++) { case SYMBOL: - sy = (SYM *)*tk++; - sy->sattr |= REFERENCED; // Set "referenced" bit +//printf("evexpr(): SYMBOL\n"); + sy = symbolPtr[*tk++]; + sy->sattr |= REFERENCED; // Set "referenced" bit if (!(sy->sattr & DEFINED)) { + // Reference to undefined symbol if (!(sy->sattr & GLOBAL)) - { // Reference to undefined symbol + { *a_attr = 0; *a_value = 0; return OK; } - if (esym != NULL) // Check for multiple externals + if (esym != NULL) // Check for multiple externals return error(seg_error); esym = sy; @@ -454,209 +574,579 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym) if (sy->sattr & DEFINED) { - *++sval = sy->svalue; // Push symbol's value + *++sval = sy->svalue; // Push symbol's value } else { - *++sval = 0; // 0 for undefined symbols + *++sval = 0; // 0 for undefined symbols } - *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs - sym_seg = (WORD)(sy->sattr & (TEXT|DATA|BSS)); + *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs + sym_seg = (WORD)(sy->sattr & TDB); break; case CONST: - *++sval = *tk++; // Push value - *++sattr = ABS|DEFINED; // Push simple attribs + tk64 = (uint64_t *)tk; + *++sval = *tk64++; + tk = (TOKEN *)tk64; +//printf("evexpr(): CONST = %lX\n", *sval); + *++sattr = ABS | DEFINED; // Push simple attribs + break; + case FCONST: +//printf("evexpr(): CONST = %i\n", *tk); + *((double *)sval) = *((double *)tk); + tk += 2; + *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs break; case ACONST: - *++sval = *tk++; // Push value - *++sattr = (WORD)*tk++; // Push attribs +//printf("evexpr(): ACONST = %i\n", *tk); + *++sval = *tk++; // Push value + *++sattr = (WORD)*tk++; // Push attribs break; // Binary "+" and "-" matrix: - // + // // ABS Sect Other // ---------------------------- // ABS | ABS | Sect | Other | // Sect | Sect | [1] | Error | // Other | Other | Error | [1] | // ---------------------------- - // + // // [1] + : Error // - : ABS case '+': - --sval; // Pop value - --sattr; // Pop attrib - *sval += sval[1]; // Compute value +//printf("evexpr(): +\n"); + --sval; // Pop value + --sattr; // Pop attrib +//printf("--> N+N: %i + %i = ", *sval, sval[1]); + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float + Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *dst += *src; + } + else if (attr == FLOAT) + { + // Float + Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *dst += *src; + } + else if (attr == FLOAT >> 1) + { + // Int + Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *(double *)dst = *src + *dst; + } + else + { + *sval += sval[1]; // Compute value + } +//printf("%i\n", *sval); - if (!(*sattr & (TEXT|DATA|BSS))) - *sattr = sattr[1]; - else if (sattr[1] & (TEXT|DATA|BSS)) + if (!(*sattr & TDB)) + *sattr = sattr[1] | attr2; + else if (sattr[1] & TDB) return error(seg_error); break; case '-': - --sval; // Pop value - --sattr; // Pop attrib - *sval -= sval[1]; // Compute value +//printf("evexpr(): -\n"); + --sval; // Pop value + --sattr; // Pop attrib +//printf("--> N-N: %i - %i = ", *sval, sval[1]); + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float - Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *dst -= *src; + } + else if (attr == FLOAT) + { + // Float - Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *dst -= *src; + } + else if (attr == FLOAT >> 1) + { + // Int - Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *(double *)dst = *dst - *src; + } + else + { + *sval -= sval[1]; // Compute value + } - attr = (WORD)(*sattr & (TEXT|DATA|BSS)); +//printf("%i\n", *sval); + attr = (WORD)(*sattr & TDB); +#if 0 +printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); +#endif + *sattr |= attr2; // Inherit FLOAT attribute + // If symbol1 is ABS, take attributes from symbol2 if (!attr) *sattr = sattr[1]; - else if (sattr[1] & (TEXT|DATA|BSS)) - { - if (!(attr & sattr[1])) - return error(seg_error); - else - *sattr &= ~(TEXT|DATA|BSS); - } + // Otherwise, they're both TDB and so attributes cancel out + else if (sattr[1] & TDB) + *sattr &= ~TDB; break; - // Unary operators only work on ABS items + // Unary operators only work on ABS items case UNMINUS: - if (*sattr & (TEXT|DATA|BSS)) - error(seg_error); +//printf("evexpr(): UNMINUS\n"); + if (*sattr & TDB) + return error(seg_error); + if (*sattr & FLOAT) + { + double *dst = (double *)sval; + *dst = -*dst; + *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute + } + else + { *sval = -(int)*sval; - *sattr = ABS|DEFINED; // Expr becomes absolute + *sattr = ABS | DEFINED; // Expr becomes absolute + } break; case '!': - if (*sattr & (TEXT|DATA|BSS)) - error(seg_error); +//printf("evexpr(): !\n"); + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error("floating point numbers not allowed with operator '!'."); *sval = !*sval; - *sattr = ABS|DEFINED; // Expr becomes absolute + *sattr = ABS | DEFINED; // Expr becomes absolute break; case '~': - if (*sattr & (TEXT|DATA|BSS)) - error(seg_error); +//printf("evexpr(): ~\n"); + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error("floating point numbers not allowed with operator '~'."); *sval = ~*sval; - *sattr = ABS|DEFINED; // Expr becomes absolute + *sattr = ABS | DEFINED; // Expr becomes absolute break; - // Comparison operators must have two values that - // are in the same segment, but that's the only requirement. + // Comparison operators must have two values that + // are in the same segment, but that's the only requirement. case LE: - --sattr; - --sval; +//printf("evexpr(): LE\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); + + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); - *sattr = ABS|DEFINED; + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float <= Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *sval = *dst <= *src; + } + else if (attr == FLOAT) + { + // Float <= Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *sval = *dst <= *src; + } + else if (attr == FLOAT >> 1) + { + // Int <= Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *sval = *dst <= *src; + } + else + { *sval = *sval <= sval[1]; + } + + *sattr = ABS | DEFINED; break; case GE: - --sattr; - --sval; +//printf("evexpr(): GE\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); + + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); - *sattr = ABS|DEFINED; + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float >= Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *sval = *dst >= *src; + } + else if (attr == FLOAT) + { + // Float >= Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *sval = *dst >= *src; + } + else if (attr == FLOAT >> 1) + { + // Int >= Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *sval = *dst >= *src; + } + else if (attr == 0) + { *sval = *sval >= sval[1]; + } + else + + *sattr = ABS | DEFINED; + break; case '>': - --sattr; - --sval; +//printf("evexpr(): >\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); - *sattr = ABS|DEFINED; + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float > Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *sval = *dst > *src; + } + else if (attr == FLOAT) + { + // Float > Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *sval = *dst > *src; + } + else if (attr == FLOAT >> 1) + { + // Int > Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *sval = *dst > *src; + } + else += { *sval = *sval > sval[1]; + } + + *sattr = ABS | DEFINED; + break; case '<': - --sattr; - --sval; +//printf("evexpr(): <\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); + + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) > >1); - *sattr = ABS|DEFINED; + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float < Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *sval = *dst < *src; + } + else if (attr == FLOAT) + { + // Float < Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *sval = *dst < *src; + } + else if (attr == FLOAT >> 1) + { + // Int < Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *sval = *dst < *src; + } + else + { *sval = *sval < sval[1]; + } + + *sattr = ABS | DEFINED; + break; case NE: - --sattr; - --sval; +//printf("evexpr(): NE\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); - *sattr = ABS|DEFINED; + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float <> Float + return error("comparison for equality with float types not allowed."); + } + else if (attr == FLOAT) + { + // Float <> Int + return error("comparison for equality with float types not allowed."); + } + else if (attr == FLOAT >> 1) + { + // Int != Float + return error("comparison for equality with float types not allowed."); + } + else + { *sval = *sval != sval[1]; + } + + *sattr = ABS | DEFINED; + break; case '=': - --sattr; - --sval; +//printf("evexpr(): =\n"); + sattr--; + sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) - error(seg_error); + return error(seg_error); + + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); - *sattr = ABS|DEFINED; + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float = Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *sval = *src == *dst; + } + else if (attr == FLOAT) + { + // Float = Int + return error("equality with float "); + } + else if (attr == FLOAT >> 1) + { + // Int == Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *sval = *src == *dst; + } + else + { *sval = *sval == sval[1]; + } + + *sattr = ABS | DEFINED; + break; - // All other binary operators must have two ABS items - // to work with. They all produce an ABS value. + // All other binary operators must have two ABS items + // to work with. They all produce an ABS value. default: +//printf("evexpr(): default\n"); // GH - Removed for v1.0.15 as part of the fix for indexed loads. //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS))) //error(seg_error); - *sattr = ABS|DEFINED; // Expr becomes absolute switch ((int)tk[-1]) { case '*': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib +//printf("--> NxN: %i x %i = ", *sval, sval[1]); + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float * Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + *dst *= *src; + } + else if (attr == FLOAT) + { + // Float * Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + *dst *= *src; + } + else if (attr == FLOAT >> 1) + { + // Int * Float + uint64_t * dst = (uint64_t *)sval; + double * src = (double *)(sval + 1); + *(double *)dst = *src * *dst; + } + else + { *sval *= sval[1]; + } +//printf("%i\n", *sval); + + *sattr = ABS | DEFINED; // Expr becomes absolute + *sattr |= attr2; + break; case '/': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + + +//printf("--> N/N: %i / %i = ", sval[0], sval[1]); + // Extract float attributes from both terms and pack them + // into a single value + attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1); + attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT + + if (attr == (FLOAT | (FLOAT >> 1))) + { + // Float / Float + double * dst = (double *)sval; + double * src = (double *)(sval + 1); + if (*src == 0) + return error("divide by zero"); + *dst = *dst / *src; + } + else if (attr == FLOAT) + { + // Float / Int + double * dst = (double *)sval; + uint64_t * src = (uint64_t *)(sval + 1); + if (*src == 0) + return error("divide by zero"); + *dst = *dst / *src; + } + else if (attr == FLOAT >> 1) + { + // Int / Float + uint64_t * dst=(uint64_t *)sval; + double * src=(double *)(sval + 1); + if (*src == 0) + return error("divide by zero"); + *(double *)dst = *dst / *src; + } + else + { + if (sval[1] == 0) + return error("divide by zero"); +//printf("--> N/N: %i / %i = ", sval[0], sval[1]); + // Compiler is picky here: Without casting these, it discards + // the sign if dividing a negative # by a positive one, + // creating a bad result. :-/ + // Definitely a side effect of using uint32_ts intead of ints. + *sval = (int32_t)sval[0] / (int32_t)sval[1]; + } - if (sval[1] == 0) - return error("divide by zero"); + *sattr = ABS | DEFINED; // Expr becomes absolute + *sattr |= attr2; - *sval /= sval[1]; +//printf("%i\n", *sval); break; case '%': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '%'."); if (sval[1] == 0) return error("mod (%) by zero"); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval %= sval[1]; break; case SHL: - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '<<'."); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval <<= sval[1]; break; case SHR: - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '>>'."); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval >>= sval[1]; break; case '&': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '&'."); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval &= sval[1]; break; case '^': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '^'."); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval ^= sval[1]; break; case '|': - --sval; - --sattr; // Pop attrib + sval--; + sattr--; // Pop attrib + if ((*sattr | sattr[1]) & FLOAT) + return error("floating point numbers not allowed with operator '|'."); + *sattr = ABS | DEFINED; // Expr becomes absolute *sval |= sval[1]; break; default: - interror(5); // Bad operator in expression stream + interror(5); // Bad operator in expression stream } } } @@ -670,10 +1160,11 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym) // sym_seg added in 1.0.16 to solve a problem with forward symbols in // expressions where absolute values also existed. The absolutes were // overiding the symbol segments and not being included :( - //*a_attr = *sattr | sym_seg; // Copy value + attrib + //*a_attr = *sattr | sym_seg; // Copy value + attrib - *a_attr = *sattr; // Copy value + attrib + *a_attr = *sattr; // Copy value + attrib *a_value = *sval; return OK; } +