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