20f43cfcb3aace6feb23228e635f8a1cfd5d4dc1
[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         case FCONST:
234                 ptk.u32 = tok;
235                 *evalTokenBuffer.u32++ = CONST;
236                 *evalTokenBuffer.u64++ = *ptk.u64++;
237                 tok = ptk.u32;
238                 break;
239         case SYMBOL:
240                 p = string[*tok++];
241                 j = (*p == '.' ? curenv : 0);
242                 sy = lookup(p, LABEL, j);
243
244                 if (sy == NULL)
245                         sy = NewSymbol(p, LABEL, j);
246
247                 // Check register bank usage
248                 if (sy->sattre & EQUATEDREG)
249                 {
250                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
251                                 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
252
253                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
254                                 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
255                 }
256
257                 *evalTokenBuffer.u32++ = SYMBOL;
258                 *evalTokenBuffer.u32++ = symbolNum;
259                 symbolPtr[symbolNum] = sy;
260                 symbolNum++;
261                 break;
262         case STRING:
263                 *evalTokenBuffer.u32++ = CONST;
264                 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
265                 break;
266         case '(':
267                 if (expr0() != OK)
268                         return ERROR;
269
270                 if (*tok++ != ')')
271                         return error("missing closing parenthesis ')'");
272
273                 break;
274         case '[':
275                 if (expr0() != OK)
276                         return ERROR;
277
278                 if (*tok++ != ']')
279                         return error("missing closing bracket ']'");
280
281                 break;
282         case '{':
283                 if (expr0() != OK)      // Eat up first parameter (register or immediate)
284                         return ERROR;
285
286                 if (*tok++ != ':')      // Demand a ':' there
287                         return error("missing colon ':'");
288
289                 if (expr0() != OK)      // Eat up second parameter (register or immediate)
290                         return ERROR;
291
292                 if (*tok++ != '}')
293                         return error("missing closing brace '}'");
294
295                 break;
296         case '$':
297                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
298                 *evalTokenBuffer.u32++ = sloc;                          // Current location
299                 *evalTokenBuffer.u32++ = cursect | DEFINED;     // Store attribs
300                 break;
301         case '*':
302                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
303
304                 // pcloc == location at start of line
305                 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
306                 // '*' takes attributes of current section, not ABS!
307                 *evalTokenBuffer.u32++ = cursect | DEFINED;
308                 break;
309         default:
310                 return error("bad expression");
311         }
312
313         return OK;
314 }
315
316
317 //
318 // Recursive-descent expression analyzer (with some simple speed hacks)
319 //
320 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
321 {
322         // Passed in values (once derefenced, that is) can all be zero. They are
323         // there so that the expression analyzer can fill them in as needed. The
324         // expression analyzer gets its input from the global token pointer "tok",
325         // and not from anything passed in by the user.
326         SYM * symbol;
327         char * p;
328         int j;
329         PTR ptk;
330
331         evalTokenBuffer.u32 = otk;      // Set token pointer to 'exprbuf' (direct.c)
332                                                         // Also set in various other places too (riscasm.c,
333                                                         // e.g.)
334
335 //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]]);
336         // Optimize for single constant or single symbol.
337         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
338         //         followed by the value 101, it will trigger a bad evaluation here.
339         //         This is probably a really bad assumption to be making here...!
340         //         (assuming tok[1] == EOL is a single token that is)
341         //         Seems that even other tokens (SUNARY type) can fuck this up too.
342 #if 0
343 //      if ((tok[1] == EOL)
344         if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
345 //              || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
346 //              && (tokenClass[tok[2]] < UNARY)))
347                 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
348                         && (tokenClass[tok[2]] < UNARY))
349                 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
350                 )
351 #else
352 // 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:
353         if ((tok[1] == EOL
354                         && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
355                 || (((tok[0] == SYMBOL)
356                                 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
357                         && (tokenClass[tok[2]] < UNARY))
358                 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
359                 )
360 // 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
361 #endif
362         {
363                 if (*tok >= KW_R0 && *tok <= KW_R31)
364                 {
365                         *evalTokenBuffer.u32++ = CONST;
366                         *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
367                         *a_attr = ABS | DEFINED;
368
369                         if (a_esym != NULL)
370                                 *a_esym = NULL;
371
372                         tok++;
373                 }
374                 else if (*tok == CONST)
375                 {
376                         ptk.u32 = tok;
377                         *evalTokenBuffer.u32++ = *ptk.u32++;
378                         *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
379                         *a_attr = ABS | DEFINED;
380                         tok = ptk.u32;
381
382                         if (a_esym != NULL)
383                                 *a_esym = NULL;
384
385 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
386                 }
387 // Not sure that removing float constant here is going to break anything and/or
388 // make things significantly slower, but having this here seems to cause the
389 // complexity of the check to get to this part of the parse to go through the
390 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
391 #if 0
392                 else if (*tok == FCONST)
393                 {
394                         *evalTokenBuffer.u32++ = *tok++;
395                         *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
396                         *a_attr = ABS | DEFINED | FLOAT;
397
398                         if (a_esym != NULL)
399                                 *a_esym = NULL;
400
401 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
402                 }
403 #endif
404                 else if (*tok == '*')
405                 {
406                         *evalTokenBuffer.u32++ = CONST;
407
408                         if (orgactive)
409                                 *evalTokenBuffer.u64++ = *a_value = orgaddr;
410                         else
411                                 *evalTokenBuffer.u64++ = *a_value = pcloc;
412
413                         // '*' takes attributes of current section, not ABS!
414                         *a_attr = cursect | DEFINED;
415
416                         if (a_esym != NULL)
417                                 *a_esym = NULL;
418
419                         tok++;
420                 }
421                 else if (*tok == STRING || *tok == SYMBOL)
422                 {
423                         p = string[tok[1]];
424                         j = (*p == '.' ? curenv : 0);
425                         symbol = lookup(p, LABEL, j);
426 #if 0
427 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
428 if (symbol)
429         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
430 #endif
431
432                         if (symbol == NULL)
433                                 symbol = NewSymbol(p, LABEL, j);
434
435                         symbol->sattr |= REFERENCED;
436
437                         // Check for undefined register equates, but only if it's not part
438                         // of a #<SYMBOL> construct, as it could be that the label that's
439                         // been undefined may later be used as an address label--which
440                         // means it will be fixed up later, and thus, not an error.
441                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
442                         {
443                                 error("undefined register equate '%s'", symbol->sname);
444 //if we return right away, it returns some spurious errors...
445 //                              return ERROR;
446                         }
447
448                         // Check register bank usage
449                         if (symbol->sattre & EQUATEDREG)
450                         {
451                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
452                                         warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
453
454                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
455                                         warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
456                         }
457
458                         *evalTokenBuffer.u32++ = SYMBOL;
459 #if 0
460                         *evalTokenBuffer++ = (TOKEN)symbol;
461 #else
462 /*
463 While this approach works, it's wasteful. It would be better to use something
464 that's already available, like the symbol "order defined" table (which needs to
465 be converted from a linked list into an array).
466 */
467                         *evalTokenBuffer.u32++ = symbolNum;
468                         symbolPtr[symbolNum] = symbol;
469                         symbolNum++;
470 #endif
471
472                         if (symbol->sattr & DEFINED)
473                                 *a_value = symbol->svalue;
474                         else
475                                 *a_value = 0;
476
477 /*
478 All that extra crap that was put into the svalue when doing the equr stuff is
479 thrown away right here. What the hell is it for?
480 */
481                         if (symbol->sattre & EQUATEDREG)
482                                 *a_value &= 0x1F;
483
484                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
485
486                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
487                                 && a_esym != NULL)
488                                 *a_esym = symbol;
489
490                         tok += 2;
491                 }
492                 else
493                 {
494                         // Unknown type here... Alert the user!,
495                         error("undefined RISC register in expression");
496                         // Prevent spurious error reporting...
497                         tok++;
498                         return ERROR;
499                 }
500
501                 *evalTokenBuffer.u32++ = ENDEXPR;
502                 return OK;
503         }
504
505         if (expr0() != OK)
506                 return ERROR;
507
508         *evalTokenBuffer.u32++ = ENDEXPR;
509         return evexpr(otk, a_value, a_attr, a_esym);
510 }
511
512
513 //
514 // Evaluate expression.
515 // If the expression involves only ONE external symbol, the expression is
516 // UNDEFINED, but it's value includes everything but the symbol value, and
517 // 'a_esym' is set to the external symbol.
518 //
519 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
520 {
521         WORD attr, attr2;
522         SYM * sy;
523         uint64_t * sval = evstk;                                // (Empty) initial stack
524         WORD * sattr = evattr;
525         SYM * esym = NULL;                                              // No external symbol involved
526         WORD sym_seg = 0;
527         PTR tk;
528         tk.u32 = _tk;
529
530         while (*tk.u32 != ENDEXPR)
531         {
532                 switch ((int)*tk.u32++)
533                 {
534                 case SYMBOL:
535 //printf("evexpr(): SYMBOL\n");
536                         sy = symbolPtr[*tk.u32++];
537                         sy->sattr |= REFERENCED;                // Set "referenced" bit
538
539                         if (!(sy->sattr & DEFINED))
540                         {
541                                 // Reference to undefined symbol
542                                 if (!(sy->sattr & GLOBAL))
543                                 {
544                                         *a_attr = 0;
545                                         *a_value = 0;
546                                         return OK;
547                                 }
548
549                                 if (esym != NULL)                       // Check for multiple externals
550                                         return error(seg_error);
551
552                                 esym = sy;
553                         }
554
555                         if (sy->sattr & DEFINED)
556                         {
557                                 *++sval = sy->svalue;           // Push symbol's value
558                         }
559                         else
560                         {
561                                 *++sval = 0;                            // 0 for undefined symbols
562                         }
563
564                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
565                         sym_seg = (WORD)(sy->sattr & TDB);
566                         break;
567                 case CONST:
568                         *++sval = *tk.u64++;
569 //printf("evexpr(): CONST = %lX\n", *sval);
570                         *++sattr = ABS | DEFINED;               // Push simple attribs
571                         break;
572                 case FCONST:
573 //printf("evexpr(): FCONST = %i\n", *tk.u32);
574                         *((double *)sval) = *((double *)tk.u32);
575                         tk.u32 += 2;
576                         *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
577                         break;
578                 case ACONST:
579 //printf("evexpr(): ACONST = %i\n", *tk.u32);
580                         *++sval = *tk.u32++;                            // Push value
581                         *++sattr = (WORD)*tk.u32++;                     // Push attribs
582                         break;
583
584                         // Binary "+" and "-" matrix:
585                         //
586                         //                ABS    Sect     Other
587                         //     ----------------------------
588                         //   ABS     |  ABS   |  Sect  |  Other |
589                         //   Sect    |  Sect  |  [1]   |  Error |
590                         //   Other   |  Other |  Error |  [1]   |
591                         //      ----------------------------
592                         //
593                         //   [1] + : Error
594                         //       - : ABS
595                 case '+':
596 //printf("evexpr(): +\n");
597                         --sval;                                                 // Pop value
598                         --sattr;                                                // Pop attrib
599 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
600                         // Extract float attributes from both terms and pack them
601                         // into a single value
602                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
603                         attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
604
605                         if (attr == (FLOAT | (FLOAT >> 1)))
606                         {
607                                 // Float + Float
608                                 double * dst = (double *)sval;
609                                 double * src = (double *)(sval + 1);
610                                 *dst += *src;
611                         }
612                         else if (attr == FLOAT)
613                         {
614                                 // Float + Int
615                                 double * dst = (double *)sval;
616                                 uint64_t * src = (uint64_t *)(sval + 1);
617                                 *dst += *src;
618                         }
619                         else if (attr == FLOAT >> 1)
620                         {
621                                 // Int + Float
622                                 uint64_t * dst = (uint64_t *)sval;
623                                 double * src = (double *)(sval + 1);
624                                 *(double *)dst = *src + *dst;
625                         }
626                         else
627                         {
628                                 *sval += sval[1];                               // Compute value
629                         }
630 //printf("%i\n", *sval);
631
632                         if (!(*sattr & TDB))
633                                 *sattr = sattr[1] | attr2;
634                         else if (sattr[1] & TDB)
635                                 return error(seg_error);
636
637                         break;
638                 case '-':
639 //printf("evexpr(): -\n");
640                         --sval;                                                 // Pop value
641                         --sattr;                                                // Pop attrib
642 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
643                         // Extract float attributes from both terms and pack them
644                         // into a single value
645                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
646                         attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
647
648                         if (attr == (FLOAT | (FLOAT >> 1)))
649                         {
650                                 // Float - Float
651                                 double * dst = (double *)sval;
652                                 double * src = (double *)(sval + 1);
653                                 *dst -= *src;
654                         }
655                         else if (attr == FLOAT)
656                         {
657                                 // Float - Int
658                                 double * dst = (double *)sval;
659                                 uint64_t * src = (uint64_t *)(sval + 1);
660                                 *dst -= *src;
661                         }
662                         else if (attr == FLOAT >> 1)
663                         {
664                                 // Int - Float
665                                 uint64_t * dst = (uint64_t *)sval;
666                                 double * src = (double *)(sval + 1);
667                                 *(double *)dst = *dst - *src;
668                         }
669                         else
670                         {
671                                 *sval -= sval[1];                               // Compute value
672                         }
673
674 //printf("%i\n", *sval);
675
676                         attr = (WORD)(*sattr & TDB);
677 #if 0
678 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
679 #endif
680                         *sattr |= attr2;                // Inherit FLOAT attribute
681                         // If symbol1 is ABS, take attributes from symbol2
682                         if (!attr)
683                                 *sattr = sattr[1];
684                         // Otherwise, they're both TDB and so attributes cancel out
685                         else if (sattr[1] & TDB)
686                                 *sattr &= ~TDB;
687
688                         break;
689                 // Unary operators only work on ABS items
690                 case UNMINUS:
691 //printf("evexpr(): UNMINUS\n");
692                         if (*sattr & TDB)
693                                 return error(seg_error);
694
695                         if (*sattr & FLOAT)
696                         {
697                                 double *dst = (double *)sval;
698                                 *dst = -*dst;
699                                 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
700                         }
701                         else
702                         {
703                                 *sval = -(int)*sval;
704                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
705                         }
706                         break;
707                 case '!':
708 //printf("evexpr(): !\n");
709                         if (*sattr & TDB)
710                                 return error(seg_error);
711
712                         if (*sattr & FLOAT)
713                                 return error("floating point numbers not allowed with operator '!'.");
714
715                         *sval = !*sval;
716                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
717                         break;
718                 case '~':
719 //printf("evexpr(): ~\n");
720                         if (*sattr & TDB)
721                                 return error(seg_error);
722
723                         if (*sattr & FLOAT)
724                                 return error("floating point numbers not allowed with operator '~'.");
725
726                         *sval = ~*sval;
727                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
728                         break;
729                 // Comparison operators must have two values that
730                 // are in the same segment, but that's the only requirement.
731                 case LE:
732 //printf("evexpr(): LE\n");
733                         sattr--;
734                         sval--;
735
736                         if ((*sattr & TDB) != (sattr[1] & TDB))
737                                 return error(seg_error);
738
739                         // Extract float attributes from both terms and pack them
740                         // into a single value
741                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
742
743                         if (attr == (FLOAT | (FLOAT >> 1)))
744                         {
745                                 // Float <= Float
746                                 double * dst = (double *)sval;
747                                 double * src = (double *)(sval + 1);
748                                 *sval = *dst <= *src;
749                         }
750                         else if (attr == FLOAT)
751                         {
752                                 // Float <= Int
753                                 double * dst = (double *)sval;
754                                 uint64_t * src = (uint64_t *)(sval + 1);
755                                 *sval = *dst <= *src;
756                         }
757                         else if (attr == FLOAT >> 1)
758                         {
759                                 // Int <= Float
760                                 uint64_t * dst = (uint64_t *)sval;
761                                 double * src = (double *)(sval + 1);
762                                 *sval = *dst <= *src;
763                         }
764                         else
765                         {
766                                 *sval = *sval <= sval[1];
767                         }
768
769                         *sattr = ABS | DEFINED;
770                         break;
771                 case GE:
772 //printf("evexpr(): GE\n");
773                         sattr--;
774                         sval--;
775
776                         if ((*sattr & TDB) != (sattr[1] & TDB))
777                                 return error(seg_error);
778
779                         // Extract float attributes from both terms and pack them
780                         // into a single value
781                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
782
783                         if (attr == (FLOAT | (FLOAT >> 1)))
784                         {
785                                 // Float >= Float
786                                 double * dst = (double *)sval;
787                                 double * src = (double *)(sval + 1);
788                                 *sval = *dst >= *src;
789                         }
790                         else if (attr == FLOAT)
791                         {
792                                 // Float >= Int
793                                 double * dst = (double *)sval;
794                                 uint64_t * src = (uint64_t *)(sval + 1);
795                                 *sval = *dst >= *src;
796                         }
797                         else if (attr == FLOAT >> 1)
798                         {
799                                 // Int >= Float
800                                 uint64_t * dst = (uint64_t *)sval;
801                                 double * src = (double *)(sval + 1);
802                                 *sval = *dst >= *src;
803                         }
804                         else if (attr == 0)
805                         {
806                                 *sval = *sval >= sval[1];
807                         }
808                         else
809                                 *sattr = ABS | DEFINED;
810
811                         break;
812                 case '>':
813 //printf("evexpr(): >\n");
814                         sattr--;
815                         sval--;
816
817                         if ((*sattr & TDB) != (sattr[1] & TDB))
818                                 return error(seg_error);
819
820                         // Extract float attributes from both terms and pack them
821                         // into a single value
822                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
823
824                         if (attr == (FLOAT | (FLOAT >> 1)))
825                         {
826                                 // Float > Float
827                                 double * dst = (double *)sval;
828                                 double * src = (double *)(sval + 1);
829                                 *sval = *dst > *src;
830                         }
831                         else if (attr == FLOAT)
832                         {
833                                 // Float > Int
834                                 double * dst = (double *)sval;
835                                 uint64_t * src = (uint64_t *)(sval + 1);
836                                 *sval = *dst > *src;
837                         }
838                         else if (attr == FLOAT >> 1)
839                         {
840                                 // Int > Float
841                                 uint64_t * dst = (uint64_t *)sval;
842                                 double * src = (double *)(sval + 1);
843                                 *sval = *dst > *src;
844                         }
845                         else
846                         {
847                                 *sval = *sval > sval[1];
848                         }
849
850                         *sattr = ABS | DEFINED;
851
852                         break;
853                 case '<':
854 //printf("evexpr(): <\n");
855                         sattr--;
856                         sval--;
857
858                         if ((*sattr & TDB) != (sattr[1] & TDB))
859                                 return error(seg_error);
860
861                         // Extract float attributes from both terms and pack them
862                         // into a single value
863                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
864
865                         if (attr == (FLOAT | (FLOAT >> 1)))
866                         {
867                                 // Float < Float
868                                 double * dst = (double *)sval;
869                                 double * src = (double *)(sval + 1);
870                                 *sval = *dst < *src;
871                         }
872                         else if (attr == FLOAT)
873                         {
874                                 // Float < Int
875                                 double * dst = (double *)sval;
876                                 uint64_t * src = (uint64_t *)(sval + 1);
877                                 *sval = *dst < *src;
878                         }
879                         else if (attr == FLOAT >> 1)
880                         {
881                                 // Int < Float
882                                 uint64_t * dst = (uint64_t *)sval;
883                                 double * src = (double *)(sval + 1);
884                                 *sval = *dst < *src;
885                         }
886                         else
887                         {
888                                 *sval = *sval < sval[1];
889                         }
890
891                         *sattr = ABS | DEFINED;
892
893                         break;
894                 case NE:
895 //printf("evexpr(): NE\n");
896                         sattr--;
897                         sval--;
898
899                         if ((*sattr & TDB) != (sattr[1] & TDB))
900                                 return error(seg_error);
901
902                         // Extract float attributes from both terms and pack them
903                         // into a single value
904                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
905
906                         if (attr == (FLOAT | (FLOAT >> 1)))
907                         {
908                                 // Float <> Float
909                                 return error("comparison for equality with float types not allowed.");
910                         }
911                         else if (attr == FLOAT)
912                         {
913                                 // Float <> Int
914                                 return error("comparison for equality with float types not allowed.");
915                         }
916                         else if (attr == FLOAT >> 1)
917                         {
918                                 // Int != Float
919                                 return error("comparison for equality with float types not allowed.");
920                         }
921                         else
922                         {
923                                 *sval = *sval != sval[1];
924                         }
925
926                         *sattr = ABS | DEFINED;
927
928                         break;
929                 case '=':
930 //printf("evexpr(): =\n");
931                         sattr--;
932                         sval--;
933
934                         if ((*sattr & TDB) != (sattr[1] & TDB))
935                                 return error(seg_error);
936
937                         // Extract float attributes from both terms and pack them
938                         // into a single value
939                         attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
940
941                         if (attr == (FLOAT | (FLOAT >> 1)))
942                         {
943                                 // Float = Float
944                                 double * dst = (double *)sval;
945                                 double * src = (double *)(sval + 1);
946                                 *sval = *src == *dst;
947                         }
948                         else if (attr == FLOAT)
949                         {
950                                 // Float = Int
951                                 return error("equality with float ");
952                         }
953                         else if (attr == FLOAT >> 1)
954                         {
955                                 // Int == Float
956                                 uint64_t * dst = (uint64_t *)sval;
957                                 double * src = (double *)(sval + 1);
958                                 *sval = *src == *dst;
959                         }
960                         else
961                         {
962                                 *sval = *sval == sval[1];
963                         }
964
965                         *sattr = ABS | DEFINED;
966
967                         break;
968                 // All other binary operators must have two ABS items to work with.
969                 // They all produce an ABS value.
970                 default:
971 //printf("evexpr(): default\n");
972                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
973                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
974                         //error(seg_error);
975
976                         switch ((int)tk.u32[-1])
977                         {
978                         case '*':
979                                 sval--;
980                                 sattr--;                                        // Pop attrib
981 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
982                                 // Extract float attributes from both terms and pack them
983                                 // into a single value
984                                 attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
985                                 attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
986
987                                 if (attr == (FLOAT | (FLOAT >> 1)))
988                                 {
989                                         // Float * Float
990                                         double * dst = (double *)sval;
991                                         double * src = (double *)(sval + 1);
992                                         *dst *= *src;
993                                 }
994                                 else if (attr == FLOAT)
995                                 {
996                                         // Float * Int
997                                         double * dst = (double *)sval;
998                                         uint64_t * src = (uint64_t *)(sval + 1);
999                                         *dst *= *src;
1000                                 }
1001                                 else if (attr == FLOAT >> 1)
1002                                 {
1003                                         // Int * Float
1004                                         uint64_t * dst = (uint64_t *)sval;
1005                                         double * src = (double *)(sval + 1);
1006                                         *(double *)dst = *src * *dst;
1007                                 }
1008                                 else
1009                                 {
1010                                         *sval *= sval[1];
1011                                 }
1012 //printf("%i\n", *sval);
1013
1014                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1015                                 *sattr |= attr2;
1016
1017                                 break;
1018                         case '/':
1019                                 sval--;
1020                                 sattr--;                                        // Pop attrib
1021
1022
1023 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1024                                 // Extract float attributes from both terms and pack them
1025                                 // into a single value
1026                                 attr = sattr[0] & FLOAT | ((sattr[1] & FLOAT) >> 1);
1027                                 attr2 = sattr[0] | sattr[1] & FLOAT; // Returns FLOAT if either of the two numbers are FLOAT
1028
1029                                 if (attr == (FLOAT | (FLOAT >> 1)))
1030                                 {
1031                                         // Float / Float
1032                                         double * dst = (double *)sval;
1033                                         double * src = (double *)(sval + 1);
1034
1035                                         if (*src == 0)
1036                                                 return error("divide by zero");
1037
1038                                         *dst = *dst / *src;
1039                                 }
1040                                 else if (attr == FLOAT)
1041                                 {
1042                                         // Float / Int
1043                                         double * dst = (double *)sval;
1044                                         uint64_t * src = (uint64_t *)(sval + 1);
1045
1046                                         if (*src == 0)
1047                                                 return error("divide by zero");
1048
1049                                         *dst = *dst / *src;
1050                                 }
1051                                 else if (attr == FLOAT >> 1)
1052                                 {
1053                                         // Int / Float
1054                                         uint64_t * dst=(uint64_t *)sval;
1055                                         double * src=(double *)(sval + 1);
1056
1057                                         if (*src == 0)
1058                                                 return error("divide by zero");
1059
1060                                         *(double *)dst = *dst / *src;
1061                                 }
1062                                 else
1063                                 {
1064                                         if (sval[1] == 0)
1065                                                 return error("divide by zero");
1066 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1067
1068                                         // Compiler is picky here: Without casting these, it
1069                                         // discards the sign if dividing a negative # by a
1070                                         // positive one, creating a bad result. :-/
1071                                         // Definitely a side effect of using uint32_ts intead of
1072                                         // ints.
1073                                         *sval = (int32_t)sval[0] / (int32_t)sval[1];
1074                                 }
1075
1076                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1077                                 *sattr |= attr2;
1078
1079 //printf("%i\n", *sval);
1080                                 break;
1081                         case '%':
1082                                 sval--;
1083                                 sattr--;                                        // Pop attrib
1084
1085                                 if ((*sattr | sattr[1]) & FLOAT)
1086                                         return error("floating point numbers not allowed with operator '%'.");
1087
1088                                 if (sval[1] == 0)
1089                                         return error("mod (%) by zero");
1090
1091                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1092                                 *sval %= sval[1];
1093                                 break;
1094                         case SHL:
1095                                 sval--;
1096                                 sattr--;                                        // Pop attrib
1097
1098                                 if ((*sattr | sattr[1]) & FLOAT)
1099                                         return error("floating point numbers not allowed with operator '<<'.");
1100
1101                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1102                                 *sval <<= sval[1];
1103                                 break;
1104                         case SHR:
1105                                 sval--;
1106                                 sattr--;                                        // Pop attrib
1107
1108                                 if ((*sattr | sattr[1]) & FLOAT)
1109                                         return error("floating point numbers not allowed with operator '>>'.");
1110
1111                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1112                                 *sval >>= sval[1];
1113                                 break;
1114                         case '&':
1115                                 sval--;
1116                                 sattr--;                                        // Pop attrib
1117
1118                                 if ((*sattr | sattr[1]) & FLOAT)
1119                                         return error("floating point numbers not allowed with operator '&'.");
1120
1121                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1122                                 *sval &= sval[1];
1123                                 break;
1124                         case '^':
1125                                 sval--;
1126                                 sattr--;                                        // Pop attrib
1127
1128                                 if ((*sattr | sattr[1]) & FLOAT)
1129                                         return error("floating point numbers not allowed with operator '^'.");
1130
1131                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1132                                 *sval ^= sval[1];
1133                                 break;
1134                         case '|':
1135                                 sval--;
1136                                 sattr--;                                        // Pop attrib
1137
1138                                 if ((*sattr | sattr[1]) & FLOAT)
1139                                         return error("floating point numbers not allowed with operator '|'.");
1140
1141                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
1142                                 *sval |= sval[1];
1143                                 break;
1144                         default:
1145                                 interror(5);                            // Bad operator in expression stream
1146                         }
1147                 }
1148         }
1149
1150         if (esym != NULL)
1151                 *sattr &= ~DEFINED;
1152
1153         if (a_esym != NULL)
1154                 *a_esym = esym;
1155
1156         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
1157         // expressions where absolute values also existed. The absolutes were
1158         // overiding the symbol segments and not being included :(
1159         //*a_attr = *sattr | sym_seg;           // Copy value + attrib
1160
1161         *a_attr = *sattr;                                               // Copy value + attrib
1162         *a_value = *sval;
1163
1164         return OK;
1165 }
1166