]> Shamusworld >> Repos - rmac/blobdiff - expr.c
Roll back TOKENPTR changes and most of the .u32 changes weren't needed.
[rmac] / expr.c
diff --git a/expr.c b/expr.c
index deeea40a893300bba19bf3b587b18b78ad47a072..20f43cfcb3aace6feb23228e635f8a1cfd5d4dc1 100644 (file)
--- a/expr.c
+++ b/expr.c
@@ -1,9 +1,9 @@
 //
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Reboot's Macro Assembler for all Atari computers
 // EXPR.C - Expression Analyzer
-// Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
-// Source Utilised with the Kind Permission of Landon Dyer
+// Source utilised with the kind permission of Landon Dyer
 //
 
 #include "expr.h"
 #include "symbol.h"
 #include "token.h"
 
-#define DEF_KW                                         // Declare keyword values 
+#define DEF_KW                                         // Declare keyword values
 #include "kwtab.h"                                     // Incl generated keyword tables & defs
 
 // N.B.: The size of tokenClass should be identical to the largest value of
 //       a token; we're assuming 256 but not 100% sure!
 static char tokenClass[256];           // Generated table of token classes
-static VALUE evstk[EVSTACKSIZE];       // Evaluator value stack
+static uint64_t evstk[EVSTACKSIZE];    // Evaluator value stack
 static WORD evattr[EVSTACKSIZE];       // Evaluator attribute stack
 
 // Token-class initialization list
 char itokcl[] = {
        0,                                                              // END
-       CONST, SYMBOL, 0,                               // ID 
+       CONST, FCONST, SYMBOL, 0,               // ID
        '(', '[', '{', 0,                               // OPAR
-       ')', ']', '}', 0,                               // CPAR 
+       ')', ']', '}', 0,                               // CPAR
        CR_DEFINED, CR_REFERENCED,              // SUNARY (special unary)
        CR_STREQ, CR_MACDEF,
-       CR_DATE, CR_TIME, 0,
+       CR_DATE, CR_TIME,
+       CR_ABSCOUNT, 0,
        '!', '~', UNMINUS, 0,                   // UNARY
-       '*', '/', '%', 0,                               // MULT 
-       '+', '-', 0,                                    // ADD 
-       SHL, SHR, 0,                                    // SHIFT 
-       LE, GE, '<', '>', NE, '=', 0,   // REL 
-       '&', 0,                                                 // AND 
-       '^', 0,                                                 // XOR 
-       '|', 0,                                                 // OR 
-       1                                                               // (the end) 
+       '*', '/', '%', 0,                               // MULT
+       '+', '-', 0,                                    // ADD
+       SHL, SHR, 0,                                    // SHIFT
+       LE, GE, '<', '>', NE, '=', 0,   // REL
+       '&', 0,                                                 // AND
+       '^', 0,                                                 // XOR
+       '|', 0,                                                 // OR
+       1                                                               // (the end)
 };
 
 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 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[]
 
 
 //
 // Obtain a string value
 //
