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