]> Shamusworld >> Repos - rmac/blob - expr.c
Forgot to bump patch level on version.h :-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 "risca.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         SYM * sy;
332         char * p;
333         int j;
334
335         tk = otk;                                                               // Set token pointer to 'exprbuf' (direct.c)
336 //      symbolNum = 0;                                                  // Set symbol number in symbolPtr[] to 0
337
338         // Optimize for single constant or single symbol.
339         if ((tok[1] == EOL)
340                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
341                 && (tokcl[tok[2]] < UNARY)))
342         {
343                 if (*tok >= KW_R0 && *tok <= KW_R31)
344                 {
345                         *tk++ = CONST;
346                         *tk++ = *a_value = (*tok - KW_R0);
347                         *a_attr = ABS | DEFINED;
348
349                         if (a_esym != NULL)
350                                 *a_esym = NULL;
351
352                         tok++;
353                         *tk++ = ENDEXPR;
354                         return OK;
355                 }
356                 else if (*tok == CONST)
357                 {
358                         *tk++ = CONST;
359                         *tk++ = *a_value = tok[1];
360                         *a_attr = ABS | DEFINED;
361
362                         if (a_esym != NULL)
363                                 *a_esym = NULL;
364                 }
365                 else if (*tok == '*')
366                 {
367                         *tk++ = CONST;
368
369                         if (orgactive)
370                                 *tk++ = *a_value = orgaddr;
371                         else
372                                 *tk++ = *a_value = pcloc;
373
374                         *a_attr = ABS | DEFINED;
375                         //*tk++ = 
376
377                         if (a_esym != NULL)
378                                 *a_esym = NULL;
379
380                         tok--;
381                 }
382                 else
383                 {
384 #if 0
385                         p = (char *)tok[1];
386 #else
387                         p = string[tok[1]];
388 #endif
389                         j = 0;
390
391                         if (*p == '.')
392                                 j = curenv;
393
394                         sy = lookup(p, LABEL, j);
395
396                         if (sy == NULL)
397                                 sy = NewSymbol(p, LABEL, j);
398
399                         sy->sattr |= REFERENCED;
400
401                         // Check register bank usage
402                         if (sy->sattre & EQUATEDREG)
403                         {
404                                 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
405                                         warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
406
407                                 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
408                                         warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
409                         }
410
411                         *tk++ = SYMBOL;
412 #if 0
413                         *tk++ = (TOKEN)sy;
414 #else
415                         *tk++ = symbolNum;
416                         symbolPtr[symbolNum] = sy;
417                         symbolNum++;
418 #endif
419
420                         if (sy->sattr & DEFINED)
421                                 *a_value = sy->svalue;
422                         else
423                                 *a_value = 0;
424
425                         if (sy->sattre & EQUATEDREG) 
426                                 *a_value &= 0x1F;
427
428                         *a_attr = (WORD)(sy->sattr & ~GLOBAL);
429
430                         if ((sy->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
431                                 *a_esym = sy;
432                 }
433
434                 tok += 2;
435                 *tk++ = ENDEXPR;
436                 return OK;
437         }
438
439         if (expr0() != OK)
440                 return ERROR;
441
442         *tk++ = ENDEXPR;
443         return evexpr(otk, a_value, a_attr, a_esym);
444 }
445
446
447 //
448 // Evaluate expression.
449 // If the expression involves only ONE external symbol, the expression is
450 // UNDEFINED, but it's value includes everything but the symbol value, and
451 // `a_esym' is set to the external symbol.
452 //
453 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
454 {
455         WORD * sattr;
456         VALUE * sval;
457         WORD attr;
458         SYM * sy;
459         SYM * esym;
460         WORD sym_seg;
461
462         sval = evstk;                                                   // (Empty) initial stack
463         sattr = evattr;
464         esym = NULL;                                                    // No external symbol involved
465         sym_seg = 0;
466
467         while (*tk != ENDEXPR)
468         {
469                 switch ((int)*tk++)
470                 {
471                 case SYMBOL:
472 //                      sy = (SYM *)*tk++;
473                         sy = symbolPtr[*tk++];
474                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
475
476                         if (!(sy->sattr & DEFINED))
477                         {
478                                 // Reference to undefined symbol
479                                 if (!(sy->sattr & GLOBAL))
480                                 {
481                                         *a_attr = 0;
482                                         *a_value = 0;
483                                         return OK;
484                                 }
485
486                                 if (esym != NULL)                       // Check for multiple externals
487                                         return error(seg_error);
488
489                                 esym = sy;
490                         }
491
492                         if (sy->sattr & DEFINED)
493                         {
494                                 *++sval = sy->svalue;           // Push symbol's value
495                         }
496                         else
497                         {
498                                 *++sval = 0;                            // 0 for undefined symbols 
499                         }
500
501                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
502                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
503                         break;
504                 case CONST:
505                         *++sval = *tk++;                                // Push value
506                         *++sattr = ABS | DEFINED;               // Push simple attribs
507                         break;
508                 case ACONST:
509                         *++sval = *tk++;                                // Push value
510                         *++sattr = (WORD)*tk++;                 // Push attribs
511                         break;
512
513                         // Binary "+" and "-" matrix:
514                         // 
515                         //                ABS    Sect     Other
516                         //     ----------------------------
517                         //   ABS     |  ABS   |  Sect  |  Other |
518                         //   Sect    |  Sect  |  [1]   |  Error |
519                         //   Other   |  Other |  Error |  [1]   |
520                         //      ----------------------------
521                         // 
522                         //   [1] + : Error
523                         //       - : ABS
524                 case '+':
525                         --sval;                                                 // Pop value
526                         --sattr;                                                // Pop attrib 
527                         *sval += sval[1];                               // Compute value
528
529                         if (!(*sattr & (TEXT | DATA | BSS)))
530                                 *sattr = sattr[1];
531                         else if (sattr[1] & (TEXT | DATA | BSS))
532                                 return error(seg_error);
533
534                         break;
535                 case '-':
536                         --sval;                                                 // Pop value
537                         --sattr;                                                // Pop attrib 
538                         *sval -= sval[1];                               // Compute value
539
540                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
541
542                         if (!attr)
543                                 *sattr = sattr[1];
544                         else if (sattr[1] & (TEXT | DATA | BSS))
545                         {
546                                 if (!(attr & sattr[1]))
547                                         return error(seg_error);
548                                 else
549                                         *sattr &= ~(TEXT | DATA | BSS);
550                         }
551
552                         break;
553                 // Unary operators only work on ABS items
554                 case UNMINUS:
555                         if (*sattr & (TEXT | DATA | BSS))
556                                 error(seg_error);
557
558                         *sval = -(int)*sval;
559                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
560                         break;
561                 case '!':
562                         if (*sattr & (TEXT | DATA | BSS))
563                                 error(seg_error);
564
565                         *sval = !*sval;
566                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
567                         break;
568                 case '~':
569                         if (*sattr & (TEXT | DATA | BSS))
570                                 error(seg_error);
571
572                         *sval = ~*sval;
573                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
574                         break;
575                 // Comparison operators must have two values that
576                 // are in the same segment, but that's the only requirement.
577                 case LE:
578                         --sattr;
579                         --sval;
580
581                         if ((*sattr & TDB) != (sattr[1] & TDB))
582                                 error(seg_error);
583
584                         *sattr = ABS | DEFINED;
585                         *sval = *sval <= sval[1];
586                         break;
587                 case GE:
588                         --sattr;
589                         --sval;
590
591                         if ((*sattr & TDB) != (sattr[1] & TDB))
592                                 error(seg_error);
593
594                         *sattr = ABS | DEFINED;
595                         *sval = *sval >= sval[1];
596                         break;
597                 case '>':
598                         --sattr;
599                         --sval;
600
601                         if ((*sattr & TDB) != (sattr[1] & TDB))
602                                 error(seg_error);
603
604                         *sattr = ABS | DEFINED;
605                         *sval = *sval > sval[1];
606                         break;
607                 case '<':
608                         --sattr;
609                         --sval;
610
611                         if ((*sattr & TDB) != (sattr[1] & TDB))
612                                 error(seg_error);
613
614                         *sattr = ABS | DEFINED;
615                         *sval = *sval < sval[1];
616                         break;
617                 case NE:
618                         --sattr;
619                         --sval;
620
621                         if ((*sattr & TDB) != (sattr[1] & TDB))
622                                 error(seg_error);
623
624                         *sattr = ABS | DEFINED;
625                         *sval = *sval != sval[1];
626                         break;
627                 case '=':
628                         --sattr;
629                         --sval;
630
631                         if ((*sattr & TDB) != (sattr[1] & TDB))
632                                 error(seg_error);
633
634                         *sattr = ABS | DEFINED;
635                         *sval = *sval == sval[1];
636                         break;
637                 // All other binary operators must have two ABS items
638                 // to work with.  They all produce an ABS value.
639                 default:
640                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
641                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
642                         //error(seg_error);
643                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
644
645                         switch ((int)tk[-1])
646                         {
647                         case '*':
648                                 --sval;
649                                 --sattr;                                        // Pop attrib 
650                                 *sval *= sval[1];
651                                 break;
652                         case '/':
653                                 --sval;
654                                 --sattr;                                        // Pop attrib 
655
656                                 if (sval[1] == 0)
657                                         return error("divide by zero");
658
659                                 *sval /= sval[1];
660                                 break;
661                         case '%':
662                                 --sval;
663                                 --sattr;                                        // Pop attrib 
664
665                                 if (sval[1] == 0)
666                                         return error("mod (%) by zero");
667
668                                 *sval %= sval[1];
669                                 break;
670                         case SHL:
671                                 --sval;
672                                 --sattr;                                        // Pop attrib 
673                                 *sval <<= sval[1];
674                                 break;
675                         case SHR:
676                                 --sval;
677                                 --sattr;                                        // Pop attrib 
678                                 *sval >>= sval[1];
679                                 break;
680                         case '&':
681                                 --sval;
682                                 --sattr;                                        // Pop attrib 
683                                 *sval &= sval[1];
684                                 break;
685                         case '^':
686                                 --sval;
687                                 --sattr;                                        // Pop attrib 
688                                 *sval ^= sval[1];
689                                 break;
690                         case '|':
691                                 --sval;
692                                 --sattr;                                        // Pop attrib 
693                                 *sval |= sval[1];
694                                 break;
695                         default:
696                                 interror(5);                            // Bad operator in expression stream
697                         }
698                 }
699         }
700
701         if (esym != NULL)
702                 *sattr &= ~DEFINED;
703
704         if (a_esym != NULL)
705                 *a_esym = esym;
706
707         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
708         // expressions where absolute values also existed. The absolutes were
709         // overiding the symbol segments and not being included :(
710         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
711
712         *a_attr = *sattr;                                               // Copy value + attrib
713         *a_value = *sval;
714
715         return OK;
716 }