]> Shamusworld >> Repos - rmac/blobdiff - expr.c
Fix a small buglet in the last patch. :-)
[rmac] / expr.c
diff --git a/expr.c b/expr.c
index 3529f29613f2e8f9cec978514838a306ed238731..f31e9e59ddf67c1be317af23a1428c22da4ee534 100644 (file)
--- 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-2020 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,13 +49,14 @@ 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 TOKENPTR 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,14 +101,12 @@ void InitExpression(void)
 //
 int expr0(void)
 {
-       TOKEN t;
-
        if (expr1() != OK)
                return ERROR;
 
-       while (tokenClass[*tok.u32] >= MULT)
+       while (tokenClass[*tok] >= MULT)
        {
-               t = *tok.u32++;
+               TOKEN t = *tok++;
 
                if (expr1() != OK)
                        return ERROR;
@@ -127,24 +126,24 @@ int expr0(void)
 //
 int expr1(void)
 {
-       int class;
-       TOKEN t;
-       SYM * sy;
-       char * p, * p2;
+       char * p;
        WORD w;
-       int j;
 
-       class = tokenClass[*tok.u32];
+       int class = tokenClass[*tok];
 
-       if (*tok.u32 == '-' || *tok.u32 == '+' || class == UNARY)
+       if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY)
        {
-               t = *tok.u32++;
+               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,11 +152,57 @@ int expr1(void)
        }
        else if (class == SUNARY)
        {
-               switch (*tok.u32++)
+               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[1]]);
+                       }
+
+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;
@@ -168,10 +213,10 @@ int expr1(void)
                        *evalTokenBuffer.u64++ = dos_date();
                        break;
                case CR_MACDEF: // ^^macdef <macro-name>
-                       if (*tok.u32++ != SYMBOL)
+                       if (*tok++ != SYMBOL)
                                return error(missym_error);
 
-                       p = string[*tok.u32++];
+                       p = string[*tok++];
                        w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
                        *evalTokenBuffer.u32++ = CONST;
                        *evalTokenBuffer.u64++ = (uint64_t)w;
@@ -182,30 +227,31 @@ int expr1(void)
                case CR_REFERENCED:
                        w = REFERENCED;
 getsym:
-                       if (*tok.u32++ != SYMBOL)
+                       if (*tok++ != SYMBOL)
                                return error(missym_error);
 
-                       p = string[*tok.u32++];
-                       j = (*p == '.' ? curenv : 0);
-                       w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
+                       p = string[*tok++];
+                       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;
                case CR_STREQ:
-                       if (*tok.u32 != SYMBOL && *tok.u32 != STRING)
+                       if (*tok != SYMBOL && *tok != STRING)
                                return error(str_error);
 
-                       p = string[tok.u32[1]];
-                       tok.u32 +=2;
+                       p = string[tok[1]];
+                       tok +=2;
 
-                       if (*tok.u32++ != ',')
+                       if (*tok++ != ',')
                                return error(comma_error);
 
-                       if (*tok.u32 != SYMBOL && *tok.u32 != STRING)
+                       if (*tok != SYMBOL && *tok != STRING)
                                return error(str_error);
 
-                       p2 = string[tok.u32[1]];
-                       tok.u32 += 2;
+                       char * p2 = string[tok[1]];
+                       tok += 2;
 
                        w = (WORD)(!strcmp(p, p2));
                        *evalTokenBuffer.u32++ = CONST;
@@ -225,24 +271,27 @@ getsym:
 //
 int expr2(void)
 {
-       char * p;
-       SYM * sy;
-       int j;
+       PTR ptk;
 
-       switch (*tok.u32++)
+       switch (*tok++)
        {
        case CONST:
+               ptk.u32 = tok;
                *evalTokenBuffer.u32++ = CONST;
-               *evalTokenBuffer.u64++ = *tok.u64++;
+               *evalTokenBuffer.u64++ = *ptk.u64++;
+               tok = ptk.u32;
                break;
        case FCONST:
+               ptk.u32 = tok;
                *evalTokenBuffer.u32++ = FCONST;
-               *evalTokenBuffer.u64++ =  *tok.u64++;
+               *evalTokenBuffer.u64++ = *ptk.u64++;
+               tok = ptk.u32;
                break;
        case SYMBOL:
-               p = string[*tok.u32++];
-               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);
@@ -262,15 +311,16 @@ int expr2(void)
                symbolPtr[symbolNum] = sy;
                symbolNum++;
                break;
+       }
        case STRING:
                *evalTokenBuffer.u32++ = CONST;
-               *evalTokenBuffer.u64++ = str_value(string[*tok.u32++]);
+               *evalTokenBuffer.u64++ = str_value(string[*tok++]);
                break;
        case '(':
                if (expr0() != OK)
                        return ERROR;
 
-               if (*tok.u32++ != ')')
+               if (*tok++ != ')')
                        return error("missing closing parenthesis ')'");
 
                break;
@@ -278,9 +328,23 @@ int expr2(void)
                if (expr0() != OK)
                        return ERROR;
 