-static VALUE str_value(char * p)
+static uint32_t str_value(char * p)
 {
-       VALUE v;
+       uint32_t v;
 
        for(v=0; *p; p++)
                v = (v << 8) | (*p & 0xFF);
@@ -76,18 +77,17 @@ static VALUE str_value(char * p)
 //
 void InitExpression(void)
 {
-       int i;
-       char * p;
-
        // Initialize token-class table (all set to END)
-       for(i=0; i<256; i++)
+       for(int i=0; i<256; i++)
                tokenClass[i] = END;
 
-       for(i=0, p=itokcl; *p!=1; p++)
+       int i = 0;
+
+       for(char * p=itokcl; *p!=1; p++)
        {
                if (*p == 0)
                        i++;
-               else 
+               else
                        tokenClass[(int)(*p)] = (char)i;
        }
 
@@ -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,19 +119,21 @@ 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".
 //
 int expr1(void)
 {
-       int class;
        TOKEN t;
        SYM * sy;
        char * p, * p2;
        WORD w;
        int j;
 
-       class = tokenClass[*tok];
+       int class = tokenClass[*tok];
 
-       if (*tok == '-' || class == UNARY)
+       if (*tok == '-' || *tok == '+' || class == UNARY)
        {
                t = *tok++;
 
@@ -143,28 +143,35 @@ int expr1(void)
                if (t == '-')
                        t = UNMINUS;
 
-               *evalTokenBuffer++ = t;
+               // 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.u32++ = t;
        }
        else if (class == SUNARY)
        {
-               switch ((int)*tok++)
+               switch (*tok++)
                {
+               case CR_ABSCOUNT:
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc;
+                       break;
                case CR_TIME:
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = dos_time();
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = dos_time();
                        break;
                case CR_DATE:
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = dos_date();
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = dos_date();
                        break;
-               case CR_MACDEF:                                    // ^^macdef <macro-name>
+               case CR_MACDEF: // ^^macdef <macro-name>
                        if (*tok++ != SYMBOL)
                                return error(missym_error);
 
                        p = string[*tok++];
                        w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = (TOKEN)w;
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = (uint64_t)w;
                        break;
                case CR_DEFINED:
                        w = DEFINED;
@@ -178,8 +185,8 @@ getsym:
                        p = string[*tok++];
                        j = (*p == '.' ? curenv : 0);
                        w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = (TOKEN)w;
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = (uint64_t)w;
                        break;
                case CR_STREQ:
                        if (*tok != SYMBOL && *tok != STRING)
@@ -194,16 +201,16 @@ getsym:
                        if (*tok != SYMBOL && *tok != STRING)
                                return error(str_error);
 
-                       p = string[tok[1]];
+                       p2 = string[tok[1]];
                        tok += 2;
 
                        w = (WORD)(!strcmp(p, p2));
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = (TOKEN)w;
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = (uint64_t)w;
                        break;
                }
        }
-       else 
+       else
                return expr2();
 
        return OK;
@@ -218,12 +225,16 @@ int expr2(void)
        char * p;
        SYM * sy;
        int j;
+       PTR ptk;
 
-       switch ((int)*tok++)
+       switch (*tok++)
        {
        case CONST:
-               *evalTokenBuffer++ = CONST;
-               *evalTokenBuffer++ = *tok++;
+       case FCONST:
+               ptk.u32 = tok;
+               *evalTokenBuffer.u32++ = CONST;
+               *evalTokenBuffer.u64++ = *ptk.u64++;
+               tok = ptk.u32;
                break;
        case SYMBOL:
                p = string[*tok++];
@@ -236,28 +247,28 @@ int expr2(void)
                // Check register bank usage
                if (sy->sattre & EQUATEDREG)
                {
-                       if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
-                               warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
+                       if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
+                               warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
 
                        if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
-                               warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
+                               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;
-               *evalTokenBuffer++ = str_value(string[*tok++]);
+               *evalTokenBuffer.u32++ = CONST;
+               *evalTokenBuffer.u64++ = str_value(string[*tok++]);
                break;
        case '(':
                if (expr0() != OK)
                        return ERROR;
 
                if (*tok++ != ')')
-                       return error("missing close parenthesis ')'");
+                       return error("missing closing parenthesis ')'");
 
                break;
        case '[':
@@ -265,20 +276,35 @@ int expr2(void)
                        return ERROR;
 
                if (*tok++ != ']')
-                       return error("missing close parenthesis ']'");
+                       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++ = ACONST;                            // Attributed const
-               *evalTokenBuffer++ = sloc;                                      // Current location
-               *evalTokenBuffer++ = cursect | DEFINED;         // Store attribs
+               *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
+               *evalTokenBuffer.u32++ = sloc;                          // Current location
+               *evalTokenBuffer.u32++ = cursect | DEFINED;     // Store attribs
                break;
        case '*':
-               *evalTokenBuffer++ = ACONST;                            // Attributed const
+               *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
 
                // pcloc == location at start of line
-               *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
-               *evalTokenBuffer++ = ABS | DEFINED;                     // Store attribs
+               *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
+               // '*' takes attributes of current section, not ABS!
+               *evalTokenBuffer.u32++ = cursect | DEFINED;
                break;
        default:
                return error("bad expression");
@@ -291,7 +317,7 @@ int expr2(void)
 //
 // Recursive-descent expression analyzer (with some simple speed hacks)
 //
-int expr(TOKEN * otk, VALUE * 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
@@ -300,9 +326,11 @@ int expr(TOKEN * otk, VALUE * 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)
-                                                       // Also set in various other places too (riscasm.c, e.g.)
+       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[0], tok[1], tok[2], tok[0], tok[1], tok[2], tokenClass[tok[2]]);
        // Optimize for single constant or single symbol.
@@ -310,15 +338,32 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
        //         followed by the value 101, it will trigger a bad evaluation here.
        //         This is probably a really bad assumption to be making here...!
        //         (assuming tok[1] == EOL is a single token that is)
+       //         Seems that even other tokens (SUNARY type) can fuck this up too.
+#if 0
 //     if ((tok[1] == EOL)
-       if ((tok[1] == EOL && tok[0] != CONST)
-               || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
-               && (tokenClass[tok[2]] < UNARY)))
+       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[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;
-                       *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
+                       *evalTokenBuffer.u32++ = CONST;
+                       *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
                        *a_attr = ABS | DEFINED;
 
                        if (a_esym != NULL)
@@ -328,26 +373,45 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                }
                else if (*tok == CONST)
                {
-                       *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = *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;
+
+//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.u32++ = *tok++;
+                       *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
+                       *a_attr = ABS | DEFINED | FLOAT;
 
                        if (a_esym != NULL)
                                *a_esym = NULL;
 
-                       tok += 2;
 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
                }
+#endif
                else if (*tok == '*')
                {
-                       *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer.u32++ = CONST;
 
                        if (orgactive)
-                               *evalTokenBuffer++ = *a_value = orgaddr;
+                               *evalTokenBuffer.u64++ = *a_value = orgaddr;
                        else
-                               *evalTokenBuffer++ = *a_value = pcloc;
+                               *evalTokenBuffer.u64++ = *a_value = pcloc;
 
-                       *a_attr = ABS | DEFINED;
+                       // '*' takes attributes of current section, not ABS!
+                       *a_attr = cursect | DEFINED;
 
                        if (a_esym != NULL)
                                *a_esym = NULL;
@@ -376,7 +440,7 @@ if (symbol)
                        // means it will be fixed up later, and thus, not an error.
                        if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
                        {
-                               errors("undefined register equate '%s'", symbol->sname);
+                               error("undefined register equate '%s'", symbol->sname);
 //if we return right away, it returns some spurious errors...
 //                             return ERROR;
                        }
@@ -384,14 +448,14 @@ if (symbol)
                        // Check register bank usage
                        if (symbol->sattre & EQUATEDREG)
                        {
-                               if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)   
-                                       warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
+                               if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
+                                       warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
 
                                if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
-                                       warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
+                                       warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
                        }
 
-                       *evalTokenBuffer++ = SYMBOL;
+                       *evalTokenBuffer.u32++ = SYMBOL;
 #if 0
                        *evalTokenBuffer++ = (TOKEN)symbol;
 #else
@@ -400,7 +464,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
@@ -414,11 +478,13 @@ be converted from a linked list into an array).
 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) 
+                       if (symbol->sattre & EQUATEDREG)
                                *a_value &= 0x1F;
+
                        *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
 
-                       if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
+                       if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
+                               && a_esym != NULL)
                                *a_esym = symbol;
 
                        tok += 2;
@@ -432,14 +498,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);
 }
 
