]> Shamusworld >> Repos - rmac/blobdiff - expr.c
Add support for 64-bit evaluations.
[rmac] / expr.c
diff --git a/expr.c b/expr.c
index 31eb89974fb0eab6b6ab40bc0ef99597ad5a53e2..dea1de9c92d679461c90f3778e3257db01d58c7c 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 
-#include "kwtab.h"                                             // Incl generated keyword tables & defs
+#define DEF_KW                                         // Declare keyword values
+#include "kwtab.h"                                     // Incl generated keyword tables & defs
 
-static char tokenClass[128];                                   // Generated table of token classes
-static VALUE evstk[EVSTACKSIZE];               // Evaluator value stack
-static WORD evattr[EVSTACKSIZE];               // Evaluator attribute stack
+// 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 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 
-       '(', '[', '{', 0,                                       // OPAR
-       ')', ']', '}', 0,                                       // CPAR 
-       CR_DEFINED, CR_REFERENCED,                      // SUNARY (special unary)
+       0,                                                              // END
+       CONST, SYMBOL, 0,                               // ID
+       '(', '[', '{', 0,                               // OPAR
+       ')', ']', '}', 0,                               // CPAR
+       CR_DEFINED, CR_REFERENCED,              // SUNARY (special unary)
        CR_STREQ, CR_MACDEF,
-       CR_DATE, CR_TIME, 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) 
+       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)
 };
 
 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 TOKEN * evalTokenBuffer;                // Deposit tokens here (this is really a
+                                                                       // pointer to exprbuf from direct.c)
+                                                                       // (Can also be from others, like
+                                                                       // riscasm.c)
+static int symbolNum;                          // Pointer to the entry in symbolPtr[]
 
 
 //
-// Obtain a String Value
+// 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);
@@ -69,22 +73,21 @@ static VALUE str_value(char * p)
 
 
 //
