]> Shamusworld >> Repos - rmac/blob - expr.c
5c7fc8760437375850a2b60ee4496ab8cee60def
[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                 *evalTokenBuffer++ = ABS | DEFINED;                     // Store attribs
282                 break;
283         default:
284                 return error("bad expression");
285         }
286
287         return OK;
288 }
289
290
291 //
292 // Recursive-descent expression analyzer (with some simple speed hacks)
293 //
294 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
295 {
296         // Passed in values (once derefenced, that is) can all be zero. They are
297         // there so that the expression analyzer can fill them in as needed. The
298         // expression analyzer gets its input from the global token pointer "tok",
299         // and not from anything passed in by the user.
300         SYM * symbol;
301         char * p;
302         int j;
303
304         evalTokenBuffer = otk;  // Set token pointer to 'exprbuf' (direct.c)
305                                                         // Also set in various other places too (riscasm.c, e.g.)
306
307 //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]]);
308         // Optimize for single constant or single symbol.
309         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
310         //         followed by the value 101, it will trigger a bad evaluation here.
311         //         This is probably a really bad assumption to be making here...!
312         //         (assuming tok[1] == EOL is a single token that is)
313 //      if ((tok[1] == EOL)
314         if ((tok[1] == EOL && tok[0] != CONST)
315                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
316                 && (tokenClass[tok[2]] < UNARY)))
317         {
318                 if (*tok >= KW_R0 && *tok <= KW_R31)
319                 {
320                         *evalTokenBuffer++ = CONST;
321                         *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
322                         *a_attr = ABS | DEFINED;
323
324                         if (a_esym != NULL)
325                                 *a_esym = NULL;
326
327                         tok++;
328                 }
329                 else if (*tok == CONST)
330                 {
331                         *evalTokenBuffer++ = CONST;
332                         *evalTokenBuffer++ = *a_value = tok[1];
333                         *a_attr = ABS | DEFINED;
334
335                         if (a_esym != NULL)
336                                 *a_esym = NULL;
337
338                         tok += 2;
339 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
340                 }
341                 else if (*tok == '*')
342                 {
343                         *evalTokenBuffer++ = CONST;
344
345                         if (orgactive)
346                                 *evalTokenBuffer++ = *a_value = orgaddr;
347                         else
348                                 *evalTokenBuffer++ = *a_value = pcloc;
349
350                         *a_attr = ABS | DEFINED;
351
352                         if (a_esym != NULL)
353                                 *a_esym = NULL;
354
355                         tok++;
356                 }
357                 else if (*tok == STRING || *tok == SYMBOL)
358                 {
359                         p = string[tok[1]];
360                         j = (*p == '.' ? curenv : 0);
361                         symbol = lookup(p, LABEL, j);
362 #if 0
363 printf("eval: Looking up symbol [=%08X]\n", symbol);
364 if (symbol)
365         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
366 #endif
367
368                         if (symbol == NULL)
369                                 symbol = NewSymbol(p, LABEL, j);
370
371                         symbol->sattr |= REFERENCED;
372
373                         // Check for undefined register equates, but only if it's not part
374                         // of a #<SYMBOL> construct, as it could be that the label that's
375                         // been undefined may later be used as an address label--which
376                         // means it will be fixed up later, and thus, not an error.
377                         if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
378                         {
379                                 errors("undefined register equate '%s'", symbol->sname);
380 //if we return right away, it returns some spurious errors...
381 //                              return ERROR;
382                         }
383
384                         // Check register bank usage
385                         if (symbol->sattre & EQUATEDREG)
386                         {
387                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)   
388                                         warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
389
390                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
391                                         warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
392                         }
393
394                         *evalTokenBuffer++ = SYMBOL;
395 #if 0
396                         *evalTokenBuffer++ = (TOKEN)symbol;
397 #else
398 /*
399 While this approach works, it's wasteful. It would be better to use something
400 that's already available, like the symbol "order defined" table (which needs to
401 be converted from a linked list into an array).
402 */
403                         *evalTokenBuffer++ = symbolNum;
404                         symbolPtr[symbolNum] = symbol;
405                         symbolNum++;
406 #endif
407
408                         if (symbol->sattr & DEFINED)
409                                 *a_value = symbol->svalue;
410                         else
411                                 *a_value = 0;
412
413 /*
414 All that extra crap that was put into the svalue when doing the equr stuff is
415 thrown away right here. What the hell is it for?
416 */
417                         if (symbol->sattre & EQUATEDREG) 
418                                 *a_value &= 0x1F;
419
420                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
421
422                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
423                                 *a_esym = symbol;
424
425                         tok += 2;
426                 }
427                 else
428                 {
429                         // Unknown type here... Alert the user!,
430                         error("undefined RISC register in expression");
431                         // Prevent spurious error reporting...
432                         tok++;
433                         return ERROR;
434                 }
435
436                 *evalTokenBuffer++ = ENDEXPR;
437                 return OK;
438         }
439
440         if (expr0() != OK)
441                 return ERROR;
442
443         *evalTokenBuffer++ = ENDEXPR;
444         return evexpr(otk, a_value, a_attr, a_esym);
445 }
446
447
448 //
449 // Evaluate expression.
450 // If the expression involves only ONE external symbol, the expression is
451 // UNDEFINED, but it's value includes everything but the symbol value, and
452 // `a_esym' is set to the external symbol.
453 //
454 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
455 {
456         WORD * sattr;
457         VALUE * sval;
458         WORD attr;
459         SYM * sy;
460         SYM * esym;
461         WORD sym_seg;
462
463         sval = evstk;                                                   // (Empty) initial stack
464         sattr = evattr;
465         esym = NULL;                                                    // No external symbol involved
466         sym_seg = 0;
467
468         while (*tk != ENDEXPR)
469         {
470                 switch ((int)*tk++)
471                 {
472                 case SYMBOL:
473 //printf("evexpr(): SYMBOL\n");
474                         sy = symbolPtr[*tk++];
475                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
476
477                         if (!(sy->sattr & DEFINED))
478                         {
479                                 // Reference to undefined symbol
480                                 if (!(sy->sattr & GLOBAL))
481                                 {
482                                         *a_attr = 0;
483                                         *a_value = 0;
484                                         return OK;
485                                 }
486
487                                 if (esym != NULL)                       // Check for multiple externals
488                                         return error(seg_error);
489
490                                 esym = sy;
491                         }
492
493                         if (sy->sattr & DEFINED)
494                         {
495                                 *++sval = sy->svalue;           // Push symbol's value
496                         }
497                         else
498                         {
499                                 *++sval = 0;                            // 0 for undefined symbols 
500                         }
501
502                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
503                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
504                         break;
505                 case CONST:
506 //printf("evexpr(): CONST = %i\n", *tk);
507                         *++sval = *tk++;                                // Push value
508                         *++sattr = ABS | DEFINED;               // Push simple attribs
509                         break;
510                 case ACONST:
511 //printf("evexpr(): ACONST = %i\n", *tk);
512                         *++sval = *tk++;                                // Push value
513                         *++sattr = (WORD)*tk++;                 // Push attribs
514                         break;
515
516                         // Binary "+" and "-" matrix:
517                         // 
518                         //                ABS    Sect     Other
519                         //     ----------------------------
520                         //   ABS     |  ABS   |  Sect  |  Other |
521                         //   Sect    |  Sect  |  [1]   |  Error |
522                         //   Other   |  Other |  Error |  [1]   |
523                         //      ----------------------------
524                         // 
525                         //   [1] + : Error
526                         //       - : ABS
527                 case '+':
528 //printf("evexpr(): +\n");
529                         --sval;                                                 // Pop value
530                         --sattr;                                                // Pop attrib 
531                         *sval += sval[1];                               // Compute value
532
533                         if (!(*sattr & (TEXT | DATA | BSS)))
534                                 *sattr = sattr[1];
535                         else if (sattr[1] & (TEXT | DATA | BSS))
536                                 return error(seg_error);
537
538                         break;
539                 case '-':
540 //printf("evexpr(): -\n");
541                         --sval;                                                 // Pop value
542                         --sattr;                                                // Pop attrib 
543                         *sval -= sval[1];                               // Compute value
544
545                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
546
547                         if (!attr)
548                                 *sattr = sattr[1];
549                         else if (sattr[1] & (TEXT | DATA | BSS))
550                         {
551                                 if (!(attr & sattr[1]))
552                                         return error(seg_error);
553                                 else
554                                         *sattr &= ~(TEXT | DATA | BSS);
555                         }
556
557                         break;
558                 // Unary operators only work on ABS items
559                 case UNMINUS:
560 //printf("evexpr(): UNMINUS\n");
561                         if (*sattr & (TEXT | DATA | BSS))
562                                 error(seg_error);
563
564                         *sval = -(int)*sval;
565                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
566                         break;
567                 case '!':
568 //printf("evexpr(): !\n");
569                         if (*sattr & (TEXT | DATA | BSS))
570                                 error(seg_error);
571
572                         *sval = !*sval;
573                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
574                         break;
575                 case '~':
576 //printf("evexpr(): ~\n");
577                         if (*sattr & (TEXT | DATA | BSS))
578                                 error(seg_error);
579
580                         *sval = ~*sval;
581                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
582                         break;
583                 // Comparison operators must have two values that
584                 // are in the same segment, but that's the only requirement.
585                 case LE:
586 //printf("evexpr(): LE\n");
587                         --sattr;
588                         --sval;
589
590                         if ((*sattr & TDB) != (sattr[1] & TDB))
591                                 error(seg_error);
592
593                         *sattr = ABS | DEFINED;
594                         *sval = *sval <= sval[1];
595                         break;
596                 case GE:
597 //printf("evexpr(): GE\n");
598                         --sattr;
599                         --sval;
600
601                         if ((*sattr & TDB) != (sattr[1] & TDB))
602                                 error(seg_error);
603
604                         *sattr = ABS | DEFINED;
605                         *sval = *sval >= sval[1];
606                         break;
607                 case '>':
608 //printf("evexpr(): >\n");
609                         --sattr;
610                         --sval;
611
612                         if ((*sattr & TDB) != (sattr[1] & TDB))
613                                 error(seg_error);
614
615                         *sattr = ABS | DEFINED;
616                         *sval = *sval > sval[1];
617                         break;
618                 case '<':
619 //printf("evexpr(): <\n");
620                         --sattr;
621                         --sval;
622
623                         if ((*sattr & TDB) != (sattr[1] & TDB))
624                                 error(seg_error);
625
626                         *sattr = ABS | DEFINED;
627                         *sval = *sval < sval[1];
628                         break;
629                 case NE:
630 //printf("evexpr(): NE\n");
631                         --sattr;
632                         --sval;
633
634                         if ((*sattr & TDB) != (sattr[1] & TDB))
635                                 error(seg_error);
636
637                         *sattr = ABS | DEFINED;
638                         *sval = *sval != sval[1];
639                         break;
640                 case '=':
641 //printf("evexpr(): =\n");
642                         --sattr;
643                         --sval;
644
645                         if ((*sattr & TDB) != (sattr[1] & TDB))
646                                 error(seg_error);
647
648                         *sattr = ABS | DEFINED;
649                         *sval = *sval == sval[1];
650                         break;
651                 // All other binary operators must have two ABS items
652                 // to work with.  They all produce an ABS value.
653                 default:
654 //printf("evexpr(): default\n");
655                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
656                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
657                         //error(seg_error);
658                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
659
660                         switch ((int)tk[-1])
661                         {
662                         case '*':
663                                 --sval;
664                                 --sattr;                                        // Pop attrib 
665                                 *sval *= sval[1];
666                                 break;
667                         case '/':
668                                 --sval;
669                                 --sattr;                                        // Pop attrib 
670
671                                 if (sval[1] == 0)
672                                         return error("divide by zero");
673
674                                 *sval /= sval[1];
675                                 break;
676                         case '%':
677                                 --sval;
678                                 --sattr;                                        // Pop attrib 
679
680                                 if (sval[1] == 0)
681                                         return error("mod (%) by zero");
682
683                                 *sval %= sval[1];
684                                 break;
685                         case SHL:
686                                 --sval;
687                                 --sattr;                                        // Pop attrib 
688                                 *sval <<= sval[1];
689                                 break;
690                         case SHR:
691                                 --sval;
692                                 --sattr;                                        // Pop attrib 
693                                 *sval >>= sval[1];
694                                 break;
695                         case '&':
696                                 --sval;
697                                 --sattr;                                        // Pop attrib 
698                                 *sval &= sval[1];
699                                 break;
700                         case '^':
701                                 --sval;
702                                 --sattr;                                        // Pop attrib 
703                                 *sval ^= sval[1];
704                                 break;
705                         case '|':
706                                 --sval;
707                                 --sattr;                                        // Pop attrib 
708                                 *sval |= sval[1];
709                                 break;
710                         default:
711                                 interror(5);                            // Bad operator in expression stream
712                         }
713                 }
714         }
715
716         if (esym != NULL)
717                 *sattr &= ~DEFINED;
718
719         if (a_esym != NULL)
720                 *a_esym = esym;
721
722         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
723         // expressions where absolute values also existed. The absolutes were
724         // overiding the symbol segments and not being included :(
725         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
726
727         *a_attr = *sattr;                                               // Copy value + attrib
728         *a_value = *sval;
729
730         return OK;
731 }
732