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