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