-               if (*tok.u32++ != ']')
+               if (*tok++ != ']')
                        return error("missing closing bracket ']'");
 
+               break;
+       case '{':
+               if (expr0() != OK)      // Eat up first parameter (register or immediate)
+                       return ERROR;
+
+               if (*tok++ != ':')      // Demand a ':' there
+                       return error("missing colon ':'");
+
+               if (expr0() != OK)      // Eat up second parameter (register or immediate)
+                       return ERROR;
+
+               if (*tok++ != '}')
+                       return error("missing closing brace '}'");
+
                break;
        case '$':
                *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
@@ -294,20 +358,6 @@ int expr2(void)
                *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
                // '*' takes attributes of current section, not ABS!
                *evalTokenBuffer.u32++ = cursect | DEFINED;
-               break;
-       case '{':
-               if (expr0() != OK)                                                      // Eat up first parameter (register or immediate)
-                       return ERROR;
-
-               if (*tok.u32++ != ':')                                          // Demand a ':' there
-                       return error("missing colon ':'");
-
-               if (expr0() != OK)                                                      // Eat up second parameter (register or immediate)
-                       return ERROR;
-
-               if (*tok.u32++ != '}')
-                       return error("missing closing brace '}'");
-
                break;
        default:
                return error("bad expression");
@@ -320,7 +370,7 @@ int expr2(void)
 //
 // Recursive-descent expression analyzer (with some simple speed hacks)
 //
