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