@@ -448,30 +514,27 @@ 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, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
+int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
 {
-       WORD * sattr;
-       VALUE * sval;
-       WORD attr;
+       WORD attr, attr2;
        SYM * sy;
-       SYM * esym;
-       WORD sym_seg;
-
-       sval = evstk;                                                   // (Empty) initial stack
-       sattr = evattr;
-       esym = NULL;                                                    // No external symbol involved
-       sym_seg = 0;
-
-       while (*tk != ENDEXPR)
+       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)
        {
-               switch ((int)*tk++)
+               switch ((int)*tk.u32++)
                {
                case SYMBOL:
 //printf("evexpr(): SYMBOL\n");
-                       sy = symbolPtr[*tk++];
-                       sy->sattr |= REFERENCED;                // Set "referenced" bit 
+                       sy = symbolPtr[*tk.u32++];
+                       sy->sattr |= REFERENCED;                // Set "referenced" bit
 
                        if (!(sy->sattr & DEFINED))
                        {
@@ -495,86 +558,170 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        }
                        else
                        {
-                               *++sval = 0;                            // 0 for undefined symbols 
+                               *++sval = 0;                            // 0 for undefined symbols
                        }
 
                        *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
-                       sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
+                       sym_seg = (WORD)(sy->sattr & TDB);
                        break;
                case CONST:
-//printf("evexpr(): CONST = %i\n", *tk);
-                       *++sval = *tk++;                                // Push value
+                       *++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);
-                       *++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:
-                       // 
+                       //
                        //                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 
-                       *sval += sval[1];                               // Compute 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 & (TEXT | DATA | BSS)))
-                               *sattr = sattr[1];
-                       else if (sattr[1] & (TEXT | DATA | BSS))
+                       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 
-                       *sval -= sval[1];                               // Compute 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
+                       }
 
