]> Shamusworld >> Repos - rmac/blob - expr.c
4c4168f4a0c543eb45179a5ac376ff2337f8dc7c
[rmac] / expr.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 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 VALUE 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 VALUE str_value(char * p)
65 {
66         VALUE 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                                 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
248
249                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
250                                 warns("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 close parenthesis ')'");
268
269                 break;
270         case '[':
271                 if (expr0() != OK)
272                         return ERROR;
273
274                 if (*tok++ != ']')
275                         return error("missing close parenthesis ']'");
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         default:
292                 return error("bad expression");
293         }
294
295         return OK;
296 }
297
298
299 //
300 // Recursive-descent expression analyzer (with some simple speed hacks)
301 //
302 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
303 {
304         // Passed in values (once derefenced, that is) can all be zero. They are
305         // there so that the expression analyzer can fill them in as needed. The
306         // expression analyzer gets its input from the global token pointer "tok",
307         // and not from anything passed in by the user.
308         SYM * symbol;
309         char * p;
310         int j;
311
312         evalTokenBuffer = otk;  // Set token pointer to 'exprbuf' (direct.c)
313                                                         // Also set in various other places too (riscasm.c, e.g.)
314
315 //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]]);
316         // Optimize for single constant or single symbol.
317         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
318         //         followed by the value 101, it will trigger a bad evaluation here.
319         //         This is probably a really bad assumption to be making here...!
320         //         (assuming tok[1] == EOL is a single token that is)
321         //         Seems that even other tokens (SUNARY type) can fuck this up too.
322 //      if ((tok[1] == EOL)
323         if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
324                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
325                 && (tokenClass[tok[2]] < UNARY)))
326         {
327                 if (*tok >= KW_R0 && *tok <= KW_R31)
328                 {
329                         *evalTokenBuffer++ = CONST;
330                         *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
331                         *a_attr = ABS | DEFINED;
332
333                         if (a_esym != NULL)
334                                 *a_esym = NULL;
335
336                         tok++;
337                 }
338                 else if (*tok == CONST)
339                 {
340                         *evalTokenBuffer++ = CONST;
341                         *evalTokenBuffer++ = *a_value = tok[1];
342                         *a_attr = ABS | DEFINED;
343
344                         if (a_esym != NULL)
345                                 *a_esym = NULL;
346
347                         tok += 2;
348 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
349                 }
350                 else if (*tok == '*')
351                 {
352                         *evalTokenBuffer++ = CONST;
353
354                         if (orgactive)
355                                 *evalTokenBuffer++ = *a_value = orgaddr;
356                         else
357                                 *evalTokenBuffer++ = *a_value = pcloc;
358
359                         // '*' takes attributes of current section, not ABS!
360                         *a_attr = cursect | DEFINED;
361
362                         if (a_esym != NULL)
363                                 *a_esym = NULL;
364
365                         tok++;
366                 }
367                 else if (*tok == STRING || *tok == SYMBOL)
368                 {
369                         p = string[tok[1]];
370                         j = (*p == '.' ? curenv : 0);
371                         symbol = lookup(p, LABEL, j);
372 #if 0
373 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
374 if (symbol)
375         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
376 #endif
377
378                         if (symbol == NULL)
379                                 symbol = NewSymbol(p, LABEL, j);
380
381                         symbol->sattr |= REFERENCED;
382
383                         // Check for undefined register equates, but only if it's not part
384                         // of a #<SYMBOL> construct, as it could be that the label that's
385                         // been undefined may later be used as an address label--which
386                         // means it will be fixed up later, and thus, not an error.
387                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
388                         {
389                                 errors("undefined register equate '%s'", symbol->sname);
390 //if we return right away, it returns some spurious errors...
391 //                              return ERROR;
392                         }
393
394                         // Check register bank usage
395                         if (symbol->sattre & EQUATEDREG)
396                         {
397                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
398                                         warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
399
400                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
401                                         warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
402                         }
403
404                         *evalTokenBuffer++ = SYMBOL;
405 #if 0
406                         *evalTokenBuffer++ = (TOKEN)symbol;
407 #else
408 /*
409 While this approach works, it's wasteful. It would be better to use something
410 that's already available, like the symbol "order defined" table (which needs to
411 be converted from a linked list into an array).
412 */
413                         *evalTokenBuffer++ = symbolNum;
414                         symbolPtr[symbolNum] = symbol;
415                         symbolNum++;
416 #endif
417
418                         if (symbol->sattr & DEFINED)
419                                 *a_value = symbol->svalue;
420                         else
421                                 *a_value = 0;
422
423 /*
424 All that extra crap that was put into the svalue when doing the equr stuff is
425 thrown away right here. What the hell is it for?
426 */
427                         if (symbol->sattre & EQUATEDREG)
428                                 *a_value &= 0x1F;
429
430                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
431
432                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
433                                 && a_esym != NULL)
434                                 *a_esym = symbol;
435
436                         tok += 2;
437                 }
438                 else
439                 {
440                         // Unknown type here... Alert the user!,
441                         error("undefined RISC register in expression");
442                         // Prevent spurious error reporting...
443                         tok++;
444                         return ERROR;
445                 }
446
447                 *evalTokenBuffer++ = ENDEXPR;
448                 return OK;
449         }
450
451         if (expr0() != OK)
452                 return ERROR;
453
454         *evalTokenBuffer++ = ENDEXPR;
455         return evexpr(otk, a_value, a_attr, a_esym);
456 }
457
458
459 //
460 // Evaluate expression.
461 // If the expression involves only ONE external symbol, the expression is
462 // UNDEFINED, but it's value includes everything but the symbol value, and
463 // `a_esym' is set to the external symbol.
464 //
465 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
466 {
467         WORD attr;
468         SYM * sy;
469         VALUE * sval = evstk;                                   // (Empty) initial stack
470         WORD * sattr = evattr;
471         SYM * esym = NULL;                                              // No external symbol involved
472         WORD sym_seg = 0;
473
474         while (*tk != ENDEXPR)
475         {
476                 switch ((int)*tk++)
477                 {
478                 case SYMBOL:
479 //printf("evexpr(): SYMBOL\n");
480                         sy = symbolPtr[*tk++];
481                         sy->sattr |= REFERENCED;                // Set "referenced" bit
482
483                         if (!(sy->sattr & DEFINED))
484                         {
485                                 // Reference to undefined symbol
486                                 if (!(sy->sattr & GLOBAL))
487                                 {
488                                         *a_attr = 0;
489                                         *a_value = 0;
490                                         return OK;
491                                 }
492
493                                 if (esym != NULL)                       // Check for multiple externals
494                                         return error(seg_error);
495
496                                 esym = sy;
497                         }
498
499                         if (sy->sattr & DEFINED)
500                         {
501                                 *++sval = sy->svalue;           // Push symbol's value
502                         }
503                         else
504                         {
505                                 *++sval = 0;                            // 0 for undefined symbols
506                         }
507
508                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
509                         sym_seg = (WORD)(sy->sattr & TDB);
510                         break;
511                 case CONST:
512 //printf("evexpr(): CONST = %i\n", *tk);
513                         *++sval = *tk++;                                // Push value
514                         *++sattr = ABS | DEFINED;               // Push simple attribs
515                         break;
516                 case ACONST:
517 //printf("evexpr(): ACONST = %i\n", *tk);
518                         *++sval = *tk++;                                // Push value
519                         *++sattr = (WORD)*tk++;                 // Push attribs
520                         break;
521
522                         // Binary "+" and "-" matrix:
523                         //
524                         //                ABS    Sect     Other
525                         //     ----------------------------
526                         //   ABS     |  ABS   |  Sect  |  Other |
527                         //   Sect    |  Sect  |  [1]   |  Error |
528                         //   Other   |  Other |  Error |  [1]   |
529                         //      ----------------------------
530                         //
531                         //   [1] + : Error
532                         //       - : ABS
533                 case '+':
534 //printf("evexpr(): +\n");
535                         --sval;                                                 // Pop value
536                         --sattr;                                                // Pop attrib
537 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
538                         *sval += sval[1];                               // Compute value
539 //printf("%i\n", *sval);
540
541                         if (!(*sattr & TDB))
542                                 *sattr = sattr[1];
543                         else if (sattr[1] & TDB)
544                                 return error(seg_error);
545
546                         break;
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                         attr = (WORD)(*sattr & TDB);
556 #if 0
557 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
558 #endif
559                         // If symbol1 is ABS, take attributes from symbol2
560                         if (!attr)
561                                 *sattr = sattr[1];
562                         // Otherwise, they're both TDB and so attributes cancel out
563                         else if (sattr[1] & TDB)
564                                 *sattr &= ~TDB;
565
566                         break;
567                 // Unary operators only work on ABS items
568                 case UNMINUS:
569 //printf("evexpr(): UNMINUS\n");
570                         if (*sattr & TDB)
571                                 error(seg_error);
572
573                         *sval = -(int)*sval;
574                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
575                         break;
576                 case '!':
577 //printf("evexpr(): !\n");
578                         if (*sattr & TDB)
579                                 error(seg_error);
580
581                         *sval = !*sval;
582                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
583                         break;
584                 case '~':
585 //printf("evexpr(): ~\n");
586                         if (*sattr & TDB)
587                                 error(seg_error);
588
589                         *sval = ~*sval;
590                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
591                         break;
592                 // Comparison operators must have two values that
593                 // are in the same segment, but that's the only requirement.
594                 case LE:
595 //printf("evexpr(): LE\n");
596                         sattr--;
597                         sval--;
598
599                         if ((*sattr & TDB) != (sattr[1] & TDB))
600                                 error(seg_error);
601
602                         *sattr = ABS | DEFINED;
603                         *sval = *sval <= sval[1];
604                         break;
605                 case GE:
606 //printf("evexpr(): GE\n");
607                         sattr--;
608                         sval--;
609
610                         if ((*sattr & TDB) != (sattr[1] & TDB))
611                                 error(seg_error);
612
613                         *sattr = ABS | DEFINED;
614                         *sval = *sval >= sval[1];
615                         break;
616                 case '>':
617 //printf("evexpr(): >\n");
618                         sattr--;
619                         sval--;
620
621                         if ((*sattr & TDB) != (sattr[1] & TDB))
622                                 error(seg_error);
623
624                         *sattr = ABS | DEFINED;
625                         *sval = *sval > sval[1];
626                         break;
627                 case '<':
628 //printf("evexpr(): <\n");
629                         sattr--;
630                         sval--;
631
632                         if ((*sattr & TDB) != (sattr[1] & TDB))
633                                 error(seg_error);
634
635                         *sattr = ABS | DEFINED;
636                         *sval = *sval < sval[1];
637                         break;
638                 case NE:
639 //printf("evexpr(): NE\n");
640                         sattr--;
641                         sval--;
642
643                         if ((*sattr & TDB) != (sattr[1] & TDB))
644                                 error(seg_error);
645
646                         *sattr = ABS | DEFINED;
647                         *sval = *sval != sval[1];
648                         break;
649                 case '=':
650 //printf("evexpr(): =\n");
651                         sattr--;
652                         sval--;
653
654                         if ((*sattr & TDB) != (sattr[1] & TDB))
655                                 error(seg_error);
656
657                         *sattr = ABS | DEFINED;
658                         *sval = *sval == sval[1];
659                         break;
660                 // All other binary operators must have two ABS items
661                 // to work with.  They all produce an ABS value.
662                 default:
663 //printf("evexpr(): default\n");
664                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
665                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
666                         //error(seg_error);
667                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
668
669                         switch ((int)tk[-1])
670                         {
671                         case '*':
672                                 sval--;
673                                 sattr--;                                        // Pop attrib
674 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
675                                 *sval *= sval[1];
676 //printf("%i\n", *sval);
677                                 break;
678                         case '/':
679                                 sval--;
680                                 sattr--;                                        // Pop attrib
681
682                                 if (sval[1] == 0)
683                                         return error("divide by zero");
684
685 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
686                                 // Compiler is picky here: Without casting these, it discards
687                                 // the sign if dividing a negative # by a positive one,
688                                 // creating a bad result. :-/
689                                 // Probably a side effect of using VALUE intead of ints.
690                                 *sval = (int)sval[0] / (int)sval[1];
691 //printf("%i\n", *sval);
692                                 break;
693                         case '%':
694                                 sval--;
695                                 sattr--;                                        // Pop attrib
696
697                                 if (sval[1] == 0)
698                                         return error("mod (%) by zero");
699
700                                 *sval %= sval[1];
701                                 break;
702                         case SHL:
703                                 sval--;
704                                 sattr--;                                        // Pop attrib
705                                 *sval <<= sval[1];
706                                 break;
707                         case SHR:
708                                 sval--;
709                                 sattr--;                                        // Pop attrib
710                                 *sval >>= sval[1];
711                                 break;
712                         case '&':
713                                 sval--;
714                                 sattr--;                                        // Pop attrib
715                                 *sval &= sval[1];
716                                 break;
717                         case '^':
718                                 sval--;
719                                 sattr--;                                        // Pop attrib
720                                 *sval ^= sval[1];
721                                 break;
722                         case '|':
723                                 sval--;
724                                 sattr--;                                        // Pop attrib
725                                 *sval |= sval[1];
726                                 break;
727                         default:
728                                 interror(5);                            // Bad operator in expression stream
729                         }
730                 }
731         }
732
733         if (esym != NULL)
734                 *sattr &= ~DEFINED;
735
736         if (a_esym != NULL)
737                 *a_esym = esym;
738
739         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
740         // expressions where absolute values also existed. The absolutes were
741         // overiding the symbol segments and not being included :(
742         //*a_attr = *sattr | sym_seg;           // Copy value + attrib
743
744         *a_attr = *sattr;                                               // Copy value + attrib
745         *a_value = *sval;
746
747         return OK;
748 }
749