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