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