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