dea1de9c92d679461c90f3778e3257db01d58c7c
[rmac] / expr.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2017 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, SYMBOL, 0,                               // ID
33         '(', '[', '{', 0,                               // OPAR
34         ')', ']', '}', 0,                               // CPAR
35         CR_DEFINED, CR_REFERENCED,              // SUNARY (special unary)
36         CR_STREQ, CR_MACDEF,
37         CR_DATE, CR_TIME,
38         CR_ABSCOUNT, 0,
39         '!', '~', UNMINUS, 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
53 // Convert expression to postfix
54 static TOKEN * evalTokenBuffer;         // Deposit tokens here (this is really a
55                                                                         // pointer to exprbuf from direct.c)
56                                                                         // (Can also be from others, like
57                                                                         // riscasm.c)
58 static int symbolNum;                           // Pointer to the entry in symbolPtr[]
59
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 //
76 // Initialize expression analyzer
77 //
78 void InitExpression(void)
79 {
80         // Initialize token-class table (all set to END)
81         for(int i=0; i<256; i++)
82                 tokenClass[i] = END;
83
84         int i = 0;
85
86         for(char * p=itokcl; *p!=1; p++)
87         {
88                 if (*p == 0)
89                         i++;
90                 else
91                         tokenClass[(int)(*p)] = (char)i;
92         }
93
94         symbolNum = 0;
95 }
96
97
98 //
99 // Binary operators (all the same precedence)
100 //
101 int expr0(void)
102 {
103         TOKEN t;
104
105         if (expr1() != OK)
106                 return ERROR;
107
108         while (tokenClass[*tok] >= MULT)
109         {
110                 t = *tok++;
111
112                 if (expr1() != OK)
113                         return ERROR;
114
115                 *evalTokenBuffer++ = t;
116         }
117
118         return OK;
119 }
120
121
122 //
123 // Unary operators (detect unary '-')
124 // ggn: If expression starts with a plus then also eat it up.
125 //      For some reason the parser gets confused when this happens and
126 //      emits a "bad expression".
127 //
128 int expr1(void)
129 {
130         int class;
131         TOKEN t;
132         SYM * sy;
133         char * p, * p2;
134         WORD w;
135         int j;
136
137         class = tokenClass[*tok];
138
139         if (*tok == '-' || *tok == '+' || class == UNARY)
140         {
141                 t = *tok++;
142
143                 if (expr2() != OK)
144                         return ERROR;
145
146                 if (t == '-')
147                         t = UNMINUS;
148
149                 *evalTokenBuffer++ = t;
150         }
151         else if (class == SUNARY)
152         {
153                 switch ((int)*tok++)
154                 {
155                 case CR_ABSCOUNT:
156                         *evalTokenBuffer++ = CONST;
157                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
158                         *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
159                         break;
160                 case CR_TIME:
161                         *evalTokenBuffer++ = CONST;
162                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
163                         *evalTokenBuffer++ = dos_time();
164                         break;
165                 case CR_DATE:
166                         *evalTokenBuffer++ = CONST;
167                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
168                         *evalTokenBuffer++ = dos_date();
169                         break;
170                 case CR_MACDEF:                                    // ^^macdef <macro-name>
171                         if (*tok++ != SYMBOL)
172                                 return error(missym_error);
173
174                         p = string[*tok++];
175                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
176                         *evalTokenBuffer++ = CONST;
177                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
178                         *evalTokenBuffer++ = (TOKEN)w;
179                         break;
180                 case CR_DEFINED:
181                         w = DEFINED;
182                         goto getsym;
183                 case CR_REFERENCED:
184                         w = REFERENCED;
185 getsym:
186                         if (*tok++ != SYMBOL)
187                                 return error(missym_error);
188
189                         p = string[*tok++];
190                         j = (*p == '.' ? curenv : 0);
191                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
192                         *evalTokenBuffer++ = CONST;
193                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
194                         *evalTokenBuffer++ = (TOKEN)w;
195                         break;
196                 case CR_STREQ:
197                         if (*tok != SYMBOL && *tok != STRING)
198                                 return error(str_error);
199
200                         p = string[tok[1]];
201                         tok +=2;
202
203                         if (*tok++ != ',')
204                                 return error(comma_error);
205
206                         if (*tok != SYMBOL && *tok != STRING)
207                                 return error(str_error);
208
209                         p2 = string[tok[1]];
210                         tok += 2;
211
212                         w = (WORD)(!strcmp(p, p2));
213                         *evalTokenBuffer++ = CONST;
214                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
215                         *evalTokenBuffer++ = (TOKEN)w;
216                         break;
217                 }
218         }
219         else
220                 return expr2();
221
222         return OK;
223 }
224
225
226 //
227 // Terminals (CONSTs) and parenthesis grouping
228 //
229 int expr2(void)
230 {
231         char * p;
232         SYM * sy;
233         int j;
234
235         switch ((int)*tok++)
236         {
237         case CONST:
238                 *evalTokenBuffer++ = CONST;
239                 *evalTokenBuffer++ = *tok++;    // HI LONG of constant
240                 *evalTokenBuffer++ = *tok++;    // LO LONG of constant
241                 break;
242         case SYMBOL:
243                 p = string[*tok++];
244                 j = (*p == '.' ? curenv : 0);
245                 sy = lookup(p, LABEL, j);
246
247                 if (sy == NULL)
248                         sy = NewSymbol(p, LABEL, j);
249
250                 // Check register bank usage
251                 if (sy->sattre & EQUATEDREG)
252                 {
253                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
254                                 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
255
256                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
257                                 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
258                 }
259
260                 *evalTokenBuffer++ = SYMBOL;
261                 *evalTokenBuffer++ = symbolNum;
262                 symbolPtr[symbolNum] = sy;
263                 symbolNum++;
264                 break;
265         case STRING:
266                 *evalTokenBuffer++ = CONST;
267                 *evalTokenBuffer++ = 0;         // Set HI LONG to zero
268                 *evalTokenBuffer++ = str_value(string[*tok++]);
269                 break;
270         case '(':
271                 if (expr0() != OK)
272                         return ERROR;
273
274                 if (*tok++ != ')')
275                         return error("missing closing parenthesis ')'");
276
277                 break;
278         case '[':
279                 if (expr0() != OK)
280                         return ERROR;
281
282                 if (*tok++ != ']')
283                         return error("missing closing bracket ']'");
284
285                 break;
286         case '$':
287                 *evalTokenBuffer++ = ACONST;                            // Attributed const
288                 *evalTokenBuffer++ = sloc;                                      // Current location
289                 *evalTokenBuffer++ = cursect | DEFINED;         // Store attribs
290                 break;
291         case '*':
292                 *evalTokenBuffer++ = ACONST;                            // Attributed const
293
294                 // pcloc == location at start of line
295                 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
296                 // '*' takes attributes of current section, not ABS!
297                 *evalTokenBuffer++ = cursect | DEFINED;
298                 break;
299         case '{':
300                 if (expr0() != OK)                                                      // Eat up first parameter (register or immediate)
301                         return ERROR;
302
303                 if (*tok++ != ':')                                                      // Demand a ':' there
304                         return error("missing colon ':'");
305
306                 if (expr0() != OK)                                                      // Eat up second parameter (register or immediate)
307                         return ERROR;
308
309                 if (*tok++ != '}')
310                         return error("missing closing brace '}'");
311
312                 break;
313         default:
314                 return error("bad expression");
315         }
316
317         return OK;
318 }
319
320
321 //
322 // Recursive-descent expression analyzer (with some simple speed hacks)
323 //
324 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
325 {
326         // Passed in values (once derefenced, that is) can all be zero. They are
327         // there so that the expression analyzer can fill them in as needed. The
328         // expression analyzer gets its input from the global token pointer "tok",
329         // and not from anything passed in by the user.
330         SYM * symbol;
331         char * p;
332         int j;
333
334         evalTokenBuffer = otk;  // Set token pointer to 'exprbuf' (direct.c)
335                                                         // Also set in various other places too (riscasm.c,
336                                                         // e.g.)
337
338 //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]]);
339         // Optimize for single constant or single symbol.
340         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
341         //         followed by the value 101, it will trigger a bad evaluation here.
342         //         This is probably a really bad assumption to be making here...!
343         //         (assuming tok[1] == EOL is a single token that is)
344         //         Seems that even other tokens (SUNARY type) can fuck this up too.
345 //      if ((tok[1] == EOL)
346         if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
347 //              || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
348 //              && (tokenClass[tok[2]] < UNARY)))
349                 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
350                 && (tokenClass[tok[2]] < UNARY))
351                 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
352                 )
353         {
354                 if (*tok >= KW_R0 && *tok <= KW_R31)
355                 {
356                         *evalTokenBuffer++ = CONST;
357                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
358                         *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
359                         *a_attr = ABS | DEFINED;
360
361                         if (a_esym != NULL)
362                                 *a_esym = NULL;
363
364                         tok++;
365                 }
366                 else if (*tok == CONST)
367                 {
368                         *evalTokenBuffer++ = CONST;
369                         *evalTokenBuffer++ = tok[1];
370                         *evalTokenBuffer++ = tok[2];
371                         *a_value = (((uint64_t)tok[1]) << 32) | tok[2];
372                         *a_attr = ABS | DEFINED;
373
374                         if (a_esym != NULL)
375                                 *a_esym = NULL;
376
377                         tok += 3;
378 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
379                 }
380                 else if (*tok == '*')
381                 {
382                         *evalTokenBuffer++ = CONST;
383                         *evalTokenBuffer++ = 0;         // Set HI LONG to zero
384
385                         if (orgactive)
386                                 *evalTokenBuffer++ = *a_value = orgaddr;
387                         else
388                                 *evalTokenBuffer++ = *a_value = pcloc;
389
390                         // '*' takes attributes of current section, not ABS!
391                         *a_attr = cursect | DEFINED;
392
393                         if (a_esym != NULL)
394                                 *a_esym = NULL;
395
396                         tok++;
397                 }
398                 else if (*tok == STRING || *tok == SYMBOL)
399                 {
400                         p = string[tok[1]];
401                         j = (*p == '.' ? curenv : 0);
402                         symbol = lookup(p, LABEL, j);
403 #if 0
404 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
405 if (symbol)
406         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
407 #endif
408
409                         if (symbol == NULL)
410                                 symbol = NewSymbol(p, LABEL, j);
411
412                         symbol->sattr |= REFERENCED;
413
414                         // Check for undefined register equates, but only if it's not part
415                         // of a #<SYMBOL> construct, as it could be that the label that's
416                         // been undefined may later be used as an address label--which
417                         // means it will be fixed up later, and thus, not an error.
418                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
419                         {
420                                 error("undefined register equate '%s'", symbol->sname);
421 //if we return right away, it returns some spurious errors...
422 //                              return ERROR;
423                         }
424
425                         // Check register bank usage
426                         if (symbol->sattre & EQUATEDREG)
427                         {
428                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
429                                         warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
430
431                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
432                                         warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
433                         }
434
435                         *evalTokenBuffer++ = SYMBOL;
436 #if 0
437                         *evalTokenBuffer++ = (TOKEN)symbol;
438 #else
439 /*
440 While this approach works, it's wasteful. It would be better to use something
441 that's already available, like the symbol "order defined" table (which needs to
442 be converted from a linked list into an array).
443 */
444                         *evalTokenBuffer++ = symbolNum;
445                         symbolPtr[symbolNum] = symbol;
446                         symbolNum++;
447 #endif
448
449                         if (symbol->sattr & DEFINED)
450                                 *a_value = symbol->svalue;
451                         else
452                                 *a_value = 0;
453
454 /*
455 All that extra crap that was put into the svalue when doing the equr stuff is
456 thrown away right here. What the hell is it for?
457 */
458                         if (symbol->sattre & EQUATEDREG)
459                                 *a_value &= 0x1F;
460
461                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
462
463                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
464                                 && a_esym != NULL)
465                                 *a_esym = symbol;
466
467                         tok += 2;
468                 }
469                 else
470                 {
471                         // Unknown type here... Alert the user!,
472                         error("undefined RISC register in expression");
473                         // Prevent spurious error reporting...
474                         tok++;
475                         return ERROR;
476                 }
477
478                 *evalTokenBuffer++ = ENDEXPR;
479                 return OK;
480         }
481
482         if (expr0() != OK)
483                 return ERROR;
484
485         *evalTokenBuffer++ = ENDEXPR;
486         return evexpr(otk, a_value, a_attr, a_esym);
487 }
488
489
490 //
491 // Evaluate expression.
492 // If the expression involves only ONE external symbol, the expression is
493 // UNDEFINED, but it's value includes everything but the symbol value, and
494 // `a_esym' is set to the external symbol.
495 //
496 int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
497 {
498         WORD attr;
499         SYM * sy;
500         uint64_t * sval = evstk;                                // (Empty) initial stack
501         WORD * sattr = evattr;
502         SYM * esym = NULL;                                              // No external symbol involved
503         WORD sym_seg = 0;
504
505         while (*tk != ENDEXPR)
506         {
507                 switch ((int)*tk++)
508                 {
509                 case SYMBOL:
510 //printf("evexpr(): SYMBOL\n");
511                         sy = symbolPtr[*tk++];
512                         sy->sattr |= REFERENCED;                // Set "referenced" bit
513
514                         if (!(sy->sattr & DEFINED))
515                         {
516                                 // Reference to undefined symbol
517                                 if (!(sy->sattr & GLOBAL))
518                                 {
519                                         *a_attr = 0;
520                                         *a_value = 0;
521                                         return OK;
522                                 }
523
524                                 if (esym != NULL)                       // Check for multiple externals
525                                         return error(seg_error);
526
527                                 esym = sy;
528                         }
529
530                         if (sy->sattr & DEFINED)
531                         {
532                                 *++sval = sy->svalue;           // Push symbol's value
533                         }
534                         else
535                         {
536                                 *++sval = 0;                            // 0 for undefined symbols
537                         }
538
539                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
540                         sym_seg = (WORD)(sy->sattr & TDB);
541                         break;
542                 case CONST:
543                         *++sval = ((uint64_t)*tk++) << 32;                      // Push value
544                         *sval |= *tk++;         // & LO LONG (will this work???--should)
545 //printf("evexpr(): CONST = %lX\n", *sval);
546                         *++sattr = ABS | DEFINED;               // Push simple attribs
547                         break;
548                 case ACONST:
549 //printf("evexpr(): ACONST = %i\n", *tk);
550                         *++sval = *tk++;                                // Push value
551                         *++sattr = (WORD)*tk++;                 // Push attribs
552                         break;
553
554                         // Binary "+" and "-" matrix:
555                         //
556                         //                ABS    Sect     Other
557                         //     ----------------------------
558                         //   ABS     |  ABS   |  Sect  |  Other |
559                         //   Sect    |  Sect  |  [1]   |  Error |
560                         //   Other   |  Other |  Error |  [1]   |
561                         //      ----------------------------
562                         //
563                         //   [1] + : Error
564                         //       - : ABS
565                 case '+':
566 //printf("evexpr(): +\n");
567                         --sval;                                                 // Pop value
568                         --sattr;                                                // Pop attrib
569 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
570                         *sval += sval[1];                               // Compute value
571 //printf("%i\n", *sval);
572
573                         if (!(*sattr & TDB))
574                                 *sattr = sattr[1];
575                         else if (sattr[1] & TDB)
576                                 return error(seg_error);
577
578                         break;
579                 case '-':
580 //printf("evexpr(): -\n");
581                         --sval;                                                 // Pop value
582                         --sattr;                                                // Pop attrib
583 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
584                         *sval -= sval[1];                               // Compute value
585 //printf("%i\n", *sval);
586
587                         attr = (WORD)(*sattr & TDB);
588 #if 0
589 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
590 #endif
591                         // If symbol1 is ABS, take attributes from symbol2
592                         if (!attr)
593                                 *sattr = sattr[1];
594                         // Otherwise, they're both TDB and so attributes cancel out
595                         else if (sattr[1] & TDB)
596                                 *sattr &= ~TDB;
597
598                         break;
599                 // Unary operators only work on ABS items
600                 case UNMINUS:
601 //printf("evexpr(): UNMINUS\n");
602                         if (*sattr & TDB)
603                                 error(seg_error);
604
605                         *sval = -(int)*sval;
606                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
607                         break;
608                 case '!':
609 //printf("evexpr(): !\n");
610                         if (*sattr & TDB)
611                                 error(seg_error);
612
613                         *sval = !*sval;
614                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
615                         break;
616                 case '~':
617 //printf("evexpr(): ~\n");
618                         if (*sattr & TDB)
619                                 error(seg_error);
620
621                         *sval = ~*sval;
622                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
623                         break;
624                 // Comparison operators must have two values that
625                 // are in the same segment, but that's the only requirement.
626                 case LE:
627 //printf("evexpr(): LE\n");
628                         sattr--;
629                         sval--;
630
631                         if ((*sattr & TDB) != (sattr[1] & TDB))
632                                 error(seg_error);
633
634                         *sattr = ABS | DEFINED;
635                         *sval = *sval <= sval[1];
636                         break;
637                 case GE:
638 //printf("evexpr(): GE\n");
639                         sattr--;
640                         sval--;
641
642                         if ((*sattr & TDB) != (sattr[1] & TDB))
643                                 error(seg_error);
644
645                         *sattr = ABS | DEFINED;
646                         *sval = *sval >= sval[1];
647                         break;
648                 case '>':
649 //printf("evexpr(): >\n");
650                         sattr--;
651                         sval--;
652
653                         if ((*sattr & TDB) != (sattr[1] & TDB))
654                                 error(seg_error);
655
656                         *sattr = ABS | DEFINED;
657                         *sval = *sval > sval[1];
658                         break;
659                 case '<':
660 //printf("evexpr(): <\n");
661                         sattr--;
662                         sval--;
663
664                         if ((*sattr & TDB) != (sattr[1] & TDB))
665                                 error(seg_error);
666
667                         *sattr = ABS | DEFINED;
668                         *sval = *sval < sval[1];
669                         break;
670                 case NE:
671 //printf("evexpr(): NE\n");
672                         sattr--;
673                         sval--;
674
675                         if ((*sattr & TDB) != (sattr[1] & TDB))
676                                 error(seg_error);
677
678                         *sattr = ABS | DEFINED;
679                         *sval = *sval != sval[1];
680                         break;
681                 case '=':
682 //printf("evexpr(): =\n");
683                         sattr--;
684                         sval--;
685
686                         if ((*sattr & TDB) != (sattr[1] & TDB))
687                                 error(seg_error);
688
689                         *sattr = ABS | DEFINED;
690                         *sval = *sval == sval[1];
691                         break;
692                 // All other binary operators must have two ABS items
693                 // to work with.  They all produce an ABS value.
694                 default:
695 //printf("evexpr(): default\n");
696                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
697                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
698                         //error(seg_error);
699                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
700
701                         switch ((int)tk[-1])
702                         {
703                         case '*':
704                                 sval--;
705                                 sattr--;                                        // Pop attrib
706 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
707                                 *sval *= sval[1];
708 //printf("%i\n", *sval);
709                                 break;
710                         case '/':
711                                 sval--;
712                                 sattr--;                                        // Pop attrib
713
714                                 if (sval[1] == 0)
715                                         return error("division by zero");
716
717 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
718                                 // Compiler is picky here: Without casting these, it discards
719                                 // the sign if dividing a negative # by a positive one,
720                                 // creating a bad result. :-/
721                                 // Definitely a side effect of using uint32_ts intead of ints.
722                                 *sval = (int32_t)sval[0] / (int32_t)sval[1];
723 //printf("%i\n", *sval);
724                                 break;
725                         case '%':
726                                 sval--;
727                                 sattr--;                                        // Pop attrib
728
729                                 if (sval[1] == 0)
730                                         return error("mod (%) by zero");
731
732                                 *sval %= sval[1];
733                                 break;
734                         case SHL:
735                                 sval--;
736                                 sattr--;                                        // Pop attrib
737                                 *sval <<= sval[1];
738                                 break;
739                         case SHR:
740                                 sval--;
741                                 sattr--;                                        // Pop attrib
742                                 *sval >>= sval[1];
743                                 break;
744                         case '&':
745                                 sval--;
746                                 sattr--;                                        // Pop attrib
747                                 *sval &= sval[1];
748                                 break;
749                         case '^':
750                                 sval--;
751                                 sattr--;                                        // Pop attrib
752                                 *sval ^= sval[1];
753                                 break;
754                         case '|':
755                                 sval--;
756                                 sattr--;                                        // Pop attrib
757                                 *sval |= sval[1];
758                                 break;
759                         default:
760                                 interror(5);                            // Bad operator in expression stream
761                         }
762                 }
763         }
764
765         if (esym != NULL)
766                 *sattr &= ~DEFINED;
767
768         if (a_esym != NULL)
769                 *a_esym = esym;
770
771         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
772         // expressions where absolute values also existed. The absolutes were
773         // overiding the symbol segments and not being included :(
774         //*a_attr = *sattr | sym_seg;           // Copy value + attrib
775
776         *a_attr = *sattr;                                               // Copy value + attrib
777         *a_value = *sval;
778
779         return OK;
780 }
781