]> Shamusworld >> Repos - rmac/blob - expr.c
Fix silly mask bugs, added check for use of undefined register equates.
[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 static char tokcl[128];                                 // Generated table of token classes
24 static VALUE evstk[EVSTACKSIZE];                // Evaluator value stack
25 static WORD evattr[EVSTACKSIZE];                // Evaluator attribute stack
26
27 // Token-class initialization list
28 char itokcl[] = {
29         0,                                                                      // END
30         CONST, SYMBOL, 0,                                       // ID 
31         '(', '[', '{', 0,                                       // OPAR
32         ')', ']', '}', 0,                                       // CPAR 
33         CR_DEFINED, CR_REFERENCED,                      // SUNARY (special unary)
34         CR_STREQ, CR_MACDEF,
35         CR_DATE, CR_TIME, 0,
36         '!', '~', UNMINUS, 0,                           // UNARY
37         '*', '/', '%', 0,                                       // MULT 
38         '+', '-', 0,                                            // ADD 
39         SHL, SHR, 0,                                            // SHIFT 
40         LE, GE, '<', '>', NE, '=', 0,           // REL 
41         '&', 0,                                                         // AND 
42         '^', 0,                                                         // XOR 
43         '|', 0,                                                         // OR 
44         1                                                                       // (the end) 
45 };
46
47 const char missym_error[] = "missing symbol";
48 const char str_error[] = "missing symbol or string";
49
50 // Convert expression to postfix
51 static TOKEN * tk;                                              // Deposit tokens here (this is really a
52                                                                                 // pointer to exprbuf from direct.c)
53 static symbolNum;                                               // Pointer to the entry in symbolPtr[]
54
55
56 //
57 // Obtain a String Value
58 //
59 static VALUE str_value(char * p)
60 {
61         VALUE v;
62
63         for(v=0; *p; p++)
64                 v = (v << 8) | (*p & 0xFF);
65
66         return v;
67 }
68
69
70 //
71 // Initialize Expression Analyzer
72 //
73 void init_expr(void)
74 {
75         int i;                                                                  // Iterator
76         char * p;                                                               // Token pointer
77
78         // Initialize token-class table
79         for(i=0; i<128; i++)                                    // Mark all entries END
80                 tokcl[i] = END;
81
82         for(i=0, p=itokcl; *p!=1; p++)
83         {
84                 if (*p == 0)
85                         i++;
86                 else 
87                         tokcl[(int)(*p)] = (char)i;
88         }
89
90         symbolNum = 0;
91 }
92
93
94 //
95 // Binary operators (all the same precedence)
96 //
97 int expr0(void)
98 {
99         TOKEN t;
100
101         if (expr1() != OK)
102                 return ERROR;
103         
104         while (tokcl[*tok] >= MULT)
105         {
106                 t = *tok++;
107
108                 if (expr1() != OK)
109                         return ERROR;
110
111                 *tk++ = t;
112         }
113
114         return OK;
115 }
116
117
118 //
119 // Unary operators (detect unary '-')
120 //
121 int expr1(void)
122 {
123         int class;
124         TOKEN t;
125         SYM * sy;
126         char * p, * p2;
127         WORD w;
128         int j;
129
130         class = tokcl[*tok];
131
132         if (*tok == '-' || class == UNARY)
133         {
134                 t = *tok++;
135
136                 if (expr2() != OK)
137                         return ERROR;
138
139                 if (t == '-')
140                         t = UNMINUS;
141
142                 *tk++ = t;
143         }
144         else if (class == SUNARY)
145         {
146                 switch ((int)*tok++)
147                 {
148                 case CR_TIME:
149                         *tk++ = CONST;
150                         *tk++ = dos_time();
151                         break;
152                 case CR_DATE:
153                         *tk++ = CONST;
154                         *tk++ = dos_date();
155                         break;
156                 case CR_MACDEF:                                    // ^^macdef <macro-name>
157                         if (*tok++ != SYMBOL)
158                                 return error(missym_error);
159
160 #if 0
161                         p = (char *)*tok++;
162 #else
163                         p = string[*tok++];
164 #endif
165                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
166                         *tk++ = CONST;
167                         *tk++ = (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 #if 0
179                         p = (char *)*tok++;
180 #else
181                         p = string[*tok++];
182 #endif
183                         j = 0;
184
185                         if (*p == '.')
186                                 j = curenv;
187
188                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
189                         *tk++ = CONST;
190                         *tk++ = (TOKEN)w;
191                         break;
192                 case CR_STREQ:
193                         if (*tok != SYMBOL && *tok != STRING)
194                                 return error(str_error);
195
196 #if 0
197                         p = (char *)tok[1];
198 #else
199                         p = string[tok[1]];
200 #endif
201                         tok +=2;
202
203                         if (*tok++ != ',')
204                                 return error(comma_error);
205
206                         if (*tok != SYMBOL && *tok != STRING)
207                                 return error(str_error);
208
209 #if 0
210                         p2 = (char *)tok[1];
211 #else
212                         p = string[tok[1]];
213 #endif
214                         tok += 2;
215
216                         w = (WORD)(!strcmp(p, p2));
217                         *tk++ = CONST;
218                         *tk++ = (TOKEN)w;
219                         break;
220                 }
221         }
222         else 
223                 return expr2();
224
225         return OK;
226 }
227
228
229 //
230 // Terminals (CONSTs) and parenthesis grouping
231 //
232 int expr2(void)
233 {
234         char * p;
235         SYM * sy;
236         int j;
237
238         switch ((int)*tok++)
239         {
240         case CONST:
241                 *tk++ = CONST;
242                 *tk++ = *tok++;
243                 break;
244         case SYMBOL:
245 #if 0
246                 p = (char *)*tok++;
247 #else
248                 p = string[*tok++];
249 #endif
250                 j = 0;
251
252                 if (*p == '.')
253                         j = curenv;
254
255                 sy = lookup(p, LABEL, j);
256
257                 if (sy == NULL)
258                         sy = NewSymbol(p, LABEL, j);
259
260                 // Check register bank usage
261                 if (sy->sattre & EQUATEDREG)
262                 {
263                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
264                                 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
265
266                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
267                                 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
268                 }
269
270                 *tk++ = SYMBOL;
271 #if 0
272                 *tk++ = (TOKEN)sy;
273 #else
274                 *tk++ = symbolNum;
275                 symbolPtr[symbolNum] = sy;
276                 symbolNum++;
277 #endif
278                 break;
279         case STRING:
280                 *tk++ = CONST;
281 #if 0
282                 *tk++ = str_value((char *)*tok++);
283 #else
284                 *tk++ = str_value(string[*tok++]);
285 #endif
286                 break;
287         case '(':
288                 if (expr0() != OK)
289                         return ERROR;
290
291                 if (*tok++ != ')')
292                         return error("missing close parenthesis ')'");
293
294                 break;
295         case '[':
296                 if (expr0() != OK)
297                         return ERROR;
298
299                 if (*tok++ != ']')
300                         return error("missing close parenthesis ']'");
301
302                 break;
303         case '$':
304                 *tk++ = ACONST;                                    // Attributed const
305                 *tk++ = sloc;                                      // Current location
306                 *tk++ = cursect | DEFINED;                         // Store attribs
307                 break;
308         case '*':
309                 *tk++ = ACONST;                                    // Attributed const
310
311                 if (orgactive)
312                         *tk++ = orgaddr;
313                 else
314                         *tk++ = pcloc;                                  // Location at start of line
315
316                 *tk++ = ABS | DEFINED;                             // Store attribs
317                 break;
318         default:
319                 return error("bad expression");
320         }
321
322         return OK;
323 }
324
325
326 //
327 // Recursive-descent expression analyzer (with some simple speed hacks)
328 //
329 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
330 {
331         // Passed in values (once derefenced, that is) can all be zero. They are
332         // there so that the expression analyzer can fill them in as needed. The
333         // expression analyzer gets its input from "tok", and not from anything
334         // passed in by the user.
335         SYM * sy;
336         char * p;
337         int j;
338
339         tk = otk;                       // Set token pointer to 'exprbuf' (direct.c)
340                                                 // Also set in various other places too (riscasm.c, e.g.)
341 //      symbolNum = 0;          // Set symbol number in symbolPtr[] to 0
342
343         // Optimize for single constant or single symbol.
344         if ((tok[1] == EOL)
345                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
346                 && (tokcl[tok[2]] < UNARY)))
347         {
348                 if (*tok >= KW_R0 && *tok <= KW_R31)
349                 {
350                         *tk++ = CONST;
351                         *tk++ = *a_value = (*tok - KW_R0);
352                         *a_attr = ABS | DEFINED;
353
354                         if (a_esym != NULL)
355                                 *a_esym = NULL;
356
357                         tok++;
358                         *tk++ = ENDEXPR;
359                         return OK;
360                 }
361                 else if (*tok == CONST)
362                 {
363                         *tk++ = CONST;
364                         *tk++ = *a_value = tok[1];
365                         *a_attr = ABS | DEFINED;
366
367                         if (a_esym != NULL)
368                                 *a_esym = NULL;
369                 }
370                 else if (*tok == '*')
371                 {
372                         *tk++ = CONST;
373
374                         if (orgactive)
375                                 *tk++ = *a_value = orgaddr;
376                         else
377                                 *tk++ = *a_value = pcloc;
378
379                         *a_attr = ABS | DEFINED;
380                         //*tk++ = 
381
382                         if (a_esym != NULL)
383                                 *a_esym = NULL;
384
385                         tok--;
386                 }
387                 else
388                 {
389                         p = string[tok[1]];
390
391 #if 0
392                         j = 0;
393
394                         if (*p == '.')
395                                 j = curenv;
396 #else
397                         j = (*p == '.' ? curenv : 0);
398 #endif
399
400                         sy = lookup(p, LABEL, j);
401
402                         if (sy == NULL)
403                                 sy = NewSymbol(p, LABEL, j);
404
405                         sy->sattr |= REFERENCED;
406
407                         // Check for undefined register equates
408                         if (sy->sattre & UNDEF_EQUR)
409                         {
410                                 errors("undefined register equate '%s'", sy->sname);
411 //if we return right away, it returns some spurious errors...
412 //                              return ERROR;
413                         }
414
415                         // Check register bank usage
416                         if (sy->sattre & EQUATEDREG)
417                         {
418                                 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
419                                         warns("equated symbol '%s' cannot be used in register bank 0", sy->sname);
420
421                                 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
422                                         warns("equated symbol '%s' cannot be used in register bank 1", sy->sname);
423                         }
424
425                         *tk++ = SYMBOL;
426 #if 0
427                         *tk++ = (TOKEN)sy;
428 #else
429                         *tk++ = symbolNum;
430                         symbolPtr[symbolNum] = sy;
431                         symbolNum++;
432 #endif
433
434                         if (sy->sattr & DEFINED)
435                                 *a_value = sy->svalue;
436                         else
437                                 *a_value = 0;
438
439                         if (sy->sattre & EQUATEDREG) 
440                                 *a_value &= 0x1F;
441
442                         *a_attr = (WORD)(sy->sattr & ~GLOBAL);
443
444                         if ((sy->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
445                                 *a_esym = sy;
446                 }
447
448                 tok += 2;
449                 *tk++ = ENDEXPR;
450                 return OK;
451         }
452
453         if (expr0() != OK)
454                 return ERROR;
455
456         *tk++ = ENDEXPR;
457         return evexpr(otk, a_value, a_attr, a_esym);
458 }
459
460
461 //
462 // Evaluate expression.
463 // If the expression involves only ONE external symbol, the expression is
464 // UNDEFINED, but it's value includes everything but the symbol value, and
465 // `a_esym' is set to the external symbol.
466 //
467 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
468 {
469         WORD * sattr;
470         VALUE * sval;
471         WORD attr;
472         SYM * sy;
473         SYM * esym;
474         WORD sym_seg;
475
476         sval = evstk;                                                   // (Empty) initial stack
477         sattr = evattr;
478         esym = NULL;                                                    // No external symbol involved
479         sym_seg = 0;
480
481         while (*tk != ENDEXPR)
482         {
483                 switch ((int)*tk++)
484                 {
485                 case SYMBOL:
486 //                      sy = (SYM *)*tk++;
487                         sy = symbolPtr[*tk++];
488                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
489
490                         if (!(sy->sattr & DEFINED))
491                         {
492                                 // Reference to undefined symbol
493                                 if (!(sy->sattr & GLOBAL))
494                                 {
495                                         *a_attr = 0;
496                                         *a_value = 0;
497                                         return OK;
498                                 }
499
500                                 if (esym != NULL)                       // Check for multiple externals
501                                         return error(seg_error);
502
503                                 esym = sy;
504                         }
505
506                         if (sy->sattr & DEFINED)
507                         {
508                                 *++sval = sy->svalue;           // Push symbol's value
509                         }
510                         else
511                         {
512                                 *++sval = 0;                            // 0 for undefined symbols 
513                         }
514
515                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
516                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
517                         break;
518                 case CONST:
519                         *++sval = *tk++;                                // Push value
520                         *++sattr = ABS | DEFINED;               // Push simple attribs
521                         break;
522                 case ACONST:
523                         *++sval = *tk++;                                // Push value
524                         *++sattr = (WORD)*tk++;                 // Push attribs
525                         break;
526
527                         // Binary "+" and "-" matrix:
528                         // 
529                         //                ABS    Sect     Other
530                         //     ----------------------------
531                         //   ABS     |  ABS   |  Sect  |  Other |
532                         //   Sect    |  Sect  |  [1]   |  Error |
533                         //   Other   |  Other |  Error |  [1]   |
534                         //      ----------------------------
535                         // 
536                         //   [1] + : Error
537                         //       - : ABS
538                 case '+':
539                         --sval;                                                 // Pop value
540                         --sattr;                                                // Pop attrib 
541                         *sval += sval[1];                               // Compute value
542
543                         if (!(*sattr & (TEXT | DATA | BSS)))
544                                 *sattr = sattr[1];
545                         else if (sattr[1] & (TEXT | DATA | BSS))
546                                 return error(seg_error);
547
548                         break;
549                 case '-':
550                         --sval;                                                 // Pop value
551                         --sattr;                                                // Pop attrib 
552                         *sval -= sval[1];                               // Compute value
553
554                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
555
556                         if (!attr)
557                                 *sattr = sattr[1];
558                         else if (sattr[1] & (TEXT | DATA | BSS))
559                         {
560                                 if (!(attr & sattr[1]))
561                                         return error(seg_error);
562                                 else
563                                         *sattr &= ~(TEXT | DATA | BSS);
564                         }
565
566                         break;
567                 // Unary operators only work on ABS items
568                 case UNMINUS:
569                         if (*sattr & (TEXT | DATA | BSS))
570                                 error(seg_error);
571
572                         *sval = -(int)*sval;
573                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
574                         break;
575                 case '!':
576                         if (*sattr & (TEXT | DATA | BSS))
577                                 error(seg_error);
578
579                         *sval = !*sval;
580                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
581                         break;
582                 case '~':
583                         if (*sattr & (TEXT | DATA | BSS))
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                         --sattr;
593                         --sval;
594
595                         if ((*sattr & TDB) != (sattr[1] & TDB))
596                                 error(seg_error);
597
598                         *sattr = ABS | DEFINED;
599                         *sval = *sval <= sval[1];
600                         break;
601                 case GE:
602                         --sattr;
603                         --sval;
604
605                         if ((*sattr & TDB) != (sattr[1] & TDB))
606                                 error(seg_error);
607
608                         *sattr = ABS | DEFINED;
609                         *sval = *sval >= sval[1];
610                         break;
611                 case '>':
612                         --sattr;
613                         --sval;
614
615                         if ((*sattr & TDB) != (sattr[1] & TDB))
616                                 error(seg_error);
617
618                         *sattr = ABS | DEFINED;
619                         *sval = *sval > sval[1];
620                         break;
621                 case '<':
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                         --sattr;
633                         --sval;
634
635                         if ((*sattr & TDB) != (sattr[1] & TDB))
636                                 error(seg_error);
637
638                         *sattr = ABS | DEFINED;
639                         *sval = *sval != sval[1];
640                         break;
641                 case '=':
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                         // 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 }