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