-// Initialize Expression Analyzer
+// Initialize expression analyzer
 //
 void InitExpression(void)
 {
-       int i;                                                                  // Iterator
-       char * p;                                                               // Token pointer
-
        // Initialize token-class table (all set to END)
-       for(i=0; i<128; 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;
        }
 
@@ -101,7 +104,7 @@ int expr0(void)
 
        if (expr1() != OK)
                return ERROR;
-       
+
        while (tokenClass[*tok] >= MULT)
        {
                t = *tok++;
@@ -118,6 +121,9 @@ 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)
 {
@@ -130,7 +136,7 @@ int expr1(void)
 
        class = tokenClass[*tok];
 
-       if (*tok == '-' || class == UNARY)
+       if (*tok == '-' || *tok == '+' || class == UNARY)
        {
                t = *tok++;
 
@@ -146,12 +152,19 @@ int expr1(void)
        {
                switch ((int)*tok++)
                {
+               case CR_ABSCOUNT:
+                       *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
+                       *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
+                       break;
                case CR_TIME:
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = dos_time();
                        break;
                case CR_DATE:
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = dos_date();
                        break;
                case CR_MACDEF:                                    // ^^macdef <macro-name>
@@ -161,6 +174,7 @@ int expr1(void)
                        p = string[*tok++];
                        w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = (TOKEN)w;
                        break;
                case CR_DEFINED:
@@ -176,6 +190,7 @@ getsym:
                        j = (*p == '.' ? curenv : 0);
                        w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = (TOKEN)w;
                        break;
                case CR_STREQ:
@@ -191,16 +206,17 @@ 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++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = (TOKEN)w;
                        break;
                }
        }
-       else 
+       else
                return expr2();
 
        return OK;
@@ -220,7 +236,8 @@ int expr2(void)
        {
        case CONST:
                *evalTokenBuffer++ = CONST;
-               *evalTokenBuffer++ = *tok++;
+               *evalTokenBuffer++ = *tok++;    // HI LONG of constant
+               *evalTokenBuffer++ = *tok++;    // LO LONG of constant
                break;
        case SYMBOL:
                p = string[*tok++];
@@ -233,24 +250,21 @@ 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;
-#if 0
-               *evalTokenBuffer++ = (TOKEN)sy;
-#else
                *evalTokenBuffer++ = symbolNum;
                symbolPtr[symbolNum] = sy;
                symbolNum++;
-#endif
                break;
        case STRING:
                *evalTokenBuffer++ = CONST;
+               *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                *evalTokenBuffer++ = str_value(string[*tok++]);
                break;
        case '(':
@@ -258,7 +272,7 @@ int expr2(void)
                        return ERROR;
 
                if (*tok++ != ')')
-                       return error("missing close parenthesis ')'");
+                       return error("missing closing parenthesis ')'");
 
                break;
        case '[':
@@ -266,7 +280,7 @@ int expr2(void)
                        return ERROR;
 
                if (*tok++ != ']')
-                       return error("missing close parenthesis ']'");
+                       return error("missing closing bracket ']'");
 
                break;
        case '$':
@@ -277,12 +291,24 @@ int expr2(void)
        case '*':
                *evalTokenBuffer++ = ACONST;                            // Attributed const
 
-               if (orgactive)
-                       *evalTokenBuffer++ = orgaddr;
-               else
-                       *evalTokenBuffer++ = pcloc;                             // Location at start of line
+               // pcloc == location at start of line
+               *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
+               // '*' takes attributes of current section, not ABS!
+               *evalTokenBuffer++ = cursect | DEFINED;
+               break;
+       case '{':
+               if (expr0() != OK)                                                      // Eat up first parameter (register or immediate)
+                       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 '}'");
 
-               *evalTokenBuffer++ = ABS | DEFINED;                     // Store attribs
                break;
        default:
                return error("bad expression");
@@ -295,7 +321,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
@@ -306,16 +332,29 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
        int j;
 
        evalTokenBuffer = otk;  // Set token pointer to 'exprbuf' (direct.c)
-                                                       // Also set in various other places too (riscasm.c, e.g.)
+                                                       // 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.
-       if ((tok[1] == EOL)
-               || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
-               && (tokenClass[tok[2]] < UNARY)))
+       // 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[1] == EOL is a single token that is)
+       //         Seems that even other tokens (SUNARY type) can fuck this up too.
+//     if ((tok[1] == EOL)
+       if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
+//             || (((*tok == CONST || *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) && (tokenClass[tok[3]] < UNARY))
+               )
        {
                if (*tok >= KW_R0 && *tok <= KW_R31)
                {
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
                        *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
                        *a_attr = ABS | DEFINED;
 
@@ -323,49 +362,62 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                                *a_esym = NULL;
 
                        tok++;
-                       *evalTokenBuffer++ = ENDEXPR;
-                       return OK;
                }
                else if (*tok == CONST)
                {
                        *evalTokenBuffer++ = CONST;
-                       *evalTokenBuffer++ = *a_value = tok[1];
+                       *evalTokenBuffer++ = tok[1];
+                       *evalTokenBuffer++ = tok[2];
+                       *a_value = (((uint64_t)tok[1]) << 32) | tok[2];
                        *a_attr = ABS | DEFINED;
 
                        if (a_esym != NULL)
                                *a_esym = NULL;
+
+                       tok += 3;
+//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
                }
                else if (*tok == '*')
                {
                        *evalTokenBuffer++ = CONST;
+                       *evalTokenBuffer++ = 0;         // Set HI LONG to zero
 
                        if (orgactive)
                                *evalTokenBuffer++ = *a_value = orgaddr;
                        else
                                *evalTokenBuffer++ = *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;
 
-                       tok--;
+                       tok++;
                }
-               else
+               else if (*tok == STRING || *tok == SYMBOL)
                {
                        p = string[tok[1]];
                        j = (*p == '.' ? curenv : 0);
                        symbol = lookup(p, LABEL, j);
+#if 0
+printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
+if (symbol)
+       printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
+#endif
 
                        if (symbol == NULL)
                                symbol = NewSymbol(p, LABEL, j);
 
                        symbol->sattr |= REFERENCED;
 
-                       // Check for undefined register equates
-                       if (symbol->sattre & UNDEF_EQUR)
+                       // Check for undefined register equates, but only if it's not part
+                       // of a #<SYMBOL> construct, as it could be that the label that's
+                       // been undefined may later be used as an address label--which
+                       // 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;
                        }
@@ -373,11 +425,11 @@ int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        // 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;
@@ -403,16 +455,26 @@ 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;
+               }
+               else
+               {
+                       // Unknown type here... Alert the user!,
+                       error("undefined RISC register in expression");
+                       // Prevent spurious error reporting...
+                       tok++;
+                       return ERROR;
                }
 
-               tok += 2;
                *evalTokenBuffer++ = ENDEXPR;
                return OK;
        }
@@ -431,28 +493,23 @@ 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(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;
        SYM * sy;
-       SYM * esym;
-       WORD sym_seg;
-
-       sval = evstk;                                                   // (Empty) initial stack
-       sattr = evattr;
-       esym = NULL;                                                    // No external symbol involved
-       sym_seg = 0;
+       uint64_t * sval = evstk;                                // (Empty) initial stack
+       WORD * sattr = evattr;
+       SYM * esym = NULL;                                              // No external symbol involved
+       WORD sym_seg = 0;
 
        while (*tk != ENDEXPR)
        {
                switch ((int)*tk++)
                {
                case SYMBOL:
-//                     sy = (SYM *)*tk++;
+//printf("evexpr(): SYMBOL\n");
                        sy = symbolPtr[*tk++];
-                       sy->sattr |= REFERENCED;                // Set "referenced" bit 
+                       sy->sattr |= REFERENCED;                // Set "referenced" bit
 
                        if (!(sy->sattr & DEFINED))
                        {
@@ -476,78 +533,89 @@ 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:
-                       *++sval = *tk++;                                // Push value
+                       *++sval = ((uint64_t)*tk++) << 32;                      // Push value
+                       *sval |= *tk++;         // & LO LONG (will this work???--should)
+//printf("evexpr(): CONST = %lX\n", *sval);
                        *++sattr = ABS | DEFINED;               // Push simple attribs
                        break;
                case ACONST:
+//printf("evexpr(): ACONST = %i\n", *tk);
                        *++sval = *tk++;                                // Push value
                        *++sattr = (WORD)*tk++;                 // 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 
+                       --sattr;                                                // Pop attrib
+//printf("--> N+N: %i + %i = ", *sval, sval[1]);
                        *sval += sval[1];                               // Compute value
+//printf("%i\n", *sval);
 
-                       if (!(*sattr & (TEXT | DATA | BSS)))
+                       if (!(*sattr & TDB))
                                *sattr = sattr[1];
-                       else if (sattr[1] & (TEXT | DATA | BSS))
+                       else if (sattr[1] & TDB)
                                return error(seg_error);
 
                        break;
                case '-':
+//printf("evexpr(): -\n");
                        --sval;                                                 // Pop value
-                       --sattr;                                                // Pop attrib 
+                       --sattr;                                                // Pop attrib
+//printf("--> N-N: %i - %i = ", *sval, sval[1]);
                        *sval -= sval[1];                               // Compute value
+//printf("%i\n", *sval);
 
-                       attr = (WORD)(*sattr & (TEXT | DATA | BSS));
-
+                       attr = (WORD)(*sattr & TDB);
+#if 0
+printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
+#endif
+                       // If symbol1 is ABS, take attributes from symbol2
                        if (!attr)
                                *sattr = sattr[1];
-                       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:
-                       if (*sattr & (TEXT | DATA | BSS))
+//printf("evexpr(): UNMINUS\n");
+                       if (*sattr & TDB)
                                error(seg_error);
 
                        *sval = -(int)*sval;
                        *sattr = ABS | DEFINED;                 // Expr becomes absolute
                        break;
                case '!':
-                       if (*sattr & (TEXT | DATA | BSS))
+//printf("evexpr(): !\n");
+                       if (*sattr & TDB)
                                error(seg_error);
 
                        *sval = !*sval;
                        *sattr = ABS | DEFINED;                 // Expr becomes absolute
                        break;
                case '~':
-                       if (*sattr & (TEXT | DATA | BSS))
+//printf("evexpr(): ~\n");
+                       if (*sattr & TDB)
                                error(seg_error);
 
                        *sval = ~*sval;
@@ -556,8 +624,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                // Comparison operators must have two values that
                // are in the same segment, but that's the only requirement.
                case LE:
-                       --sattr;
-                       --sval;
+//printf("evexpr(): LE\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -566,8 +635,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        *sval = *sval <= sval[1];
                        break;
                case GE:
-                       --sattr;
-                       --sval;
+//printf("evexpr(): GE\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -576,8 +646,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        *sval = *sval >= sval[1];
                        break;
                case '>':
-                       --sattr;
-                       --sval;
+//printf("evexpr(): >\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -586,8 +657,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        *sval = *sval > sval[1];
                        break;
                case '<':
-                       --sattr;
-                       --sval;
+//printf("evexpr(): <\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -596,8 +668,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        *sval = *sval < sval[1];
                        break;
                case NE:
-                       --sattr;
-                       --sval;
+//printf("evexpr(): NE\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -606,8 +679,9 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        *sval = *sval != sval[1];
                        break;
                case '=':
-                       --sattr;
-                       --sval;
+//printf("evexpr(): =\n");
+                       sattr--;
+                       sval--;
 
                        if ((*sattr & TDB) != (sattr[1] & TDB))
                                error(seg_error);
@@ -618,6 +692,7 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                // 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);
@@ -626,22 +701,30 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                        switch ((int)tk[-1])
                        {
                        case '*':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
+//printf("--> NxN: %i x %i = ", *sval, sval[1]);
                                *sval *= sval[1];
+//printf("%i\n", *sval);
                                break;
                        case '/':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
 
                                if (sval[1] == 0)
-                                       return error("divide by zero");
-
-                               *sval /= sval[1];
+                                       return error("division by zero");
+
+//printf("--> N/N: %i / %i = ", sval[0], sval[1]);
+                               // Compiler is picky here: Without casting these, it discards
+                               // the sign if dividing a negative # by a positive one,
+                               // creating a bad result. :-/
+                               // Definitely a side effect of using uint32_ts intead of ints.
+                               *sval = (int32_t)sval[0] / (int32_t)sval[1];
+//printf("%i\n", *sval);
                                break;
                        case '%':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
 
                                if (sval[1] == 0)
                                        return error("mod (%) by zero");
@@ -649,28 +732,28 @@ int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
                                *sval %= sval[1];
                                break;
                        case SHL:
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
                                *sval <<= sval[1];
                                break;
                        case SHR:
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
                                *sval >>= sval[1];
                                break;
                        case '&':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
                                *sval &= sval[1];
                                break;
                        case '^':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
                                *sval ^= sval[1];
                                break;
                        case '|':
-                               --sval;
-                               --sattr;                                        // Pop attrib 
+                               sval--;
+                               sattr--;                                        // Pop attrib
                                *sval |= sval[1];
                                break;
                        default:
@@ -688,10 +771,11 @@ 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;
 
        return OK;
 }
+