]> Shamusworld >> Repos - rmac/blob - expr.c
Removed some dead code, as well as all gpu/dsp regbank check code (not only it was...
[rmac] / expr.c
1 //
2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2021 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, CR_FILESIZE, 0,
39         '!', '~', UNMINUS, UNLT, UNGT, 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 const char noflt_error[] = "operator not usable with float";
53
54 // Convert expression to postfix
55 static PTR evalTokenBuffer;             // Deposit tokens here (this is really a
56                                                                 // pointer to exprbuf from direct.c)
57                                                                 // (Can also be from others, like
58                                                                 // riscasm.c)
59 static int symbolNum;                   // Pointer to the entry in symbolPtr[]
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 // Initialize expression analyzer
76 //
77 void InitExpression(void)
78 {
79         // Initialize token-class table (all set to END)
80         for(int i=0; i<256; i++)
81                 tokenClass[i] = END;
82
83         int i = 0;
84
85         for(char * p=itokcl; *p!=1; p++)
86         {
87                 if (*p == 0)
88                         i++;
89                 else
90                         tokenClass[(int)(*p)] = (char)i;
91         }
92
93         symbolNum = 0;
94 }
95
96 //
97 // Binary operators (all the same precedence)
98 //
99 int expr0(void)
100 {
101         if (expr1() != OK)
102                 return ERROR;
103
104         while (tokenClass[*tok] >= MULT)
105         {
106                 TOKEN t = *tok++;
107
108                 if (expr1() != OK)
109                         return ERROR;
110
111                 *evalTokenBuffer.u32++ = t;
112         }
113
114         return OK;
115 }
116
117 //
118 // Unary operators (detect unary '-')
119 // ggn: If expression starts with a plus then also eat it up. For some reason
120 //      the parser gets confused when this happens and emits a "bad
121 //      expression".
122 //
123 int expr1(void)
124 {
125         char * p;
126         WORD w;
127
128         int class = tokenClass[*tok];
129
130         if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY)
131         {
132                 TOKEN t = *tok++;
133
134                 if (expr2() != OK)
135                         return ERROR;
136
137                 if (t == '-')
138                         t = UNMINUS;
139                 else if (t == '<')
140                         t = UNLT;
141                 else if (t == '>')
142                         t = UNGT;
143
144                 // With leading + we don't have to deposit anything to the buffer
145                 // because there's no unary '+' nor we have to do anything about it
146                 if (t != '+')
147                         *evalTokenBuffer.u32++ = t;
148         }
149         else if (class == SUNARY)
150         {
151                 switch (*tok++)
152                 {
153                 case CR_ABSCOUNT:
154                         if (cursect != ABS)
155                         {
156                                 *evalTokenBuffer.u32++ = CONST;
157                                 *evalTokenBuffer.u64++ = sect[ABS].sloc;
158                         }
159                         else
160                         {
161                                 *evalTokenBuffer.u32++ = CONST;
162                                 *evalTokenBuffer.u64++ = sloc;
163                         }
164                         break;
165                 case CR_FILESIZE:
166                         if (*tok++ != STRING)
167                                 return error("^^FILESIZE expects filename inside string");
168                         *evalTokenBuffer.u32++ = CONST;
169                         // @@copypasted from d_incbin, maybe factor this out somehow?
170                         // Attempt to open the include file in the current directory, then (if that
171                         // failed) try list of include files passed in the enviroment string or by
172                         // the "-d" option.
173                         int fd, i;
174                         char buf1[256];
175
176                         if ((fd = open(string[*tok], _OPEN_INC)) < 0)
177                         {
178                                 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
179                                 {
180                                         fd = strlen(buf1);
181
182                                         // Append path char if necessary
183                                         if ((fd > 0) && (buf1[fd - 1] != SLASHCHAR))
184                                                 strcat(buf1, SLASHSTRING);
185
186                                         strcat(buf1, string[*tok]);
187
188                                         if ((fd = open(buf1, _OPEN_INC)) >= 0)
189                                                 goto allright;
190                                 }
191
192                                 return error("cannot open: \"%s\"", string[tok[1]]);
193                         }
194
195 allright:
196                         *evalTokenBuffer.u64++ = (uint64_t)lseek(fd, 0L, SEEK_END);
197                         close(fd);
198
199                         // Advance tok because of consumed string token
200                         tok++;
201                         break;
202                 case CR_TIME:
203                         *evalTokenBuffer.u32++ = CONST;
204                         *evalTokenBuffer.u64++ = dos_time();
205                         break;
206                 case CR_DATE:
207                         *evalTokenBuffer.u32++ = CONST;
208                         *evalTokenBuffer.u64++ = dos_date();
209                         break;
210                 case CR_MACDEF: // ^^macdef <macro-name>
211                         if (*tok++ != SYMBOL)
212                                 return error(missym_error);
213
214                         p = string[*tok++];
215                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
216                         *evalTokenBuffer.u32++ = CONST;
217                         *evalTokenBuffer.u64++ = (uint64_t)w;
218                         break;
219                 case CR_DEFINED:
220                         w = DEFINED;
221                         goto getsym;
222                 case CR_REFERENCED:
223                         w = REFERENCED;
224 getsym:
225                         if (*tok++ != SYMBOL)
226                                 return error(missym_error);
227
228                         p = string[*tok++];
229                         int j = (*p == '.' ? curenv : 0);
230                         SYM * sy = lookup(p, LABEL, j);
231                         w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
232                         *evalTokenBuffer.u32++ = CONST;
233                         *evalTokenBuffer.u64++ = (uint64_t)w;
234                         break;
235                 case CR_STREQ:
236                         if (*tok != SYMBOL && *tok != STRING)
237                                 return error(str_error);
238
239                         p = string[tok[1]];
240                         tok +=2;
241
242                         if (*tok++ != ',')
243                                 return error(comma_error);
244
245                         if (*tok != SYMBOL && *tok != STRING)
246                                 return error(str_error);
247
248                         char * p2 = string[tok[1]];
249                         tok += 2;
250
251                         w = (WORD)(!strcmp(p, p2));
252                         *evalTokenBuffer.u32++ = CONST;
253                         *evalTokenBuffer.u64++ = (uint64_t)w;
254                         break;
255                 }
256         }
257         else
258                 return expr2();
259
260         return OK;
261 }
262
263 //
264 // Terminals (CONSTs) and parenthesis grouping
265 //
266 int expr2(void)
267 {
268         PTR ptk;
269
270         switch (*tok++)
271         {
272         case CONST:
273                 ptk.u32 = tok;
274                 *evalTokenBuffer.u32++ = CONST;
275                 *evalTokenBuffer.u64++ = *ptk.u64++;
276                 tok = ptk.u32;
277                 break;
278         case FCONST:
279                 ptk.u32 = tok;
280                 *evalTokenBuffer.u32++ = FCONST;
281                 *evalTokenBuffer.u64++ = *ptk.u64++;
282                 tok = ptk.u32;
283                 break;
284         case SYMBOL:
285         {
286                 char * p = string[*tok++];
287                 int j = (*p == '.' ? curenv : 0);
288                 SYM * sy = lookup(p, LABEL, j);
289
290                 if (sy == NULL)
291                         sy = NewSymbol(p, LABEL, j);
292
293                 *evalTokenBuffer.u32++ = SYMBOL;
294                 *evalTokenBuffer.u32++ = symbolNum;
295                 symbolPtr[symbolNum] = sy;
296                 symbolNum++;
297                 break;
298         }
299         case STRING:
300                 *evalTokenBuffer.u32++ = CONST;
301                 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
302                 break;
303         case '(':
304                 if (expr0() != OK)
305                         return ERROR;
306
307                 if (*tok++ != ')')
308                         return error("missing closing parenthesis ')'");
309
310                 break;
311         case '[':
312                 if (expr0() != OK)
313                         return ERROR;
314
315                 if (*tok++ != ']')
316                         return error("missing closing bracket ']'");
317
318                 break;
319         case '{':
320                 if (expr0() != OK)      // Eat up first parameter (register or immediate)
321                         return ERROR;
322
323                 if (*tok++ != ':')      // Demand a ':' there
324                         return error("missing colon ':'");
325
326                 if (expr0() != OK)      // Eat up second parameter (register or immediate)
327                         return ERROR;
328
329                 if (*tok++ != '}')
330                         return error("missing closing brace '}'");
331
332                 break;
333         case '$':
334                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
335                 *evalTokenBuffer.u32++ = sloc;                          // Current location
336                 *evalTokenBuffer.u32++ = DEFINED | ((orgactive | org68k_active) ? 0 : cursect);         // Store attribs
337                 break;
338         case '*':
339                 *evalTokenBuffer.u32++ = ACONST;                        // Attributed const
340
341                 // pcloc == location at start of line
342                 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
343                 // '*' takes attributes of current section, not ABS!
344                 // Also, if we're ORG'd, the symbol is absolute
345                 *evalTokenBuffer.u32++ = DEFINED | ((orgactive | org68k_active) ? 0 : cursect);
346                 break;
347         default:
348                 return error("bad expression");
349         }
350
351         return OK;
352 }
353
354 //
355 // Recursive-descent expression analyzer (with some simple speed hacks)
356 //
357 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
358 {
359         // Passed in values (once derefenced, that is) can all be zero. They are
360         // there so that the expression analyzer can fill them in as needed. The
361         // expression analyzer gets its input from the global token pointer "tok",
362         // and not from anything passed in by the user.
363         SYM * symbol;
364         char * p;
365         int j;
366         PTR ptk;
367
368         evalTokenBuffer.u32 = otk;      // Set token pointer to 'exprbuf' (direct.c)
369                                                                 // Also set in various other places too (riscasm.c,
370                                                                 // e.g.)
371
372         // Optimize for single constant or single symbol.
373         // Shamus: Seems to me that this could be greatly simplified by 1st
374         //         checking if the first token is a multibyte token, *then*
375         //         checking if there's an EOL after it depending on the actual
376         //         length of the token (multiple vs. single). Otherwise, we have
377         //         the horror show that is the following:
378         if ((tok[1] == EOL
379                         && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
380                 || ((tok[0] == SYMBOL)
381                         && (tokenClass[tok[2]] < UNARY))
382                 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
383                 )
384 // 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 naively checking tok[1] for an EOL. O_o
385         {
386                 if (*tok == CONST)
387                 {
388                         ptk.u32 = tok;
389                         *evalTokenBuffer.u32++ = *ptk.u32++;
390                         *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
391                         *a_attr = ABS | DEFINED;
392                         tok = ptk.u32;
393
394                         if (a_esym != NULL)
395                                 *a_esym = NULL;
396
397 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
398                 }
399 // Not sure that removing float constant here is going to break anything and/or
400 // make things significantly slower, but having this here seems to cause the
401 // complexity of the check to get to this part of the parse to go through the
402 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
403 #if 0
404                 else if (*tok == FCONST)
405                 {
406                         *evalTokenBuffer.u32++ = *tok++;
407                         *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
408                         *a_attr = ABS | DEFINED | FLOAT;
409
410                         if (a_esym != NULL)
411                                 *a_esym = NULL;
412
413 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
414                 }
415 #endif
416                 else if (*tok == '*')
417                 {
418                         *evalTokenBuffer.u32++ = CONST;
419
420                         if (orgactive | org68k_active)
421                         {
422                                 *evalTokenBuffer.u64++ = *a_value = orgaddr;
423                                 *a_attr = DEFINED;      // We have ORG active, it doesn't belong in a section!
424                         }
425                         else
426                         {
427                                 *evalTokenBuffer.u64++ = *a_value = pcloc;
428                                 // '*' takes attributes of current section, not ABS!
429                                 *a_attr = cursect | DEFINED;
430                         }
431
432
433                         if (a_esym != NULL)
434                                 *a_esym = NULL;
435
436                         tok++;
437                 }
438                 else if (*tok == STRING || *tok == SYMBOL)
439                 {
440                         p = string[tok[1]];
441                         j = (*p == '.' ? curenv : 0);
442                         symbol = lookup(p, LABEL, j);
443
444                         if (symbol == NULL)
445                                 symbol = NewSymbol(p, LABEL, j);
446
447                         symbol->sattr |= REFERENCED;
448
449                         // Check for undefined register equates, but only if it's not part
450                         // of a #<SYMBOL> construct, as it could be that the label that's
451                         // been undefined may later be used as an address label--which
452                         // means it will be fixed up later, and thus, not an error.
453                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
454                         {
455                                 error("undefined register equate '%s'", 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                         *a_value = (symbol->sattr & DEFINED ? symbol->svalue : 0);
473                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
474
475                         if (symbol->sattre & EQUATEDREG)
476                         {
477                                 *a_attr |= RISCREG; // Mark it as a register, 'cause it is
478                                 *a_esym = symbol;
479                         }
480
481                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
482                                 && a_esym != NULL)
483                                 *a_esym = symbol;
484
485                         tok += 2;
486                 }
487                 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
488                 else if (m6502)
489                 {
490                         *evalTokenBuffer.u32++ = *tok++;
491                 }
492                 else
493                 {
494                         // Unknown type here... Alert the user!,
495                         error("undefined RISC register in expression [token=$%X]", *tok);
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 // Evaluate expression.
514 // If the expression involves only ONE external symbol, the expression is
515 // UNDEFINED, but it's value includes everything but the symbol value, and
516 // 'a_esym' is set to the external symbol.
517 //
518 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
519 {
520         WORD attr;
521         SYM * sy;
522         uint64_t * sval = evstk;                                // (Empty) initial stack
523         WORD * sattr = evattr;
524         SYM * esym = NULL;                                              // No external symbol involved
525         WORD sym_seg = 0;
526         PTR tk;
527         tk.u32 = _tk;
528
529         while (*tk.u32 != ENDEXPR)
530         {
531                 switch ((int)*tk.u32++)
532                 {
533                 case SYMBOL:
534                         sy = symbolPtr[*tk.u32++];
535                         sy->sattr |= REFERENCED;                // Set "referenced" bit
536
537                         if (!(sy->sattr & DEFINED))
538                         {
539                                 // Reference to undefined symbol
540                                 if (!(sy->sattr & GLOBAL))
541                                 {
542                                         *a_attr = 0;
543                                         *a_value = 0;
544                                         return OK;
545                                 }
546
547                                 if (esym != NULL)                       // Check for multiple externals
548                                         return error(seg_error);
549
550                                 esym = sy;
551                         }
552
553                         if (sy->sattr & DEFINED)
554                                 *++sval = sy->svalue;           // Push symbol's value
555                         else
556                                 *++sval = 0;                            // 0 for undefined symbols
557
558                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
559                         sym_seg = (WORD)(sy->sattr & TDB);
560                         break;
561
562                 case CONST:
563                         *++sval = *tk.u64++;
564                         *++sattr = ABS | DEFINED;               // Push simple attribs
565                         break;
566
567                 case FCONST:
568                         // Even though it's a double, we can treat it like a uint64_t since
569                         // we're just moving the bits around.
570                         *++sval = *tk.u64++;
571                         *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
572                         break;
573
574                 case ACONST:
575                         *++sval = *tk.u32++;                            // Push value
576                         *++sattr = (WORD)*tk.u32++;                     // Push attribs
577                         break;
578
579                         // Binary "+" and "-" matrix:
580                         //
581                         //                ABS    Sect     Other
582                         //     ----------------------------
583                         //   ABS     |  ABS   |  Sect  |  Other |
584                         //   Sect    |  Sect  |  [1]   |  Error |
585                         //   Other   |  Other |  Error |  [1]   |
586                         //      ----------------------------
587                         //
588                         //   [1] + : Error
589                         //       - : ABS
590
591                 case '+':
592                         --sval;                                                 // Pop value
593                         --sattr;                                                // Pop attrib
594                         // Get FLOAT attribute, if any
595                         attr = (sattr[0] | sattr[1]) & FLOAT;
596
597                         // Since adding an int to a fp value promotes it to a fp value, we
598                         // don't care whether it's first or second; we cast to to a double
599                         // regardless.
600                         if (attr == FLOAT)
601                         {
602                                 PTR p;
603                                 p.u64 = sval;
604                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
605                                 p.u64++;
606                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
607                                 *(double *)sval = fpval1 + fpval2;
608                         }
609                         else
610                         {
611                                 *sval += sval[1];                               // Compute value
612                         }
613
614                         if (!(*sattr & TDB))
615                                 *sattr = sattr[1] | attr;
616                         else if (sattr[1] & TDB)
617                                 return error(seg_error);
618
619                         break;
620
621                 case '-':
622                         --sval;                                                 // Pop value
623                         --sattr;                                                // Pop attrib
624                         // Get FLOAT attribute, if any
625                         attr = (sattr[0] | sattr[1]) & FLOAT;
626
627                         // Since subtracting an int to a fp value promotes it to a fp
628                         // value, we don't care whether it's first or second; we cast to to
629                         // a double regardless.
630                         if (attr == FLOAT)
631                         {
632                                 PTR p;
633                                 p.u64 = sval;
634                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
635                                 p.u64++;
636                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
637                                 *(double *)sval = fpval1 - fpval2;
638                         }
639                         else
640                         {
641                                 *sval -= sval[1];
642                         }
643
644                         *sattr |= attr;                                 // Inherit FLOAT attribute
645                         attr = (WORD)(*sattr & TDB);
646                         // If symbol1 is ABS, take attributes from symbol2
647                         if (!attr)
648                                 *sattr = sattr[1];
649                         // Otherwise, they're both TDB and so attributes cancel out
650                         else if (sattr[1] & TDB)
651                                 *sattr &= ~TDB;
652
653                         break;
654
655                 // Unary operators only work on ABS items
656                 case UNMINUS:
657                         if (*sattr & TDB)
658                                 return error(seg_error);
659
660                         if (*sattr & FLOAT)
661                         {
662                                 double * dst = (double *)sval;
663                                 *dst = -*dst;
664                                 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
665                         }
666                         else
667                         {
668                                 *sval = -(int64_t)*sval;
669                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
670                         }
671
672                         break;
673
674                 case UNLT: // Unary < (get the low byte of a word)
675                         if (*sattr & TDB)
676                                 return error(seg_error);
677
678                         if (*sattr & FLOAT)
679                                 return error(noflt_error);
680
681                         *sval = (int64_t)((*sval) & 0x00FF);
682                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
683                         break;
684
685                 case UNGT: // Unary > (get the high byte of a word)
686                         if (*sattr & TDB)
687                                 return error(seg_error);
688
689                         if (*sattr & FLOAT)
690                                 return error(noflt_error);
691
692                         *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
693                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
694                         break;
695
696                 case '!':
697                         if (*sattr & TDB)
698                                 return error(seg_error);
699
700                         if (*sattr & FLOAT)
701                                 return error("floating point numbers not allowed with operator '!'.");
702
703                         *sval = !*sval;
704                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
705                         break;
706
707                 case '~':
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                         sattr--;
722                         sval--;
723
724                         if ((*sattr & TDB) != (sattr[1] & TDB))
725                                 return error(seg_error);
726
727                         // Get FLOAT attribute, if any
728                         attr = (sattr[0] | sattr[1]) & FLOAT;
729
730                         // Cast any ints in the comparison to double, if there's at least
731                         // one double in the comparison.
732                         if (attr == FLOAT)
733                         {
734                                 PTR p;
735                                 p.u64 = sval;
736                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
737                                 p.u64++;
738                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
739                                 *sval = (fpval1 <= fpval2);
740                         }
741                         else
742                         {
743                                 *sval = (*sval <= sval[1]);
744                         }
745
746                         *sattr = ABS | DEFINED;
747                         break;
748
749                 case GE:
750                         sattr--;
751                         sval--;
752
753                         if ((*sattr & TDB) != (sattr[1] & TDB))
754                                 return error(seg_error);
755
756                         // Get FLOAT attribute, if any
757                         attr = (sattr[0] | sattr[1]) & FLOAT;
758
759                         // Cast any ints in the comparison to double, if there's at least
760                         // one double in the comparison.
761                         if (attr == FLOAT)
762                         {
763                                 PTR p;
764                                 p.u64 = sval;
765                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
766                                 p.u64++;
767                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
768                                 *sval = (fpval1 >= fpval2);
769                         }
770                         else
771                         {
772                                 *sval = (*sval >= sval[1]);
773                         }
774
775                         *sattr = ABS | DEFINED;
776                         break;
777
778                 case '>':
779                         sattr--;
780                         sval--;
781
782                         if ((*sattr & TDB) != (sattr[1] & TDB))
783                                 return error(seg_error);
784
785                         // Get FLOAT attribute, if any
786                         attr = (sattr[0] | sattr[1]) & FLOAT;
787
788                         // Cast any ints in the comparison to double, if there's at least
789                         // one double in the comparison.
790                         if (attr == FLOAT)
791                         {
792                                 PTR p;
793                                 p.u64 = sval;
794                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
795                                 p.u64++;
796                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
797                                 *sval = (fpval1 > fpval2);
798                         }
799                         else
800                         {
801                                 *sval = (*sval > sval[1]);
802                         }
803
804                         *sattr = ABS | DEFINED;
805                         break;
806
807                 case '<':
808                         sattr--;
809                         sval--;
810
811                         if ((*sattr & TDB) != (sattr[1] & TDB))
812                                 return error(seg_error);
813
814                         // Get FLOAT attribute, if any
815                         attr = (sattr[0] | sattr[1]) & FLOAT;
816
817                         // Cast any ints in the comparison to double, if there's at least
818                         // one double in the comparison.
819                         if (attr == FLOAT)
820                         {
821                                 PTR p;
822                                 p.u64 = sval;
823                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
824                                 p.u64++;
825                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
826                                 *sval = (fpval1 < fpval2);
827                         }
828                         else
829                         {
830                                 *sval = (*sval < sval[1]);
831                         }
832
833                         *sattr = ABS | DEFINED;         // Expr forced to ABS
834                         break;
835
836                 case NE:
837                         sattr--;
838                         sval--;
839
840                         if ((*sattr & TDB) != (sattr[1] & TDB))
841                                 return error(seg_error);
842
843                         // Get FLOAT attribute, if any
844                         attr = (sattr[0] | sattr[1]) & FLOAT;
845
846                         // Cast any ints in the comparison to double, if there's at least
847                         // one double in the comparison.
848                         if (attr == FLOAT)
849                         {
850                                 PTR p;
851                                 p.u64 = sval;
852                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
853                                 p.u64++;
854                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
855                                 *sval = (fpval1 != fpval2);
856                         }
857                         else
858                         {
859                                 *sval = (*sval != sval[1]);
860                         }
861
862                         *sattr = ABS | DEFINED;         // Expr forced to ABS
863                         break;
864
865                 case '=':
866                         sattr--;
867                         sval--;
868
869                         if ((*sattr & TDB) != (sattr[1] & TDB))
870                                 return error(seg_error);
871
872                         // Get FLOAT attribute, if any
873                         attr = (sattr[0] | sattr[1]) & FLOAT;
874
875                         // Cast any ints in the comparison to double, if there's at least
876                         // one double in the comparison.
877                         if (attr == FLOAT)
878                         {
879                                 PTR p;
880                                 p.u64 = sval;
881                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
882                                 p.u64++;
883                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
884                                 *sval = (fpval1 == fpval2);
885                         }
886                         else
887                         {
888                                 *sval = (*sval == sval[1]);
889                         }
890
891                         *sattr = ABS | DEFINED;         // Expr forced to ABS
892
893                         break;
894
895                 // All other binary operators must have two ABS items to work with.
896                 // They all produce an ABS value.
897                 // Shamus: Is this true? There's at least one counterexample of legit
898                 //         code where this assumption fails to produce correct code.
899                 default:
900
901                         switch ((int)tk.u32[-1])
902                         {
903                         case '*':
904                                 sval--;
905                                 sattr--;
906                                 // Get FLOAT attribute, if any
907                                 attr = (sattr[0] | sattr[1]) & FLOAT;
908
909                                 // Since multiplying an int to a fp value promotes it to a fp
910                                 // value, we don't care whether it's first or second; it will
911                                 // be cast to a double regardless.
912 /*
913 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.
914 */
915                                 if (attr == FLOAT)
916                                 {
917                                         PTR p;
918                                         p.u64 = sval;
919                                         double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
920                                         p.u64++;
921                                         double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
922                                         *(double *)sval = fpval1 * fpval2;
923                                 }
924                                 else
925                                 {
926                                         *sval *= sval[1];
927                                 }
928
929                                 break;
930
931                         case '/':
932                                 sval--;
933                                 sattr--;
934                                 // Get FLOAT attribute, if any
935                                 attr = (sattr[0] | sattr[1]) & FLOAT;
936
937                                 if (attr == FLOAT)
938                                 {
939                                         PTR p;
940                                         p.u64 = sval;
941                                         double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
942                                         p.u64++;
943                                         double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
944
945                                         if (fpval2 == 0)
946                                                 return error("divide by zero");
947
948                                         *(double *)sval = fpval1 / fpval2;
949                                 }
950                                 else
951                                 {
952                                         if (sval[1] == 0)
953                                                 return error("divide by zero");
954
955                                         // Compiler is picky here: Without casting these, it
956                                         // discards the sign if dividing a negative # by a
957                                         // positive one, creating a bad result. :-/
958                                         // Definitely a side effect of using uint32_ts intead of
959                                         // ints.
960                                         *sval = (int32_t)sval[0] / (int32_t)sval[1];
961                                 }
962
963                                 break;
964
965                         case '%':
966                                 sval--;
967                                 sattr--;
968
969                                 if ((*sattr | sattr[1]) & FLOAT)
970                                         return error("floating point numbers not allowed with operator '%'.");
971
972                                 if (sval[1] == 0)
973                                         return error("mod (%) by zero");
974
975                                 *sval %= sval[1];
976                                 break;
977
978                         case SHL:
979                                 sval--;
980                                 sattr--;                                        // Pop attrib
981
982                                 if ((*sattr | sattr[1]) & FLOAT)
983                                         return error("floating point numbers not allowed with operator '<<'.");
984
985                                 *sval <<= sval[1];
986                                 break;
987
988                         case SHR:
989                                 sval--;
990                                 sattr--;                                        // Pop attrib
991
992                                 if ((*sattr | sattr[1]) & FLOAT)
993                                         return error("floating point numbers not allowed with operator '>>'.");
994
995                                 *sval >>= sval[1];
996                                 break;
997
998                         case '&':
999                                 sval--;
1000                                 sattr--;                                        // Pop attrib
1001
1002                                 if ((*sattr | sattr[1]) & FLOAT)
1003                                         return error("floating point numbers not allowed with operator '&'.");
1004
1005                                 *sval &= sval[1];
1006                                 break;
1007
1008                         case '^':
1009                                 sval--;
1010                                 sattr--;                                        // Pop attrib
1011
1012                                 if ((*sattr | sattr[1]) & FLOAT)
1013                                         return error("floating point numbers not allowed with operator '^'.");
1014
1015                                 *sval ^= sval[1];
1016                                 break;
1017
1018                         case '|':
1019                                 sval--;
1020                                 sattr--;
1021
1022                                 if ((*sattr | sattr[1]) & FLOAT)
1023                                         return error("floating point numbers not allowed with operator '|'.");
1024
1025                                 *sval |= sval[1];
1026                                 break;
1027
1028                         default:
1029                                 // Bad operator in expression stream (this should never happen!)
1030                                 interror(5);
1031                         }
1032                 }
1033         }
1034
1035         if (esym != NULL)
1036                 *sattr &= ~DEFINED;
1037
1038         if (a_esym != NULL)
1039                 *a_esym = esym;
1040
1041         // Copy value + attrib into return variables
1042         *a_value = *sval;
1043         *a_attr = *sattr;
1044
1045         return OK;
1046 }
1047
1048 //
1049 // Count the # of tokens in the passed in expression
1050 // N.B.: 64-bit constants count as two tokens each
1051 //
1052 uint16_t ExpressionLength(TOKEN * tk)
1053 {
1054         uint16_t length;
1055
1056         for(length=0; tk[length]!=ENDEXPR; length++)
1057         {
1058                 // Add one to length for 2X tokens, two for 3X tokens
1059                 if (tk[length] == SYMBOL)
1060                         length++;
1061                 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1062                         length += 2;
1063         }
1064
1065         // Add 1 for ENDEXPR
1066         length++;
1067
1068         return length;
1069 }