+ case '+':
+//printf("evexpr(): +\n");
+ --sval; // Pop value
+ --sattr; // Pop attrib
+//printf("--> N+N: %i + %i = ", *sval, sval[1]);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // 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)
+ {
+ 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] | 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]);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // 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)
+ {
+ 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 |= attr; // Inherit FLOAT attribute
+ attr = (WORD)(*sattr & TDB);
+#if 0
+printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
+#endif
+ // 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 = -(int64_t)*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);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *sattr = ABS | DEFINED;
+ break;
+
+ case GE:
+//printf("evexpr(): GE\n");
+ sattr--;
+ sval--;
+
+ if ((*sattr & TDB) != (sattr[1] & TDB))
+ return error(seg_error);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *sattr = ABS | DEFINED;
+ break;
+
+ case '>':
+//printf("evexpr(): >\n");
+ sattr--;
+ sval--;
+
+ if ((*sattr & TDB) != (sattr[1] & TDB))
+ return error(seg_error);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *sattr = ABS | DEFINED;
+ break;
+
+ case '<':
+//printf("evexpr(): <\n");
+ sattr--;
+ sval--;
+
+ if ((*sattr & TDB) != (sattr[1] & TDB))
+ return error(seg_error);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *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);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *sattr = ABS | DEFINED; // Expr forced to ABS
+ break;
+
+ case '=':
+//printf("evexpr(): =\n");
+ sattr--;
+ sval--;
+
+ if ((*sattr & TDB) != (sattr[1] & TDB))
+ return error(seg_error);
+
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // Cast any ints in the comparison to double, if there's at least
+ // one double in the comparison.
+ if (attr == FLOAT)
+ {
+ 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]);
+ }
+
+ *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.
+ 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--;
+//printf("--> NxN: %i x %i = ", *sval, sval[1]);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ // 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)
+ {
+ 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 | attr; // Expr becomes absolute
+ break;
+
+ case '/':
+ sval--;
+ sattr--;
+//printf("--> N/N: %i / %i = ", sval[0], sval[1]);
+ // Get FLOAT attribute, if any
+ attr = (sattr[0] | sattr[1]) & FLOAT;
+
+ if (attr == FLOAT)
+ {
+ 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 *)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];
+ }
+//printf("%i\n", *sval);
+
+ *sattr = ABS | DEFINED | attr; // Expr becomes absolute
+ break;
+
+ case '%':
+ sval--;
+ sattr--;
+
+ if ((*sattr | sattr[1]) & FLOAT)
+ return error("floating point numbers not allowed with operator '%'.");
+
+ if (sval[1] == 0)
+ return error("mod (%) by zero");
+
+ *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 '<<'.");
+
+ *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 '>>'.");
+
+ *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 '&'.");
+
+ *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 '^'.");
+
+ *sval ^= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
+ break;
+
+ case '|':
+ sval--;
+ sattr--;
+
+ if ((*sattr | sattr[1]) & FLOAT)
+ return error("floating point numbers not allowed with operator '|'.");
+
+ *sval |= sval[1];
+ *sattr = ABS | DEFINED; // Expr becomes absolute
+ break;
+
+ default:
+ // Bad operator in expression stream (this should never happen!)
+ interror(5);
+ }
+ }
+ }
+
+ if (esym != NULL)
+ *sattr &= ~DEFINED;
+
+ if (a_esym != NULL)
+ *a_esym = esym;
+
+ // Copy value + attrib into return variables
+ *a_value = *sval;
+ *a_attr = *sattr;
+
+ return OK;
+}