+ *++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;
+ *++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;
+
+ // Binary "+" and "-" matrix:
+ //
+ // ABS Sect Other
+ // ----------------------------
+ // ABS | ABS | Sect | Other |
+ // Sect | Sect | [1] | Error |
+ // Other | Other | Error | [1] |
+ // ----------------------------
+ //
+ // [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
+
+ 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 & TDB))
+ *sattr = sattr[1] | attr2;
+ 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
+
+ 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
+ }
+
+//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];
+ // 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
+ case UNMINUS:
+//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
+ }
+ break;
+ case '!':
+//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
+ break;
+ case '~':
+//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
+ 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);
+
+ 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:
+//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);
+
+ 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 '>':
+//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);
+
+ 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 '<':
+//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);
+
+ 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:
+//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);
+
+ 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 '=':
+//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);
+
+ 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.
+ 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
+
+ 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
+
+
+//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];
+ }
+
+ *sattr = ABS | DEFINED; // Expr becomes absolute
+ *sattr |= attr2;
+
+//printf("%i\n", *sval);
+ break;
+ case '%':
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+
+ 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
+ }
+ }
+ }
+
+ if (esym != NULL)
+ *sattr &= ~DEFINED;
+
+ 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
+ *a_value = *sval;
+
+ return OK;
+}