X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=expr.c;h=f31e9e59ddf67c1be317af23a1428c22da4ee534;hp=5474af8c36fa9cec7fd7506e5d230641d47f1462;hb=HEAD;hpb=4ca28ba07da9f3848c2e3db0e2e9cbcaa787dd29 diff --git a/expr.c b/expr.c index 5474af8..e597257 100644 --- a/expr.c +++ b/expr.c @@ -1,7 +1,7 @@ // -// RMAC - Reboot's Macro Assembler for all Atari computers +// RMAC - Renamed Macro Assembler for all Atari computers // EXPR.C - Expression Analyzer -// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 // Source utilised with the kind permission of Landon Dyer // @@ -35,8 +35,8 @@ char itokcl[] = { CR_DEFINED, CR_REFERENCED, // SUNARY (special unary) CR_STREQ, CR_MACDEF, CR_DATE, CR_TIME, - CR_ABSCOUNT, 0, - '!', '~', UNMINUS, 0, // UNARY + CR_ABSCOUNT, CR_FILESIZE, 0, + '!', '~', UNMINUS, UNLT, UNGT, 0, // UNARY '*', '/', '%', 0, // MULT '+', '-', 0, // ADD SHL, SHR, 0, // SHIFT @@ -49,6 +49,7 @@ char itokcl[] = { const char missym_error[] = "missing symbol"; const char str_error[] = "missing symbol or string"; +const char noflt_error[] = "operator not usable with float"; // Convert expression to postfix static PTR evalTokenBuffer; // Deposit tokens here (this is really a @@ -57,7 +58,6 @@ static PTR evalTokenBuffer; // Deposit tokens here (this is really a // riscasm.c) static int symbolNum; // Pointer to the entry in symbolPtr[] - // // Obtain a string value // @@ -71,7 +71,6 @@ static uint32_t str_value(char * p) return v; } - // // Initialize expression analyzer // @@ -94,28 +93,99 @@ void InitExpression(void) symbolNum = 0; } +extern int correctMathRules; +int xor(void); +int and(void); +int rel(void); +int shift(void); +int sum(void); +int product(void); // -// Binary operators (all the same precedence) +// Binary operators (all the same precedence, +// except if -4 is passed to the command line) // +#define precedence(HIERARCHY_HIGHER, HIERARCHY_CURRENT) \ +do \ +{ \ + if (HIERARCHY_HIGHER() != OK) \ + return ERROR; \ + while (tokenClass[*tok] == HIERARCHY_CURRENT) \ + { \ + TOKEN t = *tok++; \ + if (HIERARCHY_HIGHER() != OK) \ + return ERROR; \ + *evalTokenBuffer.u32++ = t; \ + } \ +}while (0) + int expr0(void) { - if (expr1() != OK) - return ERROR; - - while (tokenClass[*tok] >= MULT) + if ( correctMathRules == 0 ) { - TOKEN t = *tok++; - if (expr1() != OK) return ERROR; - *evalTokenBuffer.u32++ = t; + while (tokenClass[*tok] >= MULT) + { + TOKEN t = *tok++; + + if (expr1() != OK) + return ERROR; + + *evalTokenBuffer.u32++ = t; + } } + else + { + // The order of C precedence (lower to higher): + // bitwise XOR ^ + // bitwise OR | + // bitwise AND & + // relational = < <= >= > != + // shifts << >> + // sum + - + // product * / + precedence(xor, OR); + } + return OK; +} + +int xor(void) +{ + precedence(and, XOR); + return OK; +} + +int and(void) +{ + precedence(rel, AND); + return OK; +} + +int rel(void) +{ + precedence(shift, REL); + return OK; +} + +int shift(void) +{ + precedence(sum, SHIFT); + return OK; +} +int sum(void) +{ + precedence(product, ADD); return OK; } +int product(void) +{ + precedence(expr1, MULT); + return OK; +} // // Unary operators (detect unary '-') @@ -125,23 +195,24 @@ int expr0(void) // int expr1(void) { - TOKEN t; - SYM * sy; - char * p, * p2; + char * p; WORD w; - int j; int class = tokenClass[*tok]; - if (*tok == '-' || *tok == '+' || class == UNARY) + if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY) { - t = *tok++; + TOKEN t = *tok++; if (expr2() != OK) return ERROR; if (t == '-') t = UNMINUS; + else if (t == '<') + t = UNLT; + else if (t == '>') + t = UNGT; // 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 @@ -153,8 +224,53 @@ int expr1(void) switch (*tok++) { case CR_ABSCOUNT: + if (cursect != ABS) + { + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = sect[ABS].sloc; + } + else + { + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = sloc; + } + break; + case CR_FILESIZE: + if (*tok++ != STRING) + return error("^^FILESIZE expects filename inside string"); *evalTokenBuffer.u32++ = CONST; - *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc; + // @@copypasted from d_incbin, maybe factor this out somehow? + // Attempt to open the include file in the current directory, then (if that + // failed) try list of include files passed in the enviroment string or by + // the "-d" option. + int fd, i; + char buf1[256]; + + if ((fd = open(string[*tok], _OPEN_INC)) < 0) + { + for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++) + { + fd = strlen(buf1); + + // Append path char if necessary + if ((fd > 0) && (buf1[fd - 1] != SLASHCHAR)) + strcat(buf1, SLASHSTRING); + + strcat(buf1, string[*tok]); + + if ((fd = open(buf1, _OPEN_INC)) >= 0) + goto allright; + } + + return error("cannot open: \"%s\"", string[*tok]); + } + +allright: + *evalTokenBuffer.u64++ = (uint64_t)lseek(fd, 0L, SEEK_END); + close(fd); + + // Advance tok because of consumed string token + tok++; break; case CR_TIME: *evalTokenBuffer.u32++ = CONST; @@ -183,8 +299,9 @@ getsym: return error(missym_error); p = string[*tok++]; - j = (*p == '.' ? curenv : 0); - w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0); + int j = (*p == '.' ? curenv : 0); + SYM * sy = lookup(p, LABEL, j); + w = ((sy != NULL) && (sy->sattr & w ? 1 : 0)); *evalTokenBuffer.u32++ = CONST; *evalTokenBuffer.u64++ = (uint64_t)w; break; @@ -201,7 +318,7 @@ getsym: if (*tok != SYMBOL && *tok != STRING) return error(str_error); - p2 = string[tok[1]]; + char * p2 = string[tok[1]]; tok += 2; w = (WORD)(!strcmp(p, p2)); @@ -216,15 +333,11 @@ getsym: return OK; } - // // Terminals (CONSTs) and parenthesis grouping // int expr2(void) { - char * p; - SYM * sy; - int j; PTR ptk; switch (*tok++) @@ -237,33 +350,25 @@ int expr2(void) break; case FCONST: ptk.u32 = tok; - *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u32++ = FCONST; *evalTokenBuffer.u64++ = *ptk.u64++; tok = ptk.u32; break; case SYMBOL: - p = string[*tok++]; - j = (*p == '.' ? curenv : 0); - sy = lookup(p, LABEL, j); + { + char * p = string[*tok++]; + int j = (*p == '.' ? curenv : 0); + SYM * sy = lookup(p, LABEL, j); if (sy == NULL) sy = NewSymbol(p, LABEL, j); - // Check register bank usage - if (sy->sattre & EQUATEDREG) - { - 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) - warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname); - } - *evalTokenBuffer.u32++ = SYMBOL; *evalTokenBuffer.u32++ = symbolNum; symbolPtr[symbolNum] = sy; symbolNum++; break; + } case STRING: *evalTokenBuffer.u32++ = CONST; *evalTokenBuffer.u64++ = str_value(string[*tok++]); @@ -301,7 +406,7 @@ int expr2(void) case '$': *evalTokenBuffer.u32++ = ACONST; // Attributed const *evalTokenBuffer.u32++ = sloc; // Current location - *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs + *evalTokenBuffer.u32++ = DEFINED | ((orgactive | org68k_active) ? 0 : cursect); // Store attribs break; case '*': *evalTokenBuffer.u32++ = ACONST; // Attributed const @@ -309,7 +414,8 @@ int expr2(void) // pcloc == location at start of line *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc); // '*' takes attributes of current section, not ABS! - *evalTokenBuffer.u32++ = cursect | DEFINED; + // Also, if we're ORG'd, the symbol is absolute + *evalTokenBuffer.u32++ = DEFINED | ((orgactive | org68k_active) ? 0 : cursect); break; default: return error("bad expression"); @@ -318,7 +424,6 @@ int expr2(void) return OK; } - // // Recursive-descent expression analyzer (with some simple speed hacks) // @@ -334,49 +439,24 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) PTR ptk; evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c) - // Also set in various other places too (riscasm.c, - // e.g.) + // 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. - // 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 0 -// 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)) - ) -#else -// Shamus: Seems to me that this could be greatly simplified by 1st checking if the first token is a multibyte token, *then* checking if there's an EOL after it depending on the actual length of the token (multiple vs. single). Otherwise, we have the horror show that is the following: + // Shamus: Seems to me that this could be greatly simplified by 1st + // checking if the first token is a multibyte token, *then* + // checking if there's an EOL after it depending on the actual + // length of the token (multiple vs. single). Otherwise, we have + // the horror show that is the following: if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY)) - || (((tok[0] == SYMBOL) - || (tok[0] >= KW_R0 && tok[0] <= KW_R31)) + || ((tok[0] == SYMBOL) && (tokenClass[tok[2]] < UNARY)) || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY)) ) -// Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis niavely checking tok[1] for an EOL. O_o -#endif +// Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis naively checking tok[1] for an EOL. O_o { - if (*tok >= KW_R0 && *tok <= KW_R31) - { - *evalTokenBuffer.u32++ = CONST; - *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0); - *a_attr = ABS | DEFINED; - - if (a_esym != NULL) - *a_esym = NULL; - - tok++; - } - else if (*tok == CONST) + if (*tok == CONST) { ptk.u32 = tok; *evalTokenBuffer.u32++ = *ptk.u32++; @@ -410,13 +490,18 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) { *evalTokenBuffer.u32++ = CONST; - if (orgactive) + if (orgactive | org68k_active) + { *evalTokenBuffer.u64++ = *a_value = orgaddr; + *a_attr = DEFINED; // We have ORG active, it doesn't belong in a section! + } else + { *evalTokenBuffer.u64++ = *a_value = pcloc; + // '*' takes attributes of current section, not ABS! + *a_attr = cursect | DEFINED; + } - // '*' takes attributes of current section, not ABS! - *a_attr = cursect | DEFINED; if (a_esym != NULL) *a_esym = NULL; @@ -428,11 +513,6 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) 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); @@ -446,18 +526,6 @@ if (symbol) 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 (symbol->sattre & EQUATEDREG) - { - 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) && (symbol->sattre & BANK_0) && !altbankok) - warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname); } *evalTokenBuffer.u32++ = SYMBOL; @@ -474,19 +542,14 @@ be converted from a linked list into an array). symbolNum++; #endif - if (symbol->sattr & DEFINED) - *a_value = symbol->svalue; - else - *a_value = 0; + *a_value = (symbol->sattr & DEFINED ? symbol->svalue : 0); + *a_attr = (WORD)(symbol->sattr & ~GLOBAL); -/* -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)(symbol->sattr & ~GLOBAL); + { + *a_attr |= RISCREG; // Mark it as a register, 'cause it is + *a_esym = symbol; + } if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL) @@ -494,10 +557,15 @@ thrown away right here. What the hell is it for? tok += 2; } + // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!! + else if (m6502) + { + *evalTokenBuffer.u32++ = *tok++; + } else { // Unknown type here... Alert the user!, - error("undefined RISC register in expression"); + error("undefined RISC register in expression [token=$%X]", *tok); // Prevent spurious error reporting... tok++; return ERROR; @@ -514,16 +582,15 @@ thrown away right here. What the hell is it for? return evexpr(otk, a_value, a_attr, a_esym); } - // // Evaluate expression. // If the expression involves only ONE external symbol, the expression is -// UNDEFINED, but it's value includes everything but the symbol value, and +// UNDEFINED, but its value includes everything but the symbol value, and // 'a_esym' is set to the external symbol. // int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) { - WORD attr, attr2; + WORD attr; SYM * sy; uint64_t * sval = evstk; // (Empty) initial stack WORD * sattr = evattr; @@ -537,7 +604,6 @@ int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) switch ((int)*tk.u32++) { case SYMBOL: -//printf("evexpr(): SYMBOL\n"); sy = symbolPtr[*tk.u32++]; sy->sattr |= REFERENCED; // Set "referenced" bit @@ -558,30 +624,27 @@ int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) } if (sy->sattr & DEFINED) - { *++sval = sy->svalue; // Push symbol's value - } else - { *++sval = 0; // 0 for undefined symbols - } *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs sym_seg = (WORD)(sy->sattr & TDB); break; + case CONST: *++sval = *tk.u64++; -//printf("evexpr(): CONST = %lX\n", *sval); *++sattr = ABS | DEFINED; // Push simple attribs break; + case FCONST: -//printf("evexpr(): FCONST = %i\n", *tk.u32); - *((double *)sval) = *((double *)tk.u32); - tk.u32 += 2; + // Even though it's a double, we can treat it like a uint64_t since + // we're just moving the bits around. + *++sval = *tk.u64++; *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs break; + case ACONST: -//printf("evexpr(): ACONST = %i\n", *tk.u32); *++sval = *tk.u32++; // Push value *++sattr = (WORD)*tk.u32++; // Push attribs break; @@ -597,92 +660,62 @@ int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) // // [1] + : Error // - : ABS + case '+': -//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 + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + // Since adding an int to a fp value promotes it to a fp value, we + // don't care whether it's first or second; we cast to to a double + // regardless. + if (attr == FLOAT) { - // 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; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *(double *)sval = fpval1 + fpval2; } else { *sval += sval[1]; // Compute value } -//printf("%i\n", *sval); if (!(*sattr & TDB)) - *sattr = sattr[1] | attr2; + *sattr = sattr[1] | attr; else if (sattr[1] & TDB) return error(seg_error); break; + case '-': -//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 + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + // Since subtracting an int to a fp value promotes it to a fp + // value, we don't care whether it's first or second; we cast to to + // a double regardless. + if (attr == FLOAT) { - // 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; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *(double *)sval = fpval1 - fpval2; } else { - *sval -= sval[1]; // Compute value + *sval -= sval[1]; } -//printf("%i\n", *sval); - + *sattr |= attr; // Inherit FLOAT attribute 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]; @@ -691,26 +724,49 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); *sattr &= ~TDB; break; + // Unary operators only work on ABS items case UNMINUS: -//printf("evexpr(): UNMINUS\n"); if (*sattr & TDB) return error(seg_error); if (*sattr & FLOAT) { - double *dst = (double *)sval; + double * dst = (double *)sval; *dst = -*dst; *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute } else { - *sval = -(int)*sval; + *sval = -(int64_t)*sval; *sattr = ABS | DEFINED; // Expr becomes absolute } + + break; + + case UNLT: // Unary < (get the low byte of a word) + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error(noflt_error); + + *sval = (int64_t)((*sval) & 0x00FF); + *sattr = ABS | DEFINED; // Expr becomes absolute + break; + + case UNGT: // Unary > (get the high byte of a word) + if (*sattr & TDB) + return error(seg_error); + + if (*sattr & FLOAT) + return error(noflt_error); + + *sval = (int64_t)(((*sval) >> 8) & 0x00FF); + *sattr = ABS | DEFINED; // Expr becomes absolute break; + case '!': -//printf("evexpr(): !\n"); if (*sattr & TDB) return error(seg_error); @@ -720,8 +776,8 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); *sval = !*sval; *sattr = ABS | DEFINED; // Expr becomes absolute break; + case '~': -//printf("evexpr(): ~\n"); if (*sattr & TDB) return error(seg_error); @@ -731,344 +787,243 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); *sval = ~*sval; *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. case LE: -//printf("evexpr(): LE\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // 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; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 <= fpval2); } else { - *sval = *sval <= sval[1]; + *sval = (*sval <= sval[1]); } *sattr = ABS | DEFINED; break; + case GE: -//printf("evexpr(): GE\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - 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) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // Int >= Float - uint64_t * dst = (uint64_t *)sval; - double * src = (double *)(sval + 1); - *sval = *dst >= *src; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 >= fpval2); } - else if (attr == 0) + else { - *sval = *sval >= sval[1]; + *sval = (*sval >= sval[1]); } - else - *sattr = ABS | DEFINED; + *sattr = ABS | DEFINED; break; + case '>': -//printf("evexpr(): >\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // 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; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 > fpval2); } else { - *sval = *sval > sval[1]; + *sval = (*sval > sval[1]); } *sattr = ABS | DEFINED; - break; + case '<': -//printf("evexpr(): <\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // 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; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 < fpval2); } else { - *sval = *sval < sval[1]; + *sval = (*sval < sval[1]); } - *sattr = ABS | DEFINED; - + *sattr = ABS | DEFINED; // Expr forced to ABS break; + case NE: -//printf("evexpr(): NE\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - 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) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // Int != Float - return error("comparison for equality with float types not allowed."); + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 != fpval2); } else { - *sval = *sval != sval[1]; + *sval = (*sval != sval[1]); } - *sattr = ABS | DEFINED; - + *sattr = ABS | DEFINED; // Expr forced to ABS break; + case '=': -//printf("evexpr(): =\n"); sattr--; sval--; if ((*sattr & TDB) != (sattr[1] & TDB)) 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); + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - 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) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + if (attr == FLOAT) { - // Int == Float - uint64_t * dst = (uint64_t *)sval; - double * src = (double *)(sval + 1); - *sval = *src == *dst; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *sval = (fpval1 == fpval2); } else { - *sval = *sval == sval[1]; + *sval = (*sval == sval[1]); } - *sattr = ABS | DEFINED; + *sattr = ABS | DEFINED; // Expr forced to ABS break; + // All other binary operators must have two ABS items to work with. // They all produce an ABS value. + // Shamus: Is this true? There's at least one counterexample of legit + // code where this assumption fails to produce correct code. 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); switch ((int)tk.u32[-1]) { case '*': 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 + sattr--; + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & 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) + // Since multiplying an int to a fp value promotes it to a fp + // value, we don't care whether it's first or second; it will + // be cast to a double regardless. +/* +An open question here is do we promote ints to floats as signed or unsigned? It makes a difference if, say, the int is put in as -1 but is promoted to a double as $FFFFFFFFFFFFFFFF--you get very different results that way! For now, we promote as signed until proven detrimental otherwise. +*/ + if (attr == FLOAT) { - // Int * Float - uint64_t * dst = (uint64_t *)sval; - double * src = (double *)(sval + 1); - *(double *)dst = *src * *dst; + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); + *(double *)sval = fpval1 * fpval2; } else { *sval *= sval[1]; } -//printf("%i\n", *sval); - - *sattr = ABS | DEFINED; // Expr becomes absolute - *sattr |= attr2; break; + case '/': sval--; - sattr--; // Pop attrib + sattr--; + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - -//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) + if (attr == FLOAT) { - // Float / Int - double * dst = (double *)sval; - uint64_t * src = (uint64_t *)(sval + 1); + PTR p; + p.u64 = sval; + double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64); + p.u64++; + double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64); - if (*src == 0) + if (fpval2 == 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; + *(double *)sval = fpval1 / fpval2; } 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 @@ -1078,14 +1033,11 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); *sval = (int32_t)sval[0] / (int32_t)sval[1]; } - *sattr = ABS | DEFINED; // Expr becomes absolute - *sattr |= attr2; - -//printf("%i\n", *sval); break; + case '%': sval--; - sattr--; // Pop attrib + sattr--; if ((*sattr | sattr[1]) & FLOAT) return error("floating point numbers not allowed with operator '%'."); @@ -1093,9 +1045,9 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 @@ -1103,9 +1055,9 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 @@ -1113,9 +1065,9 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 @@ -1123,9 +1075,9 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 @@ -1133,21 +1085,22 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 + sattr--; 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 + // Bad operator in expression stream (this should never happen!) + interror(5); } } } @@ -1158,14 +1111,32 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); if (a_esym != NULL) *a_esym = 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; // Copy value + attrib + // Copy value + attrib into return variables *a_value = *sval; + *a_attr = *sattr; return OK; } +// +// Count the # of tokens in the passed in expression +// N.B.: 64-bit constants count as two tokens each +// +uint16_t ExpressionLength(TOKEN * tk) +{ + uint16_t length; + + for(length=0; tk[length]!=ENDEXPR; length++) + { + // Add one to length for 2X tokens, two for 3X tokens + if (tk[length] == SYMBOL) + length++; + else if ((tk[length] == CONST) || (tk[length] == FCONST)) + length += 2; + } + + // Add 1 for ENDEXPR + length++; + + return length; +}