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