]> Shamusworld >> Repos - rmac/blob - expr.c
.equr overhaul part 3: store and handle banks in .equr evaluation
[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 (moved to EvaluateRegisterFromTokenStream()))
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                         if (symbol->sattre & EQUATEDREG)
498                         {
499                                 *a_attr |= RISCREG; // Mark it as a register, 'cause it is
500                                 *a_esym = symbol;
501                         }
502
503                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
504                                 && a_esym != NULL)
505                                 *a_esym = symbol;
506
507                         tok += 2;
508                 }
509                 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
510                 else if (m6502)
511                 {
512                         *evalTokenBuffer.u32++ = *tok++;
513                 }
514                 else
515                 {
516                         // Unknown type here... Alert the user!,
517                         error("undefined RISC register in expression [token=$%X]", *tok);
518                         // Prevent spurious error reporting...
519                         tok++;
520                         return ERROR;
521                 }
522
523                 *evalTokenBuffer.u32++ = ENDEXPR;
524                 return OK;
525         }
526
527         if (expr0() != OK)
528                 return ERROR;
529
530         *evalTokenBuffer.u32++ = ENDEXPR;
531         return evexpr(otk, a_value, a_attr, a_esym);
532 }
533
534 //
535 // Evaluate expression.
536 // If the expression involves only ONE external symbol, the expression is
537 // UNDEFINED, but it's value includes everything but the symbol value, and
538 // 'a_esym' is set to the external symbol.
539 //
540 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
541 {
542         WORD attr;
543         SYM * sy;
544         uint64_t * sval = evstk;                                // (Empty) initial stack
545         WORD * sattr = evattr;
546         SYM * esym = NULL;                                              // No external symbol involved
547         WORD sym_seg = 0;
548         PTR tk;
549         tk.u32 = _tk;
550
551         while (*tk.u32 != ENDEXPR)
552         {
553                 switch ((int)*tk.u32++)
554                 {
555                 case SYMBOL:
556                         sy = symbolPtr[*tk.u32++];
557                         sy->sattr |= REFERENCED;                // Set "referenced" bit
558
559                         if (!(sy->sattr & DEFINED))
560                         {
561                                 // Reference to undefined symbol
562                                 if (!(sy->sattr & GLOBAL))
563                                 {
564                                         *a_attr = 0;
565                                         *a_value = 0;
566                                         return OK;
567                                 }
568
569                                 if (esym != NULL)                       // Check for multiple externals
570                                         return error(seg_error);
571
572                                 esym = sy;
573                         }
574
575                         if (sy->sattr & DEFINED)
576                                 *++sval = sy->svalue;           // Push symbol's value
577                         else
578                                 *++sval = 0;                            // 0 for undefined symbols
579
580                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
581                         sym_seg = (WORD)(sy->sattr & TDB);
582                         break;
583
584                 case CONST:
585                         *++sval = *tk.u64++;
586                         *++sattr = ABS | DEFINED;               // Push simple attribs
587                         break;
588
589                 case FCONST:
590                         // Even though it's a double, we can treat it like a uint64_t since
591                         // we're just moving the bits around.
592                         *++sval = *tk.u64++;
593                         *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
594                         break;
595
596                 case ACONST:
597                         *++sval = *tk.u32++;                            // Push value
598                         *++sattr = (WORD)*tk.u32++;                     // Push attribs
599                         break;
600
601                         // Binary "+" and "-" matrix:
602                         //
603                         //                ABS    Sect     Other
604                         //     ----------------------------
605                         //   ABS     |  ABS   |  Sect  |  Other |
606                         //   Sect    |  Sect  |  [1]   |  Error |
607                         //   Other   |  Other |  Error |  [1]   |
608                         //      ----------------------------
609                         //
610                         //   [1] + : Error
611                         //       - : ABS
612
613                 case '+':
614                         --sval;                                                 // Pop value
615                         --sattr;                                                // Pop attrib
616                         // Get FLOAT attribute, if any
617                         attr = (sattr[0] | sattr[1]) & FLOAT;
618
619                         // Since adding an int to a fp value promotes it to a fp value, we
620                         // don't care whether it's first or second; we cast to to a double
621                         // regardless.
622                         if (attr == FLOAT)
623                         {
624                                 PTR p;
625                                 p.u64 = sval;
626                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
627                                 p.u64++;
628                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
629                                 *(double *)sval = fpval1 + fpval2;
630                         }
631                         else
632                         {
633                                 *sval += sval[1];                               // Compute value
634                         }
635
636                         if (!(*sattr & TDB))
637                                 *sattr = sattr[1] | attr;
638                         else if (sattr[1] & TDB)
639                                 return error(seg_error);
640
641                         break;
642
643                 case '-':
644                         --sval;                                                 // Pop value
645                         --sattr;                                                // Pop attrib
646                         // Get FLOAT attribute, if any
647                         attr = (sattr[0] | sattr[1]) & FLOAT;
648
649                         // Since subtracting an int to a fp value promotes it to a fp
650                         // value, we don't care whether it's first or second; we cast to to
651                         // a double regardless.
652                         if (attr == FLOAT)
653                         {
654                                 PTR p;
655                                 p.u64 = sval;
656                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
657                                 p.u64++;
658                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
659                                 *(double *)sval = fpval1 - fpval2;
660                         }
661                         else
662                         {
663                                 *sval -= sval[1];
664                         }
665
666                         *sattr |= attr;                                 // Inherit FLOAT attribute
667                         attr = (WORD)(*sattr & TDB);
668                         // If symbol1 is ABS, take attributes from symbol2
669                         if (!attr)
670                                 *sattr = sattr[1];
671                         // Otherwise, they're both TDB and so attributes cancel out
672                         else if (sattr[1] & TDB)
673                                 *sattr &= ~TDB;
674
675                         break;
676
677                 // Unary operators only work on ABS items
678                 case UNMINUS:
679                         if (*sattr & TDB)
680                                 return error(seg_error);
681
682                         if (*sattr & FLOAT)
683                         {
684                                 double * dst = (double *)sval;
685                                 *dst = -*dst;
686                                 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
687                         }
688                         else
689                         {
690                                 *sval = -(int64_t)*sval;
691                                 *sattr = ABS | DEFINED;                 // Expr becomes absolute
692                         }
693
694                         break;
695
696                 case UNLT: // Unary < (get the low byte of a word)
697                         if (*sattr & TDB)
698                                 return error(seg_error);
699
700                         if (*sattr & FLOAT)
701                                 return error(noflt_error);
702
703                         *sval = (int64_t)((*sval) & 0x00FF);
704                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
705                         break;
706
707                 case UNGT: // Unary > (get the high byte of a word)
708                         if (*sattr & TDB)
709                                 return error(seg_error);
710
711                         if (*sattr & FLOAT)
712                                 return error(noflt_error);
713
714                         *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
715                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
716                         break;
717
718                 case '!':
719                         if (*sattr & TDB)
720                                 return error(seg_error);
721
722                         if (*sattr & FLOAT)
723                                 return error("floating point numbers not allowed with operator '!'.");
724
725                         *sval = !*sval;
726                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
727                         break;
728
729                 case '~':
730                         if (*sattr & TDB)
731                                 return error(seg_error);
732
733                         if (*sattr & FLOAT)
734                                 return error("floating point numbers not allowed with operator '~'.");
735
736                         *sval = ~*sval;
737                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
738                         break;
739
740                 // Comparison operators must have two values that
741                 // are in the same segment, but that's the only requirement.
742                 case LE:
743                         sattr--;
744                         sval--;
745
746                         if ((*sattr & TDB) != (sattr[1] & TDB))
747                                 return error(seg_error);
748
749                         // Get FLOAT attribute, if any
750                         attr = (sattr[0] | sattr[1]) & FLOAT;
751
752                         // Cast any ints in the comparison to double, if there's at least
753                         // one double in the comparison.
754                         if (attr == FLOAT)
755                         {
756                                 PTR p;
757                                 p.u64 = sval;
758                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
759                                 p.u64++;
760                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
761                                 *sval = (fpval1 <= fpval2);
762                         }
763                         else
764                         {
765                                 *sval = (*sval <= sval[1]);
766                         }
767
768                         *sattr = ABS | DEFINED;
769                         break;
770
771                 case GE:
772                         sattr--;
773                         sval--;
774
775                         if ((*sattr & TDB) != (sattr[1] & TDB))
776                                 return error(seg_error);
777
778                         // Get FLOAT attribute, if any
779                         attr = (sattr[0] | sattr[1]) & FLOAT;
780
781                         // Cast any ints in the comparison to double, if there's at least
782                         // one double in the comparison.
783                         if (attr == FLOAT)
784                         {
785                                 PTR p;
786                                 p.u64 = sval;
787                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
788                                 p.u64++;
789                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
790                                 *sval = (fpval1 >= fpval2);
791                         }
792                         else
793                         {
794                                 *sval = (*sval >= sval[1]);
795                         }
796
797                         *sattr = ABS | DEFINED;
798                         break;
799
800                 case '>':
801                         sattr--;
802                         sval--;
803
804                         if ((*sattr & TDB) != (sattr[1] & TDB))
805                                 return error(seg_error);
806
807                         // Get FLOAT attribute, if any
808                         attr = (sattr[0] | sattr[1]) & FLOAT;
809
810                         // Cast any ints in the comparison to double, if there's at least
811                         // one double in the comparison.
812                         if (attr == FLOAT)
813                         {
814                                 PTR p;
815                                 p.u64 = sval;
816                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
817                                 p.u64++;
818                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
819                                 *sval = (fpval1 > fpval2);
820                         }
821                         else
822                         {
823                                 *sval = (*sval > sval[1]);
824                         }
825
826                         *sattr = ABS | DEFINED;
827                         break;
828
829                 case '<':
830                         sattr--;
831                         sval--;
832
833                         if ((*sattr & TDB) != (sattr[1] & TDB))
834                                 return error(seg_error);
835
836                         // Get FLOAT attribute, if any
837                         attr = (sattr[0] | sattr[1]) & FLOAT;
838
839                         // Cast any ints in the comparison to double, if there's at least
840                         // one double in the comparison.
841                         if (attr == FLOAT)
842                         {
843                                 PTR p;
844                                 p.u64 = sval;
845                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
846                                 p.u64++;
847                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
848                                 *sval = (fpval1 < fpval2);
849                         }
850                         else
851                         {
852                                 *sval = (*sval < sval[1]);
853                         }
854
855                         *sattr = ABS | DEFINED;         // Expr forced to ABS
856                         break;
857
858                 case NE:
859                         sattr--;
860                         sval--;
861
862                         if ((*sattr & TDB) != (sattr[1] & TDB))
863                                 return error(seg_error);
864
865                         // Get FLOAT attribute, if any
866                         attr = (sattr[0] | sattr[1]) & FLOAT;
867
868                         // Cast any ints in the comparison to double, if there's at least
869                         // one double in the comparison.
870                         if (attr == FLOAT)
871                         {
872                                 PTR p;
873                                 p.u64 = sval;
874                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
875                                 p.u64++;
876                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
877                                 *sval = (fpval1 != fpval2);
878                         }
879                         else
880                         {
881                                 *sval = (*sval != sval[1]);
882                         }
883
884                         *sattr = ABS | DEFINED;         // Expr forced to ABS
885                         break;
886
887                 case '=':
888                         sattr--;
889                         sval--;
890
891                         if ((*sattr & TDB) != (sattr[1] & TDB))
892                                 return error(seg_error);
893
894                         // Get FLOAT attribute, if any
895                         attr = (sattr[0] | sattr[1]) & FLOAT;
896
897                         // Cast any ints in the comparison to double, if there's at least
898                         // one double in the comparison.
899                         if (attr == FLOAT)
900                         {
901                                 PTR p;
902                                 p.u64 = sval;
903                                 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
904                                 p.u64++;
905                                 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
906                                 *sval = (fpval1 == fpval2);
907                         }
908                         else
909                         {
910                                 *sval = (*sval == sval[1]);
911                         }
912
913                         *sattr = ABS | DEFINED;         // Expr forced to ABS
914
915                         break;
916
917                 // All other binary operators must have two ABS items to work with.
918                 // They all produce an ABS value.
919                 // Shamus: Is this true? There's at least one counterexample of legit
920                 //         code where this assumption fails to produce correct code.
921                 default:
922
923                         switch ((int)tk.u32[-1])
924                         {
925                         case '*':
926                                 sval--;
927                                 sattr--;
928                                 // Get FLOAT attribute, if any
929                                 attr = (sattr[0] | sattr[1]) & FLOAT;
930
931                                 // Since multiplying an int to a fp value promotes it to a fp
932                                 // value, we don't care whether it's first or second; it will
933                                 // be cast to a double regardless.
934 /*
935 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.
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                                         *(double *)sval = fpval1 * fpval2;
945                                 }
946                                 else
947                                 {
948                                         *sval *= sval[1];
949                                 }
950
951                                 break;
952
953                         case '/':
954                                 sval--;
955                                 sattr--;
956                                 // Get FLOAT attribute, if any
957                                 attr = (sattr[0] | sattr[1]) & FLOAT;
958
959                                 if (attr == FLOAT)
960                                 {
961                                         PTR p;
962                                         p.u64 = sval;
963                                         double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
964                                         p.u64++;
965                                         double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
966
967                                         if (fpval2 == 0)
968                                                 return error("divide by zero");
969
970                                         *(double *)sval = fpval1 / fpval2;
971                                 }
972                                 else
973                                 {
974                                         if (sval[1] == 0)
975                                                 return error("divide by zero");
976
977                                         // Compiler is picky here: Without casting these, it
978                                         // discards the sign if dividing a negative # by a
979                                         // positive one, creating a bad result. :-/
980                                         // Definitely a side effect of using uint32_ts intead of
981                                         // ints.
982                                         *sval = (int32_t)sval[0] / (int32_t)sval[1];
983                                 }
984
985                                 break;
986
987                         case '%':
988                                 sval--;
989                                 sattr--;
990
991                                 if ((*sattr | sattr[1]) & FLOAT)
992                                         return error("floating point numbers not allowed with operator '%'.");
993
994                                 if (sval[1] == 0)
995                                         return error("mod (%) by zero");
996
997                                 *sval %= sval[1];
998                                 break;
999
1000                         case SHL:
1001                                 sval--;
1002                                 sattr--;                                        // Pop attrib
1003
1004                                 if ((*sattr | sattr[1]) & FLOAT)
1005                                         return error("floating point numbers not allowed with operator '<<'.");
1006
1007                                 *sval <<= sval[1];
1008                                 break;
1009
1010                         case SHR:
1011                                 sval--;
1012                                 sattr--;                                        // Pop attrib
1013
1014                                 if ((*sattr | sattr[1]) & FLOAT)
1015                                         return error("floating point numbers not allowed with operator '>>'.");
1016
1017                                 *sval >>= sval[1];
1018                                 break;
1019
1020                         case '&':
1021                                 sval--;
1022                                 sattr--;                                        // Pop attrib
1023
1024                                 if ((*sattr | sattr[1]) & FLOAT)
1025                                         return error("floating point numbers not allowed with operator '&'.");
1026
1027                                 *sval &= sval[1];
1028                                 break;
1029
1030                         case '^':
1031                                 sval--;
1032                                 sattr--;                                        // Pop attrib
1033
1034                                 if ((*sattr | sattr[1]) & FLOAT)
1035                                         return error("floating point numbers not allowed with operator '^'.");
1036
1037                                 *sval ^= sval[1];
1038                                 break;
1039
1040                         case '|':
1041                                 sval--;
1042                                 sattr--;
1043
1044                                 if ((*sattr | sattr[1]) & FLOAT)
1045                                         return error("floating point numbers not allowed with operator '|'.");
1046
1047                                 *sval |= sval[1];
1048                                 break;
1049
1050                         default:
1051                                 // Bad operator in expression stream (this should never happen!)
1052                                 interror(5);
1053                         }
1054                 }
1055         }
1056
1057         if (esym != NULL)
1058                 *sattr &= ~DEFINED;
1059
1060         if (a_esym != NULL)
1061                 *a_esym = esym;
1062
1063         // Copy value + attrib into return variables
1064         *a_value = *sval;
1065         *a_attr = *sattr;
1066
1067         return OK;
1068 }
1069
1070 //
1071 // Count the # of tokens in the passed in expression
1072 // N.B.: 64-bit constants count as two tokens each
1073 //
1074 uint16_t ExpressionLength(TOKEN * tk)
1075 {
1076         uint16_t length;
1077
1078         for(length=0; tk[length]!=ENDEXPR; length++)
1079         {
1080                 // Add one to length for 2X tokens, two for 3X tokens
1081                 if (tk[length] == SYMBOL)
1082                         length++;
1083                 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1084                         length += 2;
1085         }
1086
1087         // Add 1 for ENDEXPR
1088         length++;
1089
1090         return length;
1091 }