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