]> Shamusworld >> Repos - rmac/blob - expr.c
Fixed a nasty bug that dropped symbols that shouldn't have been.
[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 (%s) [=%08X]\n", p, 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                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
420
421                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
422                                 *a_esym = symbol;
423
424                         tok += 2;
425                 }
426                 else
427                 {
428                         // Unknown type here... Alert the user!,
429                         error("undefined RISC register in expression");
430                         // Prevent spurious error reporting...
431                         tok++;
432                         return ERROR;
433                 }
434
435                 *evalTokenBuffer++ = ENDEXPR;
436                 return OK;
437         }
438
439         if (expr0() != OK)
440                 return ERROR;
441
442         *evalTokenBuffer++ = ENDEXPR;
443         return evexpr(otk, a_value, a_attr, a_esym);
444 }
445
446
447 //
448 // Evaluate expression.
449 // If the expression involves only ONE external symbol, the expression is
450 // UNDEFINED, but it's value includes everything but the symbol value, and
451 // `a_esym' is set to the external symbol.
452 //
453 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
454 {
455         WORD * sattr;
456         VALUE * sval;
457         WORD attr;
458         SYM * sy;
459         SYM * esym;
460         WORD sym_seg;
461
462         sval = evstk;                                                   // (Empty) initial stack
463         sattr = evattr;
464         esym = NULL;                                                    // No external symbol involved
465         sym_seg = 0;
466
467         while (*tk != ENDEXPR)
468         {
469                 switch ((int)*tk++)
470                 {
471                 case SYMBOL:
472 //printf("evexpr(): SYMBOL\n");
473                         sy = symbolPtr[*tk++];
474                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
475
476                         if (!(sy->sattr & DEFINED))
477                         {
478                                 // Reference to undefined symbol
479                                 if (!(sy->sattr & GLOBAL))
480                                 {
481                                         *a_attr = 0;
482                                         *a_value = 0;
483                                         return OK;
484                                 }
485
486                                 if (esym != NULL)                       // Check for multiple externals
487                                         return error(seg_error);
488
489                                 esym = sy;
490                         }
491
492                         if (sy->sattr & DEFINED)
493                         {
494                                 *++sval = sy->svalue;           // Push symbol's value
495                         }
496                         else
497                         {
498                                 *++sval = 0;                            // 0 for undefined symbols 
499                         }
500
501                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
502                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
503                         break;
504                 case CONST:
505 //printf("evexpr(): CONST = %i\n", *tk);
506                         *++sval = *tk++;                                // Push value
507                         *++sattr = ABS | DEFINED;               // Push simple attribs
508                         break;
509                 case ACONST:
510 //printf("evexpr(): ACONST = %i\n", *tk);
511                         *++sval = *tk++;                                // Push value
512                         *++sattr = (WORD)*tk++;                 // Push attribs
513                         break;
514
515                         // Binary "+" and "-" matrix:
516                         // 
517                         //                ABS    Sect     Other
518                         //     ----------------------------
519                         //   ABS     |  ABS   |  Sect  |  Other |
520                         //   Sect    |  Sect  |  [1]   |  Error |
521                         //   Other   |  Other |  Error |  [1]   |
522                         //      ----------------------------
523                         // 
524                         //   [1] + : Error
525                         //       - : ABS
526                 case '+':
527 //printf("evexpr(): +\n");
528                         --sval;                                                 // Pop value
529                         --sattr;                                                // Pop attrib 
530                         *sval += sval[1];                               // Compute value
531
532                         if (!(*sattr & (TEXT | DATA | BSS)))
533                                 *sattr = sattr[1];
534                         else if (sattr[1] & (TEXT | DATA | BSS))
535                                 return error(seg_error);
536
537                         break;
538                 case '-':
539 //printf("evexpr(): -\n");
540                         --sval;                                                 // Pop value
541                         --sattr;                                                // Pop attrib 
542                         *sval -= sval[1];                               // Compute value
543
544                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
545
546                         if (!attr)
547                                 *sattr = sattr[1];
548                         else if (sattr[1] & (TEXT | DATA | BSS))
549                         {
550                                 if (!(attr & sattr[1]))
551                                         return error(seg_error);
552                                 else
553                                         *sattr &= ~(TEXT | DATA | BSS);
554                         }
555
556                         break;
557                 // Unary operators only work on ABS items
558                 case UNMINUS:
559 //printf("evexpr(): UNMINUS\n");
560                         if (*sattr & (TEXT | DATA | BSS))
561                                 error(seg_error);
562
563                         *sval = -(int)*sval;
564                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
565                         break;
566                 case '!':
567 //printf("evexpr(): !\n");
568                         if (*sattr & (TEXT | DATA | BSS))
569                                 error(seg_error);
570
571                         *sval = !*sval;
572                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
573                         break;
574                 case '~':
575 //printf("evexpr(): ~\n");
576                         if (*sattr & (TEXT | DATA | BSS))
577                                 error(seg_error);
578
579                         *sval = ~*sval;
580                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
581                         break;
582                 // Comparison operators must have two values that
583                 // are in the same segment, but that's the only requirement.
584                 case LE:
585 //printf("evexpr(): LE\n");
586                         --sattr;
587                         --sval;
588
589                         if ((*sattr & TDB) != (sattr[1] & TDB))
590                                 error(seg_error);
591
592                         *sattr = ABS | DEFINED;
593                         *sval = *sval <= sval[1];
594                         break;
595                 case GE:
596 //printf("evexpr(): GE\n");
597                         --sattr;
598                         --sval;
599
600                         if ((*sattr & TDB) != (sattr[1] & TDB))
601                                 error(seg_error);
602
603                         *sattr = ABS | DEFINED;
604                         *sval = *sval >= sval[1];
605                         break;
606                 case '>':
607 //printf("evexpr(): >\n");
608                         --sattr;
609                         --sval;
610
611                         if ((*sattr & TDB) != (sattr[1] & TDB))
612                                 error(seg_error);
613
614                         *sattr = ABS | DEFINED;
615                         *sval = *sval > sval[1];
616                         break;
617                 case '<':
618 //printf("evexpr(): <\n");
619                         --sattr;
620                         --sval;
621
622                         if ((*sattr & TDB) != (sattr[1] & TDB))
623                                 error(seg_error);
624
625                         *sattr = ABS | DEFINED;
626                         *sval = *sval < sval[1];
627                         break;
628                 case NE:
629 //printf("evexpr(): NE\n");
630                         --sattr;
631                         --sval;
632
633                         if ((*sattr & TDB) != (sattr[1] & TDB))
634                                 error(seg_error);
635
636                         *sattr = ABS | DEFINED;
637                         *sval = *sval != sval[1];
638                         break;
639                 case '=':
640 //printf("evexpr(): =\n");
641                         --sattr;
642                         --sval;
643
644                         if ((*sattr & TDB) != (sattr[1] & TDB))
645                                 error(seg_error);
646
647                         *sattr = ABS | DEFINED;
648                         *sval = *sval == sval[1];
649                         break;
650                 // All other binary operators must have two ABS items
651                 // to work with.  They all produce an ABS value.
652                 default:
653 //printf("evexpr(): default\n");
654                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
655                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
656                         //error(seg_error);
657                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
658
659                         switch ((int)tk[-1])
660                         {
661                         case '*':
662                                 --sval;
663                                 --sattr;                                        // Pop attrib 
664                                 *sval *= sval[1];
665                                 break;
666                         case '/':
667                                 --sval;
668                                 --sattr;                                        // Pop attrib 
669
670                                 if (sval[1] == 0)
671                                         return error("divide by zero");
672
673                                 *sval /= sval[1];
674                                 break;
675                         case '%':
676                                 --sval;
677                                 --sattr;                                        // Pop attrib 
678
679                                 if (sval[1] == 0)
680                                         return error("mod (%) by zero");
681
682                                 *sval %= sval[1];
683                                 break;
684                         case SHL:
685                                 --sval;
686                                 --sattr;                                        // Pop attrib 
687                                 *sval <<= sval[1];
688                                 break;
689                         case SHR:
690                                 --sval;
691                                 --sattr;                                        // Pop attrib 
692                                 *sval >>= sval[1];
693                                 break;
694                         case '&':
695                                 --sval;
696                                 --sattr;                                        // Pop attrib 
697                                 *sval &= sval[1];
698                                 break;
699                         case '^':
700                                 --sval;
701                                 --sattr;                                        // Pop attrib 
702                                 *sval ^= sval[1];
703                                 break;
704                         case '|':
705                                 --sval;
706                                 --sattr;                                        // Pop attrib 
707                                 *sval |= sval[1];
708                                 break;
709                         default:
710                                 interror(5);                            // Bad operator in expression stream
711                         }
712                 }
713         }
714
715         if (esym != NULL)
716                 *sattr &= ~DEFINED;
717
718         if (a_esym != NULL)
719                 *a_esym = esym;
720
721         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
722         // expressions where absolute values also existed. The absolutes were
723         // overiding the symbol segments and not being included :(
724         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
725
726         *a_attr = *sattr;                                               // Copy value + attrib
727         *a_value = *sval;
728
729         return OK;
730 }
731