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