X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=expr.c;h=1d6ce38a5b9e581ef705960b1083e3e56b44f36e;hp=a0f6f9f49494d8ea96f55aee4a6f831ba50a348e;hb=9153334781cd2e23750f4dc002e847606c07a1f0;hpb=582df8950c285e1746d0c4a9e3ead6545c962dc8 diff --git a/expr.c b/expr.c index a0f6f9f..1d6ce38 100644 --- a/expr.c +++ b/expr.c @@ -1,7 +1,7 @@ // // RMAC - Reboot's 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-2018 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 // Source utilised with the kind permission of Landon Dyer // @@ -51,11 +51,11 @@ const char missym_error[] = "missing symbol"; const char str_error[] = "missing symbol or string"; // Convert expression to postfix -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[] +static PTR 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[] // @@ -100,19 +100,17 @@ void InitExpression(void) // int expr0(void) { - TOKEN t; - if (expr1() != OK) return ERROR; while (tokenClass[*tok] >= MULT) { - t = *tok++; + TOKEN t = *tok++; if (expr1() != OK) return ERROR; - *evalTokenBuffer++ = t; + *evalTokenBuffer.u32++ = t; } return OK; @@ -121,21 +119,19 @@ 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". +// 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) { - int class; TOKEN t; SYM * sy; char * p, * p2; WORD w; int j; - uint64_t * evalTokenBuffer64; - class = tokenClass[*tok]; + int class = tokenClass[*tok]; if (*tok == '-' || *tok == '+' || class == UNARY) { @@ -147,44 +143,35 @@ int expr1(void) if (t == '-') t = UNMINUS; - // 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 + // 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; + *evalTokenBuffer.u32++ = t; } else if (class == SUNARY) { - switch ((int)*tok++) + switch (*tok++) { case CR_ABSCOUNT: - *evalTokenBuffer++ = CONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = (LONG)sect[ABS].sloc; - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc; break; case CR_TIME: - *evalTokenBuffer++ = CONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = dos_time(); - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = dos_time(); break; case CR_DATE: - *evalTokenBuffer++ = CONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = dos_date(); - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = dos_date(); break; - case CR_MACDEF: // ^^macdef + case CR_MACDEF: // ^^macdef if (*tok++ != SYMBOL) return error(missym_error); 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; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = (uint64_t)w; break; case CR_DEFINED: w = DEFINED; @@ -198,10 +185,8 @@ getsym: 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; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = (uint64_t)w; break; case CR_STREQ: if (*tok != SYMBOL && *tok != STRING) @@ -220,10 +205,8 @@ getsym: tok += 2; w = (WORD)(!strcmp(p, p2)); - *evalTokenBuffer++ = CONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = (TOKEN)w; - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = (uint64_t)w; break; } } @@ -242,26 +225,21 @@ int expr2(void) char * p; SYM * sy; int j; - uint64_t * evalTokenBuffer64; - uint64_t * tok64; + PTR ptk; - switch ((int)*tok++) + switch (*tok++) { case CONST: - *evalTokenBuffer++ = CONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - tok64 = (uint64_t *)tok; - *evalTokenBuffer64++ = *tok64++; - tok = (TOKEN *)tok64; - evalTokenBuffer = (TOKEN *)evalTokenBuffer64; + ptk.u32 = tok; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = *ptk.u64++; + tok = ptk.u32; break; case FCONST: - *evalTokenBuffer++ = FCONST; - evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - tok64 = (uint64_t *)tok; - *evalTokenBuffer64++ = *tok64++; - tok = (TOKEN *)tok64; - evalTokenBuffer = (TOKEN *)evalTokenBuffer64; + ptk.u32 = tok; + *evalTokenBuffer.u32++ = FCONST; + *evalTokenBuffer.u64++ = *ptk.u64++; + tok = ptk.u32; break; case SYMBOL: p = string[*tok++]; @@ -281,16 +259,14 @@ int expr2(void) warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname); } - *evalTokenBuffer++ = SYMBOL; - *evalTokenBuffer++ = symbolNum; + *evalTokenBuffer.u32++ = SYMBOL; + *evalTokenBuffer.u32++ = symbolNum; symbolPtr[symbolNum] = sy; symbolNum++; break; case STRING: - *evalTokenBuffer++ = CONST; - uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = str_value(string[*tok++]); - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = str_value(string[*tok++]); break; case '(': if (expr0() != OK) @@ -307,33 +283,33 @@ int expr2(void) if (*tok++ != ']') return error("missing closing bracket ']'"); - break; - case '$': - *evalTokenBuffer++ = ACONST; // Attributed const - *evalTokenBuffer++ = sloc; // Current location - *evalTokenBuffer++ = cursect | DEFINED; // Store attribs - break; - case '*': - *evalTokenBuffer++ = ACONST; // Attributed const - - // 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) + if (expr0() != OK) // Eat up first parameter (register or immediate) return ERROR; - if (*tok++ != ':') // Demand a ':' there + if (*tok++ != ':') // Demand a ':' there return error("missing colon ':'"); - if (expr0() != OK) // Eat up second parameter (register or immediate) + if (expr0() != OK) // Eat up second parameter (register or immediate) return ERROR; if (*tok++ != '}') return error("missing closing brace '}'"); + break; + case '$': + *evalTokenBuffer.u32++ = ACONST; // Attributed const + *evalTokenBuffer.u32++ = sloc; // Current location + *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs + break; + case '*': + *evalTokenBuffer.u32++ = ACONST; // Attributed const + + // pcloc == location at start of line + *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc); + // '*' takes attributes of current section, not ABS! + *evalTokenBuffer.u32++ = cursect | DEFINED; break; default: return error("bad expression"); @@ -355,8 +331,9 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) SYM * symbol; char * p; int j; + PTR ptk; - evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c) + evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c) // Also set in various other places too (riscasm.c, // e.g.) @@ -367,21 +344,31 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) // 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)) + && (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: + if ((tok[1] == EOL + && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY)) + || (((tok[0] == SYMBOL) + || (tok[0] >= KW_R0 && tok[0] <= KW_R31)) + && (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 { if (*tok >= KW_R0 && *tok <= KW_R31) { - *evalTokenBuffer++ = CONST; - uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - *evalTokenBuffer64++ = *a_value = (*tok - KW_R0); - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u32++ = CONST; + *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0); *a_attr = ABS | DEFINED; if (a_esym != NULL) @@ -391,45 +378,42 @@ int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) } else if (*tok == CONST) { - *evalTokenBuffer++ = CONST; - uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; - uint64_t *tok64 = (uint64_t *)&tok[1]; - *evalTokenBuffer64++ = *tok64++; - evalTokenBuffer = (TOKEN *)evalTokenBuffer64; - *a_value = tok[1]; + ptk.u32 = tok; + *evalTokenBuffer.u32++ = *ptk.u32++; + *evalTokenBuffer.u64++ = *a_value = *ptk.u64++; *a_attr = ABS | DEFINED; + tok = ptk.u32; 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]); } +// Not sure that removing float constant here is going to break anything and/or +// make things significantly slower, but having this here seems to cause the +// complexity of the check to get to this part of the parse to go through the +// roof, and dammit, I just don't feel like fighting that fight ATM. :-P +#if 0 else if (*tok == FCONST) { - *evalTokenBuffer++ = FCONST; - *((double *)evalTokenBuffer) = *((double *)&tok[1]); - evalTokenBuffer += 2; - //*(double *)evalTokenBuffer++ = tok[2]; - *a_value = *((uint64_t *)&tok[1]); + *evalTokenBuffer.u32++ = *tok++; + *evalTokenBuffer.u64++ = *a_value = *tok.u64++; *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]); } +#endif else if (*tok == '*') { - *evalTokenBuffer++ = CONST; - uint64_t *evalTokenBuffer64 = (uint64_t *)evalTokenBuffer; + *evalTokenBuffer.u32++ = CONST; if (orgactive) - *evalTokenBuffer64++ = *a_value = orgaddr; + *evalTokenBuffer.u64++ = *a_value = orgaddr; else - *evalTokenBuffer64++ = *a_value = pcloc; - evalTokenBuffer = (uint32_t *)evalTokenBuffer64; + *evalTokenBuffer.u64++ = *a_value = pcloc; // '*' takes attributes of current section, not ABS! *a_attr = cursect | DEFINED; @@ -476,7 +460,7 @@ if (symbol) warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname); } - *evalTokenBuffer++ = SYMBOL; + *evalTokenBuffer.u32++ = SYMBOL; #if 0 *evalTokenBuffer++ = (TOKEN)symbol; #else @@ -485,7 +469,7 @@ 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; + *evalTokenBuffer.u32++ = symbolNum; symbolPtr[symbolNum] = symbol; symbolNum++; #endif @@ -519,14 +503,14 @@ thrown away right here. What the hell is it for? return ERROR; } - *evalTokenBuffer++ = ENDEXPR; + *evalTokenBuffer.u32++ = ENDEXPR; return OK; } if (expr0() != OK) return ERROR; - *evalTokenBuffer++ = ENDEXPR; + *evalTokenBuffer.u32++ = ENDEXPR; return evexpr(otk, a_value, a_attr, a_esym); } @@ -535,9 +519,9 @@ thrown away right here. What the hell is it for? // 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 -// `a_esym' is set to the external symbol. +// 'a_esym' is set to the external symbol. // -int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) +int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) { WORD attr, attr2; SYM * sy; @@ -545,15 +529,16 @@ int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym) WORD * sattr = evattr; SYM * esym = NULL; // No external symbol involved WORD sym_seg = 0; - uint64_t *tk64; + PTR tk; + tk.u32 = _tk; - while (*tk != ENDEXPR) + while (*tk.u32 != ENDEXPR) { - switch ((int)*tk++) + switch ((int)*tk.u32++) { case SYMBOL: //printf("evexpr(): SYMBOL\n"); - sy = symbolPtr[*tk++]; + sy = symbolPtr[*tk.u32++]; sy->sattr |= REFERENCED; // Set "referenced" bit if (!(sy->sattr & DEFINED)) @@ -573,34 +558,32 @@ 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: - tk64 = (uint64_t *)tk; - *++sval = *tk64++; - tk = (TOKEN *)tk64; + *++sval = *tk.u64++; //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; +//printf("evexpr(): FCONST = %lf\n", *tk.dp); + // 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); - *++sval = *tk++; // Push value - *++sattr = (WORD)*tk++; // Push attribs +//printf("evexpr(): ACONST = %i\n", *tk.u32); + *++sval = *tk.u32++; // Push value + *++sattr = (WORD)*tk.u32++; // Push attribs break; // Binary "+" and "-" matrix: @@ -614,92 +597,71 @@ 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 + *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))) - { - // 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 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) { - // 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]; @@ -708,6 +670,7 @@ 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"); @@ -716,16 +679,18 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); if (*sattr & FLOAT) { - double *dst = (double *)sval; + double * dst = (double *)sval; *dst = -*dst; *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute } else { - *sval = -(int)*sval; - *sattr = ABS | DEFINED; // Expr becomes absolute + *sval = -(int64_t)*sval; + *sattr = ABS | DEFINED; // Expr becomes absolute } + break; + case '!': //printf("evexpr(): !\n"); if (*sattr & TDB) @@ -737,6 +702,7 @@ 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) @@ -748,6 +714,7 @@ 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: @@ -758,38 +725,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 { - *sval = *sval <= sval[1]; + *sval = (*sval <= sval[1]); } *sattr = ABS | DEFINED; break; + case GE: //printf("evexpr(): GE\n"); sattr--; @@ -798,40 +755,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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; + 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 == 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) + else { - *sval = *sval >= sval[1]; + *sval = (*sval >= sval[1]); } - else *sattr = ABS | DEFINED; - break; + case '>': //printf("evexpr(): >\n"); sattr--; @@ -840,39 +785,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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 -= { - *sval = *sval > sval[1]; + { + *sval = (*sval > sval[1]); } *sattr = ABS | DEFINED; - break; + case '<': //printf("evexpr(): <\n"); sattr--; @@ -881,39 +815,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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) + // Cast any ints in the comparison to double, if there's at least + // one double in the comparison. + 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--; @@ -922,33 +845,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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--; @@ -957,196 +875,180 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]); 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. + + // 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); - switch ((int)tk[-1]) + switch ((int)tk.u32[-1]) { case '*': sval--; - sattr--; // Pop attrib + sattr--; //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 + // 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]; + *sval *= sval[1]; } //printf("%i\n", *sval); - *sattr = ABS | DEFINED; // Expr becomes absolute - *sattr |= attr2; - + *sattr = ABS | DEFINED | attr; // Expr becomes absolute break; + case '/': sval--; - sattr--; // Pop attrib - - + sattr--; //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 + // Get FLOAT attribute, if any + attr = (sattr[0] | sattr[1]) & FLOAT; - if (attr == (FLOAT | (FLOAT >> 1))) + if (attr == FLOAT) { - // 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) + 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 (fpval2 == 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 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]; - } - - *sattr = ABS | DEFINED; // Expr becomes absolute - *sattr |= attr2; + // 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]; + } //printf("%i\n", *sval); + + *sattr = ABS | DEFINED | attr; // Expr becomes absolute break; + case '%': sval--; - sattr--; // Pop attrib + sattr--; + 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute break; + case SHL: 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute break; + case SHR: 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute break; + case '&': 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute break; + case '^': 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute 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]; + *sattr = ABS | DEFINED; // Expr becomes absolute break; + default: - interror(5); // Bad operator in expression stream + // Bad operator in expression stream (this should never happen!) + interror(5); } } } @@ -1157,14 +1059,34 @@ 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; +} +