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