]> Shamusworld >> Repos - rmac/blob - expr.c
Force -fa when user passes -p.
[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 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
535                         *sval += sval[1];                               // Compute value
536 //printf("%i\n", *sval);
537
538                         if (!(*sattr & TDB))
539                                 *sattr = sattr[1];
540                         else if (sattr[1] & TDB)
541                                 return error(seg_error);
542
543                         break;
544                 case '-':
545 //printf("evexpr(): -\n");
546                         --sval;                                                 // Pop value
547                         --sattr;                                                // Pop attrib 
548 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
549                         *sval -= sval[1];                               // Compute value
550 //printf("%i\n", *sval);
551
552                         attr = (WORD)(*sattr & TDB);
553 #if 0
554 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
555 #endif
556                         // If symbol1 is ABS, take attributes from symbol2
557                         if (!attr)
558                                 *sattr = sattr[1];
559                         // Otherwise, they're both TDB and so attributes cancel out
560                         else if (sattr[1] & TDB)
561                                 *sattr &= ~TDB;
562
563                         break;
564                 // Unary operators only work on ABS items
565                 case UNMINUS:
566 //printf("evexpr(): UNMINUS\n");
567                         if (*sattr & TDB)
568                                 error(seg_error);
569
570                         *sval = -(int)*sval;
571                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
572                         break;
573                 case '!':
574 //printf("evexpr(): !\n");
575                         if (*sattr & TDB)
576                                 error(seg_error);
577
578                         *sval = !*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                 // Comparison operators must have two values that
590                 // are in the same segment, but that's the only requirement.
591                 case LE:
592 //printf("evexpr(): LE\n");
593                         --sattr;
594                         --sval;
595
596                         if ((*sattr & TDB) != (sattr[1] & TDB))
597                                 error(seg_error);
598
599                         *sattr = ABS | DEFINED;
600                         *sval = *sval <= sval[1];
601                         break;
602                 case GE:
603 //printf("evexpr(): GE\n");
604                         --sattr;
605                         --sval;
606
607                         if ((*sattr & TDB) != (sattr[1] & TDB))
608                                 error(seg_error);
609
610                         *sattr = ABS | DEFINED;
611                         *sval = *sval >= sval[1];
612                         break;
613                 case '>':
614 //printf("evexpr(): >\n");
615                         --sattr;
616                         --sval;
617
618                         if ((*sattr & TDB) != (sattr[1] & TDB))
619                                 error(seg_error);
620
621                         *sattr = ABS | DEFINED;
622                         *sval = *sval > sval[1];
623                         break;
624                 case '<':
625 //printf("evexpr(): <\n");
626                         --sattr;
627                         --sval;
628
629                         if ((*sattr & TDB) != (sattr[1] & TDB))
630                                 error(seg_error);
631
632                         *sattr = ABS | DEFINED;
633                         *sval = *sval < sval[1];
634                         break;
635                 case NE:
636 //printf("evexpr(): NE\n");
637                         --sattr;
638                         --sval;
639
640                         if ((*sattr & TDB) != (sattr[1] & TDB))
641                                 error(seg_error);
642
643                         *sattr = ABS | DEFINED;
644                         *sval = *sval != sval[1];
645                         break;
646                 case '=':
647 //printf("evexpr(): =\n");
648                         --sattr;
649                         --sval;
650
651                         if ((*sattr & TDB) != (sattr[1] & TDB))
652                                 error(seg_error);
653
654                         *sattr = ABS | DEFINED;
655                         *sval = *sval == sval[1];
656                         break;
657                 // All other binary operators must have two ABS items
658                 // to work with.  They all produce an ABS value.
659                 default:
660 //printf("evexpr(): default\n");
661                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
662                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
663                         //error(seg_error);
664                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
665
666                         switch ((int)tk[-1])
667                         {
668                         case '*':
669                                 --sval;
670                                 --sattr;                                        // Pop attrib 
671 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
672                                 *sval *= sval[1];
673 //printf("%i\n", *sval);
674                                 break;
675                         case '/':
676                                 --sval;
677                                 --sattr;                                        // Pop attrib 
678
679                                 if (sval[1] == 0)
680                                         return error("divide by zero");
681
682 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
683                                 // Compiler is picky here: Without casting these, it discards
684                                 // the sign if dividing a negative # by a positive one,
685                                 // creating a bad result. :-/
686                                 // Probably a side effect of using VALUE intead of ints.
687                                 *sval = (int)sval[0] / (int)sval[1];
688 //printf("%i\n", *sval);
689                                 break;
690                         case '%':
691                                 --sval;
692                                 --sattr;                                        // Pop attrib 
693
694                                 if (sval[1] == 0)
695                                         return error("mod (%) by zero");
696
697                                 *sval %= sval[1];
698                                 break;
699                         case SHL:
700                                 --sval;
701                                 --sattr;                                        // Pop attrib 
702                                 *sval <<= sval[1];
703                                 break;
704                         case SHR:
705                                 --sval;
706                                 --sattr;                                        // Pop attrib 
707                                 *sval >>= sval[1];
708                                 break;
709                         case '&':
710                                 --sval;
711                                 --sattr;                                        // Pop attrib 
712                                 *sval &= sval[1];
713                                 break;
714                         case '^':
715                                 --sval;
716                                 --sattr;                                        // Pop attrib 
717                                 *sval ^= sval[1];
718                                 break;
719                         case '|':
720                                 --sval;
721                                 --sattr;                                        // Pop attrib 
722                                 *sval |= sval[1];
723                                 break;
724                         default:
725                                 interror(5);                            // Bad operator in expression stream
726                         }
727                 }
728         }
729
730         if (esym != NULL)
731                 *sattr &= ~DEFINED;
732
733         if (a_esym != NULL)
734                 *a_esym = esym;
735
736         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
737         // expressions where absolute values also existed. The absolutes were
738         // overiding the symbol segments and not being included :(
739         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
740
741         *a_attr = *sattr;                                               // Copy value + attrib
742         *a_value = *sval;
743
744         return OK;
745 }
746