-                       attr = (WORD)(*sattr & (TEXT | DATA | BSS));
+//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];
-                       else if (sattr[1] & (TEXT | DATA | BSS))
-                       {
-                               if (!(attr & sattr[1]))
-                                       return error(seg_error);
-                               else
-                                       *sattr &= ~(TEXT | DATA | BSS);
-                       }
+                       // 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 & (TEXT | DATA | BSS))
-                               error(seg_error);
+                       if (*sattr & TDB)
+                               return error(seg_error);
 
-                       *sval = -(int)*sval;
-                       *sattr = ABS | DEFINED;                 // Expr becomes absolute
+                       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 & (TEXT | DATA | BSS))
-                               error(seg_error);
+                       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 & (TEXT | DATA | BSS))
-                               error(seg_error);
+                       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
@@ -583,127 +730,415 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                // are in the same segment, but that's the only requirement.
                case LE:
 //printf("evexpr(): LE\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
-                       *sval = *sval <= sval[1];
                        break;
                case GE:
 //printf("evexpr(): GE\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
 
-                       *sattr = ABS | DEFINED;
-                       *sval = *sval >= sval[1];
                        break;
                case '>':
 //printf("evexpr(): >\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
-                       *sval = *sval > sval[1];
+
                        break;
                case '<':
 //printf("evexpr(): <\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
-                       *sval = *sval < sval[1];
+
                        break;
                case NE:
 //printf("evexpr(): NE\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
-                       *sval = *sval != sval[1];
+
                        break;
                case '=':
 //printf("evexpr(): =\n");
-                       --sattr;
-                       --sval;
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
-                               error(seg_error);
+                               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;
-                       *sval = *sval == sval[1];
+
                        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);
-                       *sattr = ABS | DEFINED;                 // Expr becomes absolute
 
-                       switch ((int)tk[-1])
+                       switch ((int)tk.u32[-1])
                        {
                        case '*':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
-                               *sval *= sval[1];
+                               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 
+                               sval--;
+                               sattr--;                                        // Pop attrib
 
-                               if (sval[1] == 0)
-                                       return error("divide by zero");
 
-                               *sval /= sval[1];
+//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 
+                               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 
+                               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 
+                               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 
+                               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 
+                               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 
+                               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:
@@ -721,7 +1156,7 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_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 | sym_seg;           // Copy value + attrib
 
        *a_attr = *sattr;                                               // Copy value + attrib
        *a_value = *sval;