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