]> Shamusworld >> Repos - rmac/blob - expr.c
Doc fixes/updates.
[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 * sattr;
468         VALUE * sval;
469         WORD attr;
470         SYM * sy;
471         SYM * esym;
472         WORD sym_seg;
473
474         sval = evstk;                                                   // (Empty) initial stack
475         sattr = evattr;
476         esym = NULL;                                                    // No external symbol involved
477         sym_seg = 0;
478
479         while (*tk != ENDEXPR)
480         {
481                 switch ((int)*tk++)
482                 {
483                 case SYMBOL:
484 //printf("evexpr(): SYMBOL\n");
485                         sy = symbolPtr[*tk++];
486                         sy->sattr |= REFERENCED;                // Set "referenced" bit
487
488                         if (!(sy->sattr & DEFINED))
489                         {
490                                 // Reference to undefined symbol
491                                 if (!(sy->sattr & GLOBAL))
492                                 {
493                                         *a_attr = 0;
494                                         *a_value = 0;
495                                         return OK;
496                                 }
497
498                                 if (esym != NULL)                       // Check for multiple externals
499                                         return error(seg_error);
500
501                                 esym = sy;
502                         }
503
504                         if (sy->sattr & DEFINED)
505                         {
506                                 *++sval = sy->svalue;           // Push symbol's value
507                         }
508                         else
509                         {
510                                 *++sval = 0;                            // 0 for undefined symbols
511                         }
512
513                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
514                         sym_seg = (WORD)(sy->sattr & TDB);
515                         break;
516                 case CONST:
517 //printf("evexpr(): CONST = %i\n", *tk);
518                         *++sval = *tk++;                                // Push value
519                         *++sattr = ABS | DEFINED;               // Push simple attribs
520                         break;
521                 case ACONST:
522 //printf("evexpr(): ACONST = %i\n", *tk);
523                         *++sval = *tk++;                                // Push value
524                         *++sattr = (WORD)*tk++;                 // Push attribs
525                         break;
526
527                         // Binary "+" and "-" matrix:
528                         //
529                         //                ABS    Sect     Other
530                         //     ----------------------------
531                         //   ABS     |  ABS   |  Sect  |  Other |
532                         //   Sect    |  Sect  |  [1]   |  Error |
533                         //   Other   |  Other |  Error |  [1]   |
534                         //      ----------------------------
535                         //
536                         //   [1] + : Error
537                         //       - : ABS
538                 case '+':
539 //printf("evexpr(): +\n");
540                         --sval;                                                 // Pop value
541                         --sattr;                                                // Pop attrib
542 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
543                         *sval += sval[1];                               // Compute value
544 //printf("%i\n", *sval);
545
546                         if (!(*sattr & TDB))
547                                 *sattr = sattr[1];
548                         else if (sattr[1] & TDB)
549                                 return error(seg_error);
550
551                         break;
552                 case '-':
553 //printf("evexpr(): -\n");
554                         --sval;                                                 // Pop value
555                         --sattr;                                                // Pop attrib
556 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
557                         *sval -= sval[1];                               // Compute value
558 //printf("%i\n", *sval);
559
560                         attr = (WORD)(*sattr & TDB);
561 #if 0
562 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
563 #endif
564                         // If symbol1 is ABS, take attributes from symbol2
565                         if (!attr)
566                                 *sattr = sattr[1];
567                         // Otherwise, they're both TDB and so attributes cancel out
568                         else if (sattr[1] & TDB)
569                                 *sattr &= ~TDB;
570
571                         break;
572                 // Unary operators only work on ABS items
573                 case UNMINUS:
574 //printf("evexpr(): UNMINUS\n");
575                         if (*sattr & TDB)
576                                 error(seg_error);
577
578                         *sval = -(int)*sval;
579                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
580                         break;
581                 case '!':
582 //printf("evexpr(): !\n");
583                         if (*sattr & TDB)
584                                 error(seg_error);
585
586                         *sval = !*sval;
587                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
588                         break;
589                 case '~':
590 //printf("evexpr(): ~\n");
591                         if (*sattr & TDB)
592                                 error(seg_error);
593
594                         *sval = ~*sval;
595                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
596                         break;
597                 // Comparison operators must have two values that
598                 // are in the same segment, but that's the only requirement.
599                 case LE:
600 //printf("evexpr(): LE\n");
601                         sattr--;
602                         sval--;
603
604                         if ((*sattr & TDB) != (sattr[1] & TDB))
605                                 error(seg_error);
606
607                         *sattr = ABS | DEFINED;
608                         *sval = *sval <= sval[1];
609                         break;
610                 case GE:
611 //printf("evexpr(): GE\n");
612                         sattr--;
613                         sval--;
614
615                         if ((*sattr & TDB) != (sattr[1] & TDB))
616                                 error(seg_error);
617
618                         *sattr = ABS | DEFINED;
619                         *sval = *sval >= sval[1];
620                         break;
621                 case '>':
622 //printf("evexpr(): >\n");
623                         sattr--;
624                         sval--;
625
626                         if ((*sattr & TDB) != (sattr[1] & TDB))
627                                 error(seg_error);
628
629                         *sattr = ABS | DEFINED;
630                         *sval = *sval > sval[1];
631                         break;
632                 case '<':
633 //printf("evexpr(): <\n");
634                         sattr--;
635                         sval--;
636
637                         if ((*sattr & TDB) != (sattr[1] & TDB))
638                                 error(seg_error);
639
640                         *sattr = ABS | DEFINED;
641                         *sval = *sval < sval[1];
642                         break;
643                 case NE:
644 //printf("evexpr(): NE\n");
645                         sattr--;
646                         sval--;
647
648                         if ((*sattr & TDB) != (sattr[1] & TDB))
649                                 error(seg_error);
650
651                         *sattr = ABS | DEFINED;
652                         *sval = *sval != sval[1];
653                         break;
654                 case '=':
655 //printf("evexpr(): =\n");
656                         sattr--;
657                         sval--;
658
659                         if ((*sattr & TDB) != (sattr[1] & TDB))
660                                 error(seg_error);
661
662                         *sattr = ABS | DEFINED;
663                         *sval = *sval == sval[1];
664                         break;
665                 // All other binary operators must have two ABS items
666                 // to work with.  They all produce an ABS value.
667                 default:
668 //printf("evexpr(): default\n");
669                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
670                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
671                         //error(seg_error);
672                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
673
674                         switch ((int)tk[-1])
675                         {
676                         case '*':
677                                 sval--;
678                                 sattr--;                                        // Pop attrib
679 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
680                                 *sval *= sval[1];
681 //printf("%i\n", *sval);
682                                 break;
683                         case '/':
684                                 sval--;
685                                 sattr--;                                        // Pop attrib
686
687                                 if (sval[1] == 0)
688                                         return error("divide by zero");
689
690 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
691                                 // Compiler is picky here: Without casting these, it discards
692                                 // the sign if dividing a negative # by a positive one,
693                                 // creating a bad result. :-/
694                                 // Probably a side effect of using VALUE intead of ints.
695                                 *sval = (int)sval[0] / (int)sval[1];
696 //printf("%i\n", *sval);
697                                 break;
698                         case '%':
699                                 sval--;
700                                 sattr--;                                        // Pop attrib
701
702                                 if (sval[1] == 0)
703                                         return error("mod (%) by zero");
704
705                                 *sval %= sval[1];
706                                 break;
707                         case SHL:
708                                 sval--;
709                                 sattr--;                                        // Pop attrib
710                                 *sval <<= sval[1];
711                                 break;
712                         case SHR:
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                         case '|':
728                                 sval--;
729                                 sattr--;                                        // Pop attrib
730                                 *sval |= sval[1];
731                                 break;
732                         default:
733                                 interror(5);                            // Bad operator in expression stream
734                         }
735                 }
736         }
737
738         if (esym != NULL)
739                 *sattr &= ~DEFINED;
740
741         if (a_esym != NULL)
742                 *a_esym = esym;
743
744         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
745         // expressions where absolute values also existed. The absolutes were
746         // overiding the symbol segments and not being included :(
747         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
748
749         *a_attr = *sattr;                                               // Copy value + attrib
750         *a_value = *sval;
751
752         return OK;
753 }
754