Lots of fixes for floating point handling; version now at 1.11.0.
[rmac] / expr.c
1
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "expr.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "listing.h"
13 #include "mach.h"
14 #include "procln.h"
15 #include "riscasm.h"
16 #include "sect.h"
17 #include "symbol.h"
18 #include "token.h"
19
20 #define DEF_KW                                          // Declare keyword values
21 #include "kwtab.h"                                      // Incl generated keyword tables & defs
22
23 // N.B.: The size of tokenClass should be identical to the largest value of
24 //       a token; we're assuming 256 but not 100% sure!
25 static char tokenClass[256];            // Generated table of token classes
26 static uint64_t evstk[EVSTACKSIZE];     // Evaluator value stack
27 static WORD evattr[EVSTACKSIZE];        // Evaluator attribute stack
28
29 // Token-class initialization list
30 char itokcl[] = {
31         0,                                                              // END
32         CONST, FCONST, SYMBOL, 0,               // ID
33         '(', '[', '{', 0,                               // OPAR
34         ')', ']', '}', 0,                               // CPAR
35         CR_DEFINED, CR_REFERENCED,              // SUNARY (special unary)
36         CR_STREQ, CR_MACDEF,
37         CR_DATE, CR_TIME,
38         CR_ABSCOUNT, 0,
39         '!', '~', UNMINUS, 0,                   // UNARY
40         '*', '/', '%', 0,                               // MULT
41         '+', '-', 0,                                    // ADD
42         SHL, SHR, 0,                                    // SHIFT
43         LE, GE, '<', '>', NE, '=', 0,   // REL
44         '&', 0,                                                 // AND
45         '^', 0,                                                 // XOR
46         '|', 0,                                                 // OR
47         1                                                               // (the end)
48 };
49
50 const char missym_error[] = "missing symbol";
51 const char str_error[] = "missing symbol or string";
52
53 // Convert expression to postfix
54 static PTR evalTokenBuffer;             // Deposit tokens here (this is really a
55                                                                 // pointer to exprbuf from direct.c)
56                                                                 // (Can also be from others, like
57                                                                 // riscasm.c)
58 static int symbolNum;                   // Pointer to the entry in symbolPtr[]
59
60
61 //
62 // Obtain a string value
63 //
64 static uint32_t str_value(char * p)
65 {
66         uint32_t v;
67
68         for(v=0; *p; p++)
69                 v = (v << 8) | (*p & 0xFF);
70
71         return v;
72 }
73
74
75 //
76 // Initialize expression analyzer
77 //
78 void InitExpression(void)
79 {
80         // Initialize token-class table (all set to END)
81         for(int i=0; i<256; i++)
82                 tokenClass[i] = END;
83
84         int i = 0;
85
86         for(char * p=itokcl; *p!=1; p++)
87         {
88                 if (*p == 0)
89                         i++;
90                 else
91                         tokenClass[(int)(*p)] = (char)i;
92         }
93
94         symbolNum = 0;
95 }
96
97
98 //
99 // Binary operators (all the same precedence)
100 //
101 int expr0(void)
102 {
103         if (expr1() != OK)
104                 return ERROR;
105
106         while (tokenClass[*tok] >= MULT)
107         {
108                 TOKEN t = *tok++;
109
110                 if (expr1() != OK)
111                         return ERROR;
112
113                 *evalTokenBuffer.u32++ = t;
114         }
115
116         return OK;
117 }
118
119
120 //
121 // Unary operators (detect unary '-')
122 // ggn: If expression starts with a plus then also eat it up. For some reason
123 //      the parser gets confused when this happens and emits a "bad
124 //      expression".
125 //
126 int expr1(void)
127 {
128         TOKEN t;
129         SYM * sy;
130         char * p, * p2;
131         WORD w;
132         int j;
133
134         int class = tokenClass[*tok];
135
136         if (*tok == '-' || *tok == '+' || class == UNARY)
137         {
138                 t = *tok++;
139
140                 if (expr2() != OK)
141                         return ERROR;
142
143                 if (t == '-')
144                         t = UNMINUS;
145
146                 // With leading + we don't have to deposit anything to the buffer
147                 // because there's no unary '+' nor we have to do anything about it
148                 if (t != '+')
149                         *evalTokenBuffer.u32++ = t;
150         }
151         else if (class == SUNARY)
152         {
153                 switch (*tok++)
154                 {
155                 case CR_ABSCOUNT:
156                         *evalTokenBuffer.u32++ = CONST;
157                         *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc;
158                         break;
159                 case CR_TIME:
160                         *evalTokenBuffer.u32++ = CONST;
161                         *evalTokenBuffer.u64++ = dos_time();
162                         break;
163                 case CR_DATE:
164                         *evalTokenBuffer.u32++ = CONST;
165                         *evalTokenBuffer.u64++ = dos_date();
166                         break;
167                 case CR_MACDEF: // ^^macdef <macro-name>
168                         if (*tok++ != SYMBOL)
169                                 return error(missym_error);
170
171                         p = string[*tok++];
172                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
173                         *evalTokenBuffer.u32++ = CONST;
174                         *evalTokenBuffer.u64++ = (uint64_t)w;
175                         break;
176                 case CR_DEFINED:
177                         w = DEFINED;
178                         goto getsym;
179                 case CR_REFERENCED:
180                         w = REFERENCED;
181 getsym:
182                         if (*tok++ != SYMBOL)
183                                 return error(missym_error);
184
185                         p = string[*tok++];
186                         j = (*p == '.' ? curenv : 0);
187                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
188                         *evalTokenBuffer.u32++ = CONST;
189                         *evalTokenBuffer.u64++ = (uint64_t)w;
190                         break;
191                 case CR_STREQ:
192                         if (*tok != SYMBOL && *tok != STRING)
193                                 return error(str_error);
194
195                         p = string[tok[1]];
196                         tok +=2;
197
198                         if (*tok++ != ',')
199                                 return error(comma_error);
200
201                         if (*tok != SYMBOL && *tok != STRING)
202                                 return error(str_error);
203
204                         p2 = string[tok[1]];
205                         tok += 2;
206
207                         w = (WORD)(!strcmp(p, p2));
208                         *evalTokenBuffer.u32++ = CONST;
209                         *evalTokenBuffer.u64++ = (uint64_t)w;
210                         break;
211                 }
212         }
213         else
214                 return expr2();
215
216         return OK;
217 }
218
219
220 //
221 // Terminals (CONSTs) and parenthesis grouping
222 //
223 int expr2(void)
224 {
225         char * p;
226         SYM * sy;
227         int j;
228         PTR ptk;
229
230         switch (*tok++)
231         {
232         case CONST:
233                 ptk.u32 = tok;
234                 *evalTokenBuffer.u32++ = CONST;
235                 *evalTokenBuffer.u64++ = *ptk.u64++;
236                 tok = ptk.u32;
237                 break;
238         case FCONST:
239                 ptk.u32 = tok;
240                 *evalTokenBuffer.u32++ = FCONST;
241                 *evalTokenBuffer.u64++ = *ptk.u64++;
242                 tok = ptk.u32;
243                 break;
244         case SYMBOL:
245                 p = string[*tok++];
246                 j = (*p == '.' ? curenv : 0);
247                 sy = lookup(p, LABEL, j);
248
249                 if (sy == NULL)
250                         sy = NewSymbol(p, LABEL, j);
251
252                 // Check register bank usage
253                 if (sy->sattre & EQUATEDREG)
254                 {
255                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
256                                 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
257
258                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
259                                 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
260                 }
261
262                 *evalTokenBuffer.u32++ = SYMBOL;
263                 *evalTokenBuffer.u32++ = symbolNum;
264                 symbolPtr[symbolNum] = sy;
265                 symbolNum++;
266                 break;
267         case STRING:
268                 *evalTokenBuffer.u32++ = CONST;
269                 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
270                 break;
271         case '(':
272                 if (expr0() != OK)
273                         return ERROR;
274
275                 if (*tok++ != ')')
276                         return error("missing closing parenthesis ')'");
277
278                 break;
279         case '[':
280                 if (expr0() != OK)
281                         return ERROR;
282
283                 if (*tok++ != ']')
284                         return error("missing closing bracket ']'");
285
286                 break;
287         case '{':
288                 if (expr0() != OK)      // Eat up first parameter (register or immediate)
289                         return ERROR;
290
291                 if (*tok++ != ':')      // Demand a ':' there
292                         return error("missing colon ':'");
293
294                 if (expr0() != OK)      // Eat up second parameter (register or immediate)
295                         return ERROR;
296
297                 if (*tok++ != '}')
298                         return error("missing closing brace '}'");
299
300                 break;
301         case '$':
302                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
303                 *evalTokenBuffer.u32++ = sloc;                          // Current location
304                 *evalTokenBuffer.u32++ = cursect | DEFINED;     // Store attribs
305                 break;
306         case '*':
307                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
308
309                 // pcloc == location at start of line
310                 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
311                 // '*' takes attributes of current section, not ABS!
312                 *evalTokenBuffer.u32++ = cursect | DEFINED;
313                 break;
314         default:
315                 return error("bad expression");
316         }
317
318         return OK;
319 }
320
321
322 //
323 // Recursive-descent expression analyzer (with some simple speed hacks)
324 //
325 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
326 {
327         // Passed in values (once derefenced, that is) can all be zero. They are
328         // there so that the expression analyzer can fill them in as needed. The
329         // expression analyzer gets its input from the global token pointer "tok",
330         // and not from anything passed in by the user.
331         SYM * symbol;
332         char * p;
333         int j;
334         PTR ptk;
335
336         evalTokenBuffer.u32 = otk;      // Set token pointer to 'exprbuf' (direct.c)
337                                                         // Also set in various other places too (riscasm.c,
338                                                         // e.g.)
339
340 //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]]);
341         // Optimize for single constant or single symbol.
342         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
343         //         followed by the value 101, it will trigger a bad evaluation here.
344         //         This is probably a really bad assumption to be making here...!
345         //         (assuming tok[1] == EOL is a single token that is)
346         //         Seems that even other tokens (SUNARY type) can fuck this up too.
347 #if 0
348 //      if ((tok[1] == EOL)
349         if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
350 //              || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
351 //              && (tokenClass[tok[2]] < UNARY)))
352                 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
353                         && (tokenClass[tok[2]] < UNARY))
354                 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
355                 )
356 #else
357 // 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:
358         if ((tok[1] == EOL
359                         && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
360                 || (((tok[0] == SYMBOL)
361                                 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
362                         && (tokenClass[tok[2]] < UNARY))
363                 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
364                 )
365 // 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
366 #endif
367         {
368                 if (*tok >= KW_R0 && *tok <= KW_R31)
369                 {
370                         *evalTokenBuffer.u32++ = CONST;
371                         *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
372                         *a_attr = ABS | DEFINED;
373
374                         if (a_esym != NULL)
375                                 *a_esym = NULL;
376
377                         tok++;
378                 }
379                 else if (*tok == CONST)
380                 {
381                         ptk.u32 = tok;
382                         *evalTokenBuffer.u32++ = *ptk.u32++;
383                         *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
384                         *a_attr = ABS | DEFINED;
385                         tok = ptk.u32;
386
387                         if (a_esym != NULL)
388                                 *a_esym = NULL;
389
390 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
391                 }
392 // Not sure that removing float constant here is going to break anything and/or
393 // make things significantly slower, but having this here seems to cause the
394 // complexity of the check to get to this part of the parse to go through the
395 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
396 #if 0
397                 else if (*tok == FCONST)
398                 {
399                         *evalTokenBuffer.u32++ = *tok++;
400                         *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
401                         *a_attr = ABS | DEFINED | FLOAT;
402
403                         if (a_esym != NULL)
404                                 *a_esym = NULL;
405
406 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
407                 }
408 #endif
409                 else if (*tok == '*')
410                 {
411                         *evalTokenBuffer.u32++ = CONST;
412
413                         if (orgactive)
414                                 *evalTokenBuffer.u64++ = *a_value = orgaddr;
415                         else
416                                 *evalTokenBuffer.u64++ = *a_value = pcloc;
417
418                         // '*' takes attributes of current section, not ABS!
419                         *a_attr = cursect | DEFINED;
420
421                         if (a_esym != NULL)
422                                 *a_esym = NULL;
423
424                         tok++;
425                 }
426                 else if (*tok == STRING || *tok == SYMBOL)
427                 {
428                         p = string[tok[1]];
429                         j = (*p == '.' ? curenv : 0);
430                         symbol = lookup(p, LABEL, j);
431 #if 0
432 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
433 if (symbol)
434         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
435 #endif
436
437                         if (symbol == NULL)
438                                 symbol = NewSymbol(p, LABEL, j);
439
440                         symbol->sattr |= REFERENCED;
441
442                         // Check for undefined register equates, but only if it's not part
443                         // of a #<SYMBOL> construct, as it could be that the label that's
444                         // been undefined may later be used as an address label--which
445                         // means it will be fixed up later, and thus, not an error.
446                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
447                         {
448                                 error("undefined register equate '%s'", symbol->sname);
449 //if we return right away, it returns some spurious errors...
450 //                              return ERROR;
451                         }
452
453                         // Check register bank usage
454                         if (symbol->sattre & EQUATEDREG)
455                         {
456                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
457                                         warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
458
459                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
460                                         warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
461                         }
462
463                         *evalTokenBuffer.u32++ = SYMBOL;
464 #if 0
465                         *evalTokenBuffer++ = (TOKEN)symbol;
466 #else
467 /*
468 While this approach works, it's wasteful. It would be better to use something
469 that's already available, like the symbol "order defined" table (which needs to
470 be converted from a linked list into an array).
471 */
472                         *evalTokenBuffer.u32++ = symbolNum;
473                         symbolPtr[symbolNum] = symbol;
474                         symbolNum++;
475 #endif
476
477                         if (symbol->sattr & DEFINED)
478                                 *a_value = symbol->svalue;
479                         else
480                                 *a_value = 0;
481
482 /*
483 All that extra crap that was put into the svalue when doing the equr stuff is
484 thrown away right here. What the hell is it for?
485 */
486                         if (symbol->sattre & EQUATEDREG)
487                                 *a_value &= 0x1F;
488
489                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
490
491                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
492                                 && a_esym != NULL)
493                                 *a_esym = symbol;
494
495                         tok += 2;
496                 }
497                 else
498                 {
499                         // Unknown type here... Alert the user!,
500                         error("undefined RISC register in expression");
501                         // Prevent spurious error reporting...
502                         tok++;
503                         return ERROR;
504                 }
505
506                 *evalTokenBuffer.u32++ = ENDEXPR;
507                 return OK;
508         }
509
510         if (expr0() != OK)
511                 return ERROR;
512
513         *evalTokenBuffer.u32++ = ENDEXPR;
514         return evexpr(otk, a_value, a_attr, a_esym);
515 }
516
517
518 //
519 // Evaluate expression.
520 // If the expression involves only ONE external symbol, the expression is
521 // UNDEFINED, but it's value includes everything but the symbol value, and
522 // 'a_esym' is set to the external symbol.
523 //
524 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
525 {
526         WORD attr, attr2;
527         SYM * sy;
528         uint64_t * sval = evstk;                                // (Empty) initial stack
529         WORD * sattr = evattr;
530         SYM * esym = NULL;                                              // No external symbol involved
531         WORD sym_seg = 0;
532         PTR tk;
533         tk.u32 = _tk;
534
535         while (*tk.u32 != ENDEXPR)
536         {
537                 switch ((int)*tk.u32++)
538                 {
539                 case SYMBOL:
540 //printf("evexpr(): SYMBOL\n");
541                         sy = symbolPtr[*tk.u32++];
542                         sy->sattr |= REFERENCED;                // Set "referenced" bit
543
544                         if (!(sy->sattr & DEFINED))
545                         {
546                                 // Reference to undefined symbol
547                                 if (!(sy->sattr & GLOBAL))
548                                 {
549                                         *a_attr = 0;
550                                         *a_value = 0;
551                                         return OK;
552                                 }
553
554                                 if (esym != NULL)                       // Check for multiple externals
555                                         return error(seg_error);
556
557                                 esym = sy;
558                         }
559
560                         if (sy->sattr & DEFINED)
561                                 *++sval = sy->svalue;           // Push symbol's value
562                         else
563                                 *++sval = 0;                            // 0 for undefined symbols
564
565                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
566                         sym_seg = (WORD)(sy->sattr & TDB);
567                         break;
568
569                 case CONST:
570                         *++sval = *tk.u64++;
571 //printf("evexpr(): CONST = %lX\n", *sval);
572                         *++sattr = ABS | DEFINED;               // Push simple attribs
573                         break;
574
575                 case FCONST:
576 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
577                         // Even though it's a double, we can treat it like a uint64_t since
578                         // we're just moving the bits around.
579                         *++sval = *tk.u64++;
580                         *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
581                         break;
582
583                 case ACONST:
584 //printf("evexpr(): ACONST = %i\n", *tk.u32);
585                         *++sval = *tk.u32++;                            // Push value
586                         *++sattr = (WORD)*tk.u32++;                     // Push attribs
587                         break;
588
589                         // Binary "+" and "-" matrix:
590                         //
591                         //                ABS    Sect     Other
592                         //     ----------------------------
593                         //   ABS     |  ABS   |  Sect  |  Other |
594                         //   Sect    |  Sect  |  [1]   |  Error |
595                         //   Other   |  Other |  Error |  [1]   |
596                         //      ----------------------------
597                         //
598                         //   [1] + : Error
599                         //       - : ABS
600
601                 case '+':
602 //printf("evexpr(): +\n");
603                         --sval;                                                 // Pop value
604                         --sattr;                                                // Pop attrib
605 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
606                         // Get FLOAT attribute, if any
607                         attr = (sattr[0] | sattr[1]) & FLOAT;
608
609                         // Since adding an int to a fp value promotes it to a fp value, we
610                         // don't care whether it's first or second; we cast to to a double
611                         // regardless.
612                         if (attr == FLOAT)
613                         {
614                                 PTR p;
615                                 p.u64 = sval;
616                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
617                                 p.u64++;
618                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
619                                 *(double *)sval = fpval1 + fpval2;
620                         }
621                         else
622                         {
623                                 *sval += sval[1];                               // Compute value
624                         }
625 //printf("%i\n", *sval);
626
627                         if (!(*sattr & TDB))
628                                 *sattr = sattr[1] | attr;
629                         else if (sattr[1] & TDB)
630                                 return error(seg_error);
631
632                         break;
633
634                 case '-':
635 //printf("evexpr(): -\n");
636                         --sval;                                                 // Pop value
637                         --sattr;                                                // Pop attrib
638 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
639                         // Get FLOAT attribute, if any
640                         attr = (sattr[0] | sattr[1]) & FLOAT;
641
642                         // Since subtracting an int to a fp value promotes it to a fp
643                         // value, we don't care whether it's first or second; we cast to to
644                         // a double regardless.
645                         if (attr == FLOAT)
646                         {
647                                 PTR p;
648                                 p.u64 = sval;
649                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
650                                 p.u64++;
651                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
652                                 *(double *)sval = fpval1 - fpval2;
653                         }
654                         else
655                         {
656                                 *sval -= sval[1];
657                         }
658 //printf("%i\n", *sval);
659
660                         *sattr |= attr;                                 // Inherit FLOAT attribute
661                         attr = (WORD)(*sattr & TDB);
662 #if 0
663 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
664 #endif
665                         // If symbol1 is ABS, take attributes from symbol2
666                         if (!attr)
667                                 *sattr = sattr[1];
668                         // Otherwise, they're both TDB and so attributes cancel out
669                         else if (sattr[1] & TDB)
670                                 *sattr &= ~TDB;
671
672                         break;
673
674                 // Unary operators only work on ABS items
675                 case UNMINUS:
676 //printf("evexpr(): UNMINUS\n");
677                         if (*sattr & TDB)
678                                 return error(seg_error);
679
680                         if (*sattr & FLOAT)
681                         {
682                                 double * dst = (double *)sval;
683                                 *dst = -*dst;
684                                 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
685                         }
686                         else
687                         {
688                                 *sval = -(int64_t)*sval;
689                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
690                         }
691
692                         break;
693
694                 case '!':
695 //printf("evexpr(): !\n");
696                         if (*sattr & TDB)
697                                 return error(seg_error);
698
699                         if (*sattr & FLOAT)
700                                 return error("floating point numbers not allowed with operator '!'.");
701
702                         *sval = !*sval;
703                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
704                         break;
705
706                 case '~':
707 //printf("evexpr(): ~\n");
708                         if (*sattr & TDB)
709                                 return error(seg_error);
710
711                         if (*sattr & FLOAT)
712                                 return error("floating point numbers not allowed with operator '~'.");
713
714                         *sval = ~*sval;
715                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
716                         break;
717
718                 // Comparison operators must have two values that
719                 // are in the same segment, but that's the only requirement.
720                 case LE:
721 //printf("evexpr(): LE\n");
722                         sattr--;
723                         sval--;
724
725                         if ((*sattr & TDB) != (sattr[1] & TDB))
726                                 return error(seg_error);
727
728                         // Get FLOAT attribute, if any
729                         attr = (sattr[0] | sattr[1]) & FLOAT;
730
731                         // Cast any ints in the comparison to double, if there's at least
732                         // one double in the comparison.
733                         if (attr == FLOAT)
734                         {
735                                 PTR p;
736                                 p.u64 = sval;
737                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
738                                 p.u64++;
739                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
740                                 *sval = (fpval1 <= fpval2);
741                         }
742                         else
743                         {
744                                 *sval = (*sval <= sval[1]);
745                         }
746
747                         *sattr = ABS | DEFINED;
748                         break;
749
750                 case GE:
751 //printf("evexpr(): GE\n");
752                         sattr--;
753                         sval--;
754
755                         if ((*sattr & TDB) != (sattr[1] & TDB))
756                                 return error(seg_error);
757
758                         // Get FLOAT attribute, if any
759                         attr = (sattr[0] | sattr[1]) & FLOAT;
760
761                         // Cast any ints in the comparison to double, if there's at least
762                         // one double in the comparison.
763                         if (attr == FLOAT)
764                         {
765                                 PTR p;
766                                 p.u64 = sval;
767                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
768                                 p.u64++;
769                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
770                                 *sval = (fpval1 >= fpval2);
771                         }
772                         else
773                         {
774                                 *sval = (*sval >= sval[1]);
775                         }
776
777                         *sattr = ABS | DEFINED;
778                         break;
779
780                 case '>':
781 //printf("evexpr(): >\n");
782                         sattr--;
783                         sval--;
784
785                         if ((*sattr & TDB) != (sattr[1] & TDB))
786                                 return error(seg_error);
787
788                         // Get FLOAT attribute, if any
789                         attr = (sattr[0] | sattr[1]) & FLOAT;
790
791                         // Cast any ints in the comparison to double, if there's at least
792                         // one double in the comparison.
793                         if (attr == FLOAT)
794                         {
795                                 PTR p;
796                                 p.u64 = sval;
797                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
798                                 p.u64++;
799                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
800                                 *sval = (fpval1 > fpval2);
801                         }
802                         else
803                         {
804                                 *sval = (*sval > sval[1]);
805                         }
806
807                         *sattr = ABS | DEFINED;
808                         break;
809
810                 case '<':
811 //printf("evexpr(): <\n");
812                         sattr--;
813                         sval--;
814
815                         if ((*sattr & TDB) != (sattr[1] & TDB))
816                                 return error(seg_error);
817
818                         // Get FLOAT attribute, if any
819                         attr = (sattr[0] | sattr[1]) & FLOAT;
820
821                         // Cast any ints in the comparison to double, if there's at least
822                         // one double in the comparison.
823                         if (attr == FLOAT)
824                         {
825                                 PTR p;
826                                 p.u64 = sval;
827                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
828                                 p.u64++;
829                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
830                                 *sval = (fpval1 < fpval2);
831                         }
832                         else
833                         {
834                                 *sval = (*sval < sval[1]);
835                         }
836
837                         *sattr = ABS | DEFINED;         // Expr forced to ABS
838                         break;
839
840                 case NE:
841 //printf("evexpr(): NE\n");
842                         sattr--;
843                         sval--;
844
845                         if ((*sattr & TDB) != (sattr[1] & TDB))
846                                 return error(seg_error);
847
848                         // Get FLOAT attribute, if any
849                         attr = (sattr[0] | sattr[1]) & FLOAT;
850
851                         // Cast any ints in the comparison to double, if there's at least
852                         // one double in the comparison.
853                         if (attr == FLOAT)
854                         {
855                                 PTR p;
856                                 p.u64 = sval;
857                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
858                                 p.u64++;
859                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
860                                 *sval = (fpval1 != fpval2);
861                         }
862                         else
863                         {
864                                 *sval = (*sval != sval[1]);
865                         }
866
867                         *sattr = ABS | DEFINED;         // Expr forced to ABS
868                         break;
869
870                 case '=':
871 //printf("evexpr(): =\n");
872                         sattr--;
873                         sval--;
874
875                         if ((*sattr & TDB) != (sattr[1] & TDB))
876                                 return error(seg_error);
877
878                         // Get FLOAT attribute, if any
879                         attr = (sattr[0] | sattr[1]) & FLOAT;
880
881                         // Cast any ints in the comparison to double, if there's at least
882                         // one double in the comparison.
883                         if (attr == FLOAT)
884                         {
885                                 PTR p;
886                                 p.u64 = sval;
887                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
888                                 p.u64++;
889                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
890                                 *sval = (fpval1 == fpval2);
891                         }
892                         else
893                         {
894                                 *sval = (*sval == sval[1]);
895                         }
896
897                         *sattr = ABS | DEFINED;         // Expr forced to ABS
898
899                         break;
900
901                 // All other binary operators must have two ABS items to work with.
902                 // They all produce an ABS value.
903                 default:
904 //printf("evexpr(): default\n");
905                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
906                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
907                         //error(seg_error);
908
909                         switch ((int)tk.u32[-1])
910                         {
911                         case '*':
912                                 sval--;
913                                 sattr--;
914 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
915                                 // Get FLOAT attribute, if any
916                                 attr = (sattr[0] | sattr[1]) & FLOAT;
917
918                                 // Since multiplying an int to a fp value promotes it to a fp
919                                 // value, we don't care whether it's first or second; it will
920                                 // be cast to a double regardless.
921 /*
922 An open question here is do we promote ints to floats as signed or unsigned? It makes a difference if, say, the int is put in as -1 but is promoted to a double as $FFFFFFFFFFFFFFFF--you get very different results that way! For now, we promote as signed until proven detrimental otherwise.
923 */
924                                 if (attr == FLOAT)
925                                 {
926                                         PTR p;
927                                         p.u64 = sval;
928                                         double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
929                                         p.u64++;
930                                         double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
931                                         *(double *)sval = fpval1 * fpval2;
932                                 }
933                                 else
934                                 {
935                                         *sval *= sval[1];
936                                 }
937 //printf("%i\n", *sval);
938
939                                 *sattr = ABS | DEFINED | attr;          // Expr becomes absolute
940                                 break;
941
942                         case '/':
943                                 sval--;
944                                 sattr--;
945 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
946                                 // Get FLOAT attribute, if any
947                                 attr = (sattr[0] | sattr[1]) & FLOAT;
948
949                                 if (attr == FLOAT)
950                                 {
951                                         PTR p;
952                                         p.u64 = sval;
953                                         double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
954                                         p.u64++;
955                                         double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
956
957                                         if (fpval2 == 0)
958                                                 return error("divide by zero");
959
960                                         *(double *)sval = fpval1 / fpval2;
961                                 }
962                                 else
963                                 {
964                                         if (sval[1] == 0)
965                                                 return error("divide by zero");
966 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
967
968                                         // Compiler is picky here: Without casting these, it
969                                         // discards the sign if dividing a negative # by a
970                                         // positive one, creating a bad result. :-/
971                                         // Definitely a side effect of using uint32_ts intead of
972                                         // ints.
973                                         *sval = (int32_t)sval[0] / (int32_t)sval[1];
974                                 }
975 //printf("%i\n", *sval);
976
977                                 *sattr = ABS | DEFINED | attr;          // Expr becomes absolute
978                                 break;
979
980                         case '%':
981                                 sval--;
982                                 sattr--;
983
984                                 if ((*sattr | sattr[1]) & FLOAT)
985                                         return error("floating point numbers not allowed with operator '%'.");
986
987                                 if (sval[1] == 0)
988                                         return error("mod (%) by zero");
989
990                                 *sval %= sval[1];
991                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
992                                 break;
993
994                         case SHL:
995                                 sval--;
996                                 sattr--;                                        // Pop attrib
997
998                                 if ((*sattr | sattr[1]) & FLOAT)
999                                         return error("floating point numbers not allowed with operator '<<'.");
1000
1001                                 *sval <<= sval[1];
1002                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1003                                 break;
1004
1005                         case SHR:
1006                                 sval--;
1007                                 sattr--;                                        // Pop attrib
1008
1009                                 if ((*sattr | sattr[1]) & FLOAT)
1010                                         return error("floating point numbers not allowed with operator '>>'.");
1011
1012                                 *sval >>= sval[1];
1013                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1014                                 break;
1015
1016                         case '&':
1017                                 sval--;
1018                                 sattr--;                                        // Pop attrib
1019
1020                                 if ((*sattr | sattr[1]) & FLOAT)
1021                                         return error("floating point numbers not allowed with operator '&'.");
1022
1023                                 *sval &= sval[1];
1024                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1025                                 break;
1026
1027                         case '^':
1028                                 sval--;
1029                                 sattr--;                                        // Pop attrib
1030
1031                                 if ((*sattr | sattr[1]) & FLOAT)
1032                                         return error("floating point numbers not allowed with operator '^'.");
1033
1034                                 *sval ^= sval[1];
1035                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1036                                 break;
1037
1038                         case '|':
1039                                 sval--;
1040                                 sattr--;
1041
1042                                 if ((*sattr | sattr[1]) & FLOAT)
1043                                         return error("floating point numbers not allowed with operator '|'.");
1044
1045                                 *sval |= sval[1];
1046                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1047                                 break;
1048
1049                         default:
1050                                 // Bad operator in expression stream (this should never happen!)
1051                                 interror(5);
1052                         }
1053                 }
1054         }
1055
1056         if (esym != NULL)
1057                 *sattr &= ~DEFINED;
1058
1059         if (a_esym != NULL)
1060                 *a_esym = esym;
1061
1062         // Copy value + attrib into return variables
1063         *a_value = *sval;
1064         *a_attr = *sattr;
1065
1066         return OK;
1067 }
1068