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