]> Shamusworld >> Repos - rmac/blob - expr.c
Forgot minor release number bump. :-P
[rmac] / expr.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "expr.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "listing.h"
13 #include "mach.h"
14 #include "procln.h"
15 #include "riscasm.h"
16 #include "sect.h"
17 #include "symbol.h"
18 #include "token.h"
19
20 #define DEF_KW                                                  // Declare keyword values 
21 #include "kwtab.h"                                              // Incl generated keyword tables & defs
22
23 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                         tok += 2;
339                 }
340                 else if (*tok == '*')
341                 {
342                         *evalTokenBuffer++ = CONST;
343
344                         if (orgactive)
345                                 *evalTokenBuffer++ = *a_value = orgaddr;
346                         else
347                                 *evalTokenBuffer++ = *a_value = pcloc;
348
349                         *a_attr = ABS | DEFINED;
350
351                         if (a_esym != NULL)
352                                 *a_esym = NULL;
353
354 //                      tok--;
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
363                         if (symbol == NULL)
364                                 symbol = NewSymbol(p, LABEL, j);
365
366                         symbol->sattr |= REFERENCED;
367
368                         // Check for undefined register equates
369                         if (symbol->sattre & UNDEF_EQUR)
370                         {
371                                 errors("undefined register equate '%s'", symbol->sname);
372 //if we return right away, it returns some spurious errors...
373 //                              return ERROR;
374                         }
375
376                         // Check register bank usage
377                         if (symbol->sattre & EQUATEDREG)
378                         {
379                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)   
380                                         warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
381
382                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
383                                         warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
384                         }
385
386                         *evalTokenBuffer++ = SYMBOL;
387 #if 0
388                         *evalTokenBuffer++ = (TOKEN)symbol;
389 #else
390 /*
391 While this approach works, it's wasteful. It would be better to use something
392 that's already available, like the symbol "order defined" table (which needs to
393 be converted from a linked list into an array).
394 */
395                         *evalTokenBuffer++ = symbolNum;
396                         symbolPtr[symbolNum] = symbol;
397                         symbolNum++;
398 #endif
399
400                         if (symbol->sattr & DEFINED)
401                                 *a_value = symbol->svalue;
402                         else
403                                 *a_value = 0;
404
405 /*
406 All that extra crap that was put into the svalue when doing the equr stuff is
407 thrown away right here. What the hell is it for?
408 */
409                         if (symbol->sattre & EQUATEDREG) 
410                                 *a_value &= 0x1F;
411
412                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
413
414                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
415                                 *a_esym = symbol;
416
417                         tok += 2;
418                 }
419                 else
420                 {
421                         // Unknown type here... Alert the user!
422                         error("undefined RISC register in expression");
423                         // Prevent spurious error reporting...
424                         tok++;
425                         return ERROR;
426                 }
427
428 //              tok += 2;
429                 *evalTokenBuffer++ = ENDEXPR;
430                 return OK;
431         }
432
433         if (expr0() != OK)
434                 return ERROR;
435
436         *evalTokenBuffer++ = ENDEXPR;
437         return evexpr(otk, a_value, a_attr, a_esym);
438 }
439
440
441 //
442 // Evaluate expression.
443 // If the expression involves only ONE external symbol, the expression is
444 // UNDEFINED, but it's value includes everything but the symbol value, and
445 // `a_esym' is set to the external symbol.
446 //
447 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
448 {
449         WORD * sattr;
450         VALUE * sval;
451         WORD attr;
452         SYM * sy;
453         SYM * esym;
454         WORD sym_seg;
455
456         sval = evstk;                                                   // (Empty) initial stack
457         sattr = evattr;
458         esym = NULL;                                                    // No external symbol involved
459         sym_seg = 0;
460
461         while (*tk != ENDEXPR)
462         {
463                 switch ((int)*tk++)
464                 {
465                 case SYMBOL:
466 //                      sy = (SYM *)*tk++;
467                         sy = symbolPtr[*tk++];
468                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
469
470                         if (!(sy->sattr & DEFINED))
471                         {
472                                 // Reference to undefined symbol
473                                 if (!(sy->sattr & GLOBAL))
474                                 {
475                                         *a_attr = 0;
476                                         *a_value = 0;
477                                         return OK;
478                                 }
479
480                                 if (esym != NULL)                       // Check for multiple externals
481                                         return error(seg_error);
482
483                                 esym = sy;
484                         }
485
486                         if (sy->sattr & DEFINED)
487                         {
488                                 *++sval = sy->svalue;           // Push symbol's value
489                         }
490                         else
491                         {
492                                 *++sval = 0;                            // 0 for undefined symbols 
493                         }
494
495                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
496                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
497                         break;
498                 case CONST:
499                         *++sval = *tk++;                                // Push value
500                         *++sattr = ABS | DEFINED;               // Push simple attribs
501                         break;
502                 case ACONST:
503                         *++sval = *tk++;                                // Push value
504                         *++sattr = (WORD)*tk++;                 // Push attribs
505                         break;
506
507                         // Binary "+" and "-" matrix:
508                         // 
509                         //                ABS    Sect     Other
510                         //     ----------------------------
511                         //   ABS     |  ABS   |  Sect  |  Other |
512                         //   Sect    |  Sect  |  [1]   |  Error |
513                         //   Other   |  Other |  Error |  [1]   |
514                         //      ----------------------------
515                         // 
516                         //   [1] + : Error
517                         //       - : ABS
518                 case '+':
519                         --sval;                                                 // Pop value
520                         --sattr;                                                // Pop attrib 
521                         *sval += sval[1];                               // Compute value
522
523                         if (!(*sattr & (TEXT | DATA | BSS)))
524                                 *sattr = sattr[1];
525                         else if (sattr[1] & (TEXT | DATA | BSS))
526                                 return error(seg_error);
527
528                         break;
529                 case '-':
530                         --sval;                                                 // Pop value
531                         --sattr;                                                // Pop attrib 
532                         *sval -= sval[1];                               // Compute value
533
534                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
535
536                         if (!attr)
537                                 *sattr = sattr[1];
538                         else if (sattr[1] & (TEXT | DATA | BSS))
539                         {
540                                 if (!(attr & sattr[1]))
541                                         return error(seg_error);
542                                 else
543                                         *sattr &= ~(TEXT | DATA | BSS);
544                         }
545
546                         break;
547                 // Unary operators only work on ABS items
548                 case UNMINUS:
549                         if (*sattr & (TEXT | DATA | BSS))
550                                 error(seg_error);
551
552                         *sval = -(int)*sval;
553                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
554                         break;
555                 case '!':
556                         if (*sattr & (TEXT | DATA | BSS))
557                                 error(seg_error);
558
559                         *sval = !*sval;
560                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
561                         break;
562                 case '~':
563                         if (*sattr & (TEXT | DATA | BSS))
564                                 error(seg_error);
565
566                         *sval = ~*sval;
567                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
568                         break;
569                 // Comparison operators must have two values that
570                 // are in the same segment, but that's the only requirement.
571                 case LE:
572                         --sattr;
573                         --sval;
574
575                         if ((*sattr & TDB) != (sattr[1] & TDB))
576                                 error(seg_error);
577
578                         *sattr = ABS | DEFINED;
579                         *sval = *sval <= sval[1];
580                         break;
581                 case GE:
582                         --sattr;
583                         --sval;
584
585                         if ((*sattr & TDB) != (sattr[1] & TDB))
586                                 error(seg_error);
587
588                         *sattr = ABS | DEFINED;
589                         *sval = *sval >= sval[1];
590                         break;
591                 case '>':
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 '<':
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 NE:
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                 // All other binary operators must have two ABS items
632                 // to work with.  They all produce an ABS value.
633                 default:
634                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
635                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
636                         //error(seg_error);
637                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
638
639                         switch ((int)tk[-1])
640                         {
641                         case '*':
642                                 --sval;
643                                 --sattr;                                        // Pop attrib 
644                                 *sval *= sval[1];
645                                 break;
646                         case '/':
647                                 --sval;
648                                 --sattr;                                        // Pop attrib 
649
650                                 if (sval[1] == 0)
651                                         return error("divide by zero");
652
653                                 *sval /= sval[1];
654                                 break;
655                         case '%':
656                                 --sval;
657                                 --sattr;                                        // Pop attrib 
658
659                                 if (sval[1] == 0)
660                                         return error("mod (%) by zero");
661
662                                 *sval %= sval[1];
663                                 break;
664                         case SHL:
665                                 --sval;
666                                 --sattr;                                        // Pop attrib 
667                                 *sval <<= sval[1];
668                                 break;
669                         case SHR:
670                                 --sval;
671                                 --sattr;                                        // Pop attrib 
672                                 *sval >>= sval[1];
673                                 break;
674                         case '&':
675                                 --sval;
676                                 --sattr;                                        // Pop attrib 
677                                 *sval &= sval[1];
678                                 break;
679                         case '^':
680                                 --sval;
681                                 --sattr;                                        // Pop attrib 
682                                 *sval ^= sval[1];
683                                 break;
684                         case '|':
685                                 --sval;
686                                 --sattr;                                        // Pop attrib 
687                                 *sval |= sval[1];
688                                 break;
689                         default:
690                                 interror(5);                            // Bad operator in expression stream
691                         }
692                 }
693         }
694
695         if (esym != NULL)
696                 *sattr &= ~DEFINED;
697
698         if (a_esym != NULL)
699                 *a_esym = esym;
700
701         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
702         // expressions where absolute values also existed. The absolutes were
703         // overiding the symbol segments and not being included :(
704         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
705
706         *a_attr = *sattr;                                               // Copy value + attrib
707         *a_value = *sval;
708
709         return OK;
710 }