-int expr(TOKENPTR otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
+int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
 {
        // Passed in values (once derefenced, that is) can all be zero. They are
        // there so that the expression analyzer can fill them in as needed. The
@@ -329,79 +379,82 @@ int expr(TOKENPTR 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.)
 
-//printf("expr(): tokens 0-2: %i %i %i (%c %c %c); tc[2] = %i\n", tok.u32[0], tok.u32[1], tok.u32[2], tok.u32[0], tok.u32[1], tok.u32[2], tokenClass[tok.u32[2]]);
+//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.u32[1] == EOL is a single token that is)
+       //         (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.u32[1] == EOL)
-       if ((tok.u32[1] == EOL && ((tok.u32[0] != CONST || tok.u32[0] != FCONST) && tokenClass[tok.u32[0]] != SUNARY))
-//             || (((*tok.u32 == CONST || *tok.u32 == FCONST || *tok.u32 == SYMBOL) || (*tok.u32 >= KW_R0 && *tok.u32 <= KW_R31))
-//             && (tokenClass[tok.u32[2]] < UNARY)))
-               || (((tok.u32[0] == SYMBOL) || (tok.u32[0] >= KW_R0 && tok.u32[0] <= KW_R31))
-                       && (tokenClass[tok.u32[2]] < UNARY))
-               || ((tok.u32[0] == CONST || tok.u32[0] == FCONST) && (tokenClass[tok.u32[3]] < UNARY))
+//     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:
-       if ((tok.u32[1] == EOL
-                       && (tok.u32[0] != CONST && tokenClass[tok.u32[0]] != SUNARY))
-               || (((tok.u32[0] == SYMBOL)
-                               || (tok.u32[0] >= KW_R0 && tok.u32[0] <= KW_R31))
-                       && (tokenClass[tok.u32[2]] < UNARY))
-               || ((tok.u32[0] == CONST) && (tokenClass[tok.u32[3]] < UNARY))
+       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.u32[1] for an EOL. O_o
+// 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.u32 >= KW_R0 && *tok.u32 <= KW_R31)
+               if (*tok >= KW_R0 && *tok <= KW_R31)
                {
                        *evalTokenBuffer.u32++ = CONST;
-                       *evalTokenBuffer.u64++ = *a_value = (*tok.u32 - KW_R0);
-                       *a_attr = ABS | DEFINED;
+                       *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
+                       *a_attr = ABS | DEFINED | RISCREG;
 
                        if (a_esym != NULL)
                                *a_esym = NULL;
 
-                       tok.u32++;
+                       tok++;
                }
-               else if (*tok.u32 == CONST)
+               else if (*tok == CONST)
                {
-                       *evalTokenBuffer.u32++ = *tok.u32++;
-                       *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
+                       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;
 
-//printf("Quick eval in expr(): CONST = %i, tokenClass[tok.u32[2]] = %i\n", *a_value, tokenClass[*tok.u32]);
+//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.u32 == FCONST)
+               else if (*tok == FCONST)
                {
-                       *evalTokenBuffer.u32++ = *tok.u32++;
+                       *evalTokenBuffer.u32++ = *tok++;
                        *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
                        *a_attr = ABS | DEFINED | FLOAT;
 
                        if (a_esym != NULL)
                                *a_esym = NULL;
 
-//printf("Quick eval in expr(): CONST = %i, tokenClass[tok.u32[2]] = %i\n", *a_value, tokenClass[*tok.u32]);
+//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
                }
 #endif
-               else if (*tok.u32 == '*')
+               else if (*tok == '*')
                {
                        *evalTokenBuffer.u32++ = CONST;
 
@@ -416,11 +469,11 @@ int expr(TOKENPTR otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
                        if (a_esym != NULL)
                                *a_esym = NULL;
 
-                       tok.u32++;
+                       tok++;
                }
-               else if (*tok.u32 == STRING || *tok.u32 == SYMBOL)
+               else if (*tok == STRING || *tok == SYMBOL)
                {
-                       p = string[tok.u32[1]];
+                       p = string[tok[1]];
                        j = (*p == '.' ? curenv : 0);
                        symbol = lookup(p, LABEL, j);
 #if 0
@@ -469,32 +522,37 @@ 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)
                                *a_esym = symbol;
 
-                       tok.u32 += 2;
+                       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.u32++;
+                       tok++;
                        return ERROR;
                }
 
@@ -516,14 +574,16 @@ thrown away right here. What the hell is it for?
 // UNDEFINED, but it's value includes everything but the symbol value, and
 // 'a_esym' is set to the external symbol.
 //
-int evexpr(TOKENPTR 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;
+       WORD attr;
        SYM * sy;
        uint64_t * sval = evstk;                                // (Empty) initial stack
        WORD * sattr = evattr;
        SYM * esym = NULL;                                              // No external symbol involved
        WORD sym_seg = 0;
+       PTR tk;
+       tk.u32 = _tk;
 
        while (*tk.u32 != ENDEXPR)
        {
@@ -551,28 +611,28 @@ int evexpr(TOKENPTR 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;
+//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.u32);
                        *++sval = *tk.u32++;                            // Push value
@@ -590,36 +650,26 @@ int evexpr(TOKENPTR 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
                        {
@@ -628,54 +678,43 @@ int evexpr(TOKENPTR tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
 //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)
+                       // 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 - 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];
@@ -684,6 +723,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");
@@ -692,16 +732,42 @@ 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;
+                               *sval = -(int64_t)*sval;
                                *sattr = ABS | DEFINED;                 // Expr becomes absolute
                        }
+
                        break;
+
+               case UNLT: // Unary < (get the low byte of a word)
+//printf("evexpr(): UNLT\n");
+                       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)
+//printf("evexpr(): UNGT\n");
+                       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)
@@ -713,6 +779,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)
@@ -724,6 +791,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:
@@ -734,38 +802,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;
-                       }
-                       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--;
@@ -774,39 +832,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 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--;
@@ -815,39 +862,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;
-                       }
-                       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--;
@@ -856,39 +892,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;
-                       }
-                       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--;
@@ -897,33 +922,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)
+                       // Cast any ints in the comparison to double, if there's at least
+                       // one double in the comparison.
+                       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.");
+                               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--;
@@ -932,76 +952,59 @@ 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.
+               // 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
+                               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
                                {
@@ -1009,53 +1012,28 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
                                }
 //printf("%i\n", *sval);
 
-                               *sattr = ABS | DEFINED;                 // Expr becomes absolute
-                               *sattr |= attr2;
-
+//no                           *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
-
-                               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);
+                               // Get FLOAT attribute, if any
+                               attr = (sattr[0] | sattr[1]) & FLOAT;
 
-                                       if (*src == 0)
-                                               return error("divide by zero");
-
-                                       *dst = *dst / *src;
-                               }
-                               else if (attr == FLOAT >> 1)
+                               if (attr == FLOAT)
                                {
-                                       // Int / Float
-                                       uint64_t * dst=(uint64_t *)sval;
-                                       double * src=(double *)(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");
 
-                                       *(double *)dst = *dst / *src;
+                                       *(double *)sval = fpval1 / fpval2;
                                }
                                else
                                {
@@ -1070,15 +1048,14 @@ printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
                                        // ints.
                                        *sval = (int32_t)sval[0] / (int32_t)sval[1];
                                }
-
-                               *sattr = ABS | DEFINED;                 // Expr becomes absolute
-                               *sattr |= attr2;
-
 //printf("%i\n", *sval);
+
+//no                           *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 '%'.");
@@ -1086,9 +1063,10 @@ 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];
+//no                           *sattr = ABS | DEFINED;                 // Expr becomes absolute
                                break;
+
                        case SHL:
                                sval--;
                                sattr--;                                        // Pop attrib
@@ -1096,9 +1074,10 @@ 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];
+//no                           *sattr = ABS | DEFINED;                 // Expr becomes absolute
                                break;
+
                        case SHR:
                                sval--;
                                sattr--;                                        // Pop attrib
@@ -1106,9 +1085,10 @@ 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];
+//no                           *sattr = ABS | DEFINED;                 // Expr becomes absolute
                                break;
+
                        case '&':
                                sval--;
                                sattr--;                                        // Pop attrib
@@ -1116,9 +1096,10 @@ 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];
+//no                           *sattr = ABS | DEFINED;                 // Expr becomes absolute
                                break;
+
                        case '^':
                                sval--;
                                sattr--;                                        // Pop attrib
@@ -1126,21 +1107,24 @@ 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];
+//no                           *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];
+//no                           *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);
                        }
                }
        }
@@ -1151,14 +1135,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;
+}
+