]> Shamusworld >> Repos - rmac/blob - expr.c
Small fix for FU_JR fixups.
[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
166 #if 0
167                         if (lookup(p, MACRO, 0) == NULL)
168                                 w = 0;
169                         else
170                                 w = 1;
171 #else
172                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
173 #endif
174
175                         *tk++ = CONST;
176                         *tk++ = (TOKEN)w;
177                         break;
178                 case CR_DEFINED:
179                         w = DEFINED;
180                         goto getsym;
181                 case CR_REFERENCED:
182                         w = REFERENCED;
183 getsym:
184                         if (*tok++ != SYMBOL)
185                                 return error(missym_error);
186
187 #if 0
188                         p = (char *)*tok++;
189 #else
190                         p = string[*tok++];
191 #endif
192                         j = 0;
193
194                         if (*p == '.')
195                                 j = curenv;
196
197 #if 0
198                         if ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w))
199                                 w = 1;
200                         else
201                                 w = 0;
202 #else
203                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
204 #endif
205
206                         *tk++ = CONST;
207                         *tk++ = (TOKEN)w;
208                         break;
209                 case CR_STREQ:
210                         if (*tok != SYMBOL && *tok != STRING)
211                                 return error(str_error);
212
213 #if 0
214                         p = (char *)tok[1];
215 #else
216                         p = string[tok[1]];
217 #endif
218                         tok +=2;
219
220                         if (*tok++ != ',')
221                                 return error(comma_error);
222
223                         if (*tok != SYMBOL && *tok != STRING)
224                                 return error(str_error);
225
226 #if 0
227                         p2 = (char *)tok[1];
228 #else
229                         p = string[tok[1]];
230 #endif
231                         tok += 2;
232
233                         w = (WORD)(!strcmp(p, p2));
234                         *tk++ = CONST;
235                         *tk++ = (TOKEN)w;
236                         break;
237                 }
238         }
239         else 
240                 return expr2();
241
242         return OK;
243 }
244
245
246 //
247 // Terminals (CONSTs) and parenthesis grouping
248 //
249 int expr2(void)
250 {
251         char * p;
252         SYM * sy;
253         int j;
254
255         switch ((int)*tok++)
256         {
257         case CONST:
258                 *tk++ = CONST;
259                 *tk++ = *tok++;
260                 break;
261         case SYMBOL:
262 #if 0
263                 p = (char *)*tok++;
264 #else
265                 p = string[*tok++];
266 #endif
267                 j = 0;
268
269                 if (*p == '.')
270                         j = curenv;
271
272                 sy = lookup(p, LABEL, j);
273
274                 if (sy == NULL)
275                         sy = NewSymbol(p, LABEL, j);
276
277                 // Check register bank usage
278                 if (sy->sattre & EQUATEDREG)
279                 {
280                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
281                                 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
282
283                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
284                                 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
285                 }
286
287                 *tk++ = SYMBOL;
288 #if 0
289                 *tk++ = (TOKEN)sy;
290 #else
291                 *tk++ = symbolNum;
292                 symbolPtr[symbolNum] = sy;
293                 symbolNum++;
294 #endif
295                 break;
296         case STRING:
297                 *tk++ = CONST;
298 #if 0
299                 *tk++ = str_value((char *)*tok++);
300 #else
301                 *tk++ = str_value(string[*tok++]);
302 #endif
303                 break;
304         case '(':
305                 if (expr0() != OK)
306                         return ERROR;
307
308                 if (*tok++ != ')')
309                         return error("missing close parenthesis ')'");
310
311                 break;
312         case '[':
313                 if (expr0() != OK)
314                         return ERROR;
315
316                 if (*tok++ != ']')
317                         return error("missing close parenthesis ']'");
318
319                 break;
320         case '$':
321                 *tk++ = ACONST;                                    // Attributed const
322                 *tk++ = sloc;                                      // Current location
323                 *tk++ = cursect | DEFINED;                         // Store attribs
324                 break;
325         case '*':
326                 *tk++ = ACONST;                                    // Attributed const
327
328                 if (orgactive)
329                         *tk++ = orgaddr;
330                 else
331                         *tk++ = pcloc;                                  // Location at start of line
332
333                 *tk++ = ABS | DEFINED;                             // Store attribs
334                 break;
335         default:
336                 return error("bad expression");
337         }
338
339         return OK;
340 }
341
342
343 //
344 // Recursive-descent expression analyzer (with some simple speed hacks)
345 //
346 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
347 {
348         SYM * sy;
349         char * p;
350         int j;
351
352         tk = otk;                                                               // Set token pointer to 'exprbuf' (direct.c)
353 //      symbolNum = 0;                                                  // Set symbol number in symbolPtr[] to 0
354
355         // Optimize for single constant or single symbol.
356         if ((tok[1] == EOL)
357                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
358                 && (tokcl[tok[2]] < UNARY)))
359         {
360                 if (*tok >= KW_R0 && *tok <= KW_R31)
361                 {
362                         *tk++ = CONST;
363                         *tk++ = *a_value = (*tok - KW_R0);
364                         *a_attr = ABS | DEFINED;
365
366                         if (a_esym != NULL)
367                                 *a_esym = NULL;
368
369                         tok++;
370                         *tk++ = ENDEXPR;
371                         return OK;
372                 }
373                 else if (*tok == CONST)
374                 {
375                         *tk++ = CONST;
376                         *tk++ = *a_value = tok[1];
377                         *a_attr = ABS | DEFINED;
378
379                         if (a_esym != NULL)
380                                 *a_esym = NULL;
381                 }
382                 else if (*tok == '*')
383                 {
384                         *tk++ = CONST;
385
386                         if (orgactive)
387                                 *tk++ = *a_value = orgaddr;
388                         else
389                                 *tk++ = *a_value = pcloc;
390
391                         *a_attr = ABS | DEFINED;
392                         //*tk++ = 
393
394                         if (a_esym != NULL)
395                                 *a_esym = NULL;
396
397                         tok--;
398                 }
399                 else
400                 {
401 #if 0
402                         p = (char *)tok[1];
403 #else
404                         p = string[tok[1]];
405 #endif
406                         j = 0;
407
408                         if (*p == '.')
409                                 j = curenv;
410
411                         sy = lookup(p, LABEL, j);
412
413                         if (sy == NULL)
414                                 sy = NewSymbol(p, LABEL, j);
415
416                         sy->sattr |= REFERENCED;
417
418                         // Check register bank usage
419                         if (sy->sattre & EQUATEDREG)
420                         {
421                                 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
422                                         warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
423
424                                 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
425                                         warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
426                         }
427
428                         *tk++ = SYMBOL;
429 #if 0
430                         *tk++ = (TOKEN)sy;
431 #else
432                         *tk++ = symbolNum;
433                         symbolPtr[symbolNum] = sy;
434                         symbolNum++;
435 #endif
436
437                         if (sy->sattr & DEFINED)
438                                 *a_value = sy->svalue;
439                         else
440                                 *a_value = 0;
441
442                         if (sy->sattre & EQUATEDREG) 
443                                 *a_value &= 0x1F;
444
445                         *a_attr = (WORD)(sy->sattr & ~GLOBAL);
446
447                         if ((sy->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
448                                 *a_esym = sy;
449                 }
450
451                 tok += 2;
452                 *tk++ = ENDEXPR;
453                 return OK;
454         }
455
456         if (expr0() != OK)
457                 return ERROR;
458
459         *tk++ = ENDEXPR;
460         return evexpr(otk, a_value, a_attr, a_esym);
461 }
462
463
464 //
465 // Evaluate expression.
466 // If the expression involves only ONE external symbol, the expression is
467 // UNDEFINED, but it's value includes everything but the symbol value, and
468 // `a_esym' is set to the external symbol.
469 //
470 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
471 {
472         WORD * sattr;
473         VALUE * sval;
474         WORD attr;
475         SYM * sy;
476         SYM * esym;
477         WORD sym_seg;
478
479         sval = evstk;                                                   // (Empty) initial stack
480         sattr = evattr;
481         esym = NULL;                                                    // No external symbol involved
482         sym_seg = 0;
483
484         while (*tk != ENDEXPR)
485         {
486                 switch ((int)*tk++)
487                 {
488                 case SYMBOL:
489 //                      sy = (SYM *)*tk++;
490                         sy = symbolPtr[*tk++];
491                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
492
493                         if (!(sy->sattr & DEFINED))
494                         {
495                                 // Reference to undefined symbol
496                                 if (!(sy->sattr & GLOBAL))
497                                 {
498                                         *a_attr = 0;
499                                         *a_value = 0;
500                                         return OK;
501                                 }
502
503                                 if (esym != NULL)                       // Check for multiple externals
504                                         return error(seg_error);
505
506                                 esym = sy;
507                         }
508
509                         if (sy->sattr & DEFINED)
510                         {
511                                 *++sval = sy->svalue;           // Push symbol's value
512                         }
513                         else
514                         {
515                                 *++sval = 0;                            // 0 for undefined symbols 
516                         }
517
518                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
519                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
520                         break;
521                 case CONST:
522                         *++sval = *tk++;                                // Push value
523                         *++sattr = ABS | DEFINED;               // Push simple attribs
524                         break;
525                 case ACONST:
526                         *++sval = *tk++;                                // Push value
527                         *++sattr = (WORD)*tk++;                 // Push attribs
528                         break;
529
530                         // Binary "+" and "-" matrix:
531                         // 
532                         //                ABS    Sect     Other
533                         //     ----------------------------
534                         //   ABS     |  ABS   |  Sect  |  Other |
535                         //   Sect    |  Sect  |  [1]   |  Error |
536                         //   Other   |  Other |  Error |  [1]   |
537                         //      ----------------------------
538                         // 
539                         //   [1] + : Error
540                         //       - : ABS
541                 case '+':
542                         --sval;                                                 // Pop value
543                         --sattr;                                                // Pop attrib 
544                         *sval += sval[1];                               // Compute value
545
546                         if (!(*sattr & (TEXT | DATA | BSS)))
547                                 *sattr = sattr[1];
548                         else if (sattr[1] & (TEXT | DATA | BSS))
549                                 return error(seg_error);
550
551                         break;
552                 case '-':
553                         --sval;                                                 // Pop value
554                         --sattr;                                                // Pop attrib 
555                         *sval -= sval[1];                               // Compute value
556
557                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
558
559                         if (!attr)
560                                 *sattr = sattr[1];
561                         else if (sattr[1] & (TEXT | DATA | BSS))
562                         {
563                                 if (!(attr & sattr[1]))
564                                         return error(seg_error);
565                                 else
566                                         *sattr &= ~(TEXT | DATA | BSS);
567                         }
568
569                         break;
570                 // Unary operators only work on ABS items
571                 case UNMINUS:
572                         if (*sattr & (TEXT | DATA | BSS))
573                                 error(seg_error);
574
575                         *sval = -(int)*sval;
576                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
577                         break;
578                 case '!':
579                         if (*sattr & (TEXT | DATA | BSS))
580                                 error(seg_error);
581
582                         *sval = !*sval;
583                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
584                         break;
585                 case '~':
586                         if (*sattr & (TEXT | DATA | BSS))
587                                 error(seg_error);
588
589                         *sval = ~*sval;
590                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
591                         break;
592                 // Comparison operators must have two values that
593                 // are in the same segment, but that's the only requirement.
594                 case LE:
595                         --sattr;
596                         --sval;
597
598                         if ((*sattr & TDB) != (sattr[1] & TDB))
599                                 error(seg_error);
600
601                         *sattr = ABS | DEFINED;
602                         *sval = *sval <= sval[1];
603                         break;
604                 case GE:
605                         --sattr;
606                         --sval;
607
608                         if ((*sattr & TDB) != (sattr[1] & TDB))
609                                 error(seg_error);
610
611                         *sattr = ABS | DEFINED;
612                         *sval = *sval >= sval[1];
613                         break;
614                 case '>':
615                         --sattr;
616                         --sval;
617
618                         if ((*sattr & TDB) != (sattr[1] & TDB))
619                                 error(seg_error);
620
621                         *sattr = ABS | DEFINED;
622                         *sval = *sval > sval[1];
623                         break;
624                 case '<':
625                         --sattr;
626                         --sval;
627
628                         if ((*sattr & TDB) != (sattr[1] & TDB))
629                                 error(seg_error);
630
631                         *sattr = ABS | DEFINED;
632                         *sval = *sval < sval[1];
633                         break;
634                 case NE:
635                         --sattr;
636                         --sval;
637
638                         if ((*sattr & TDB) != (sattr[1] & TDB))
639                                 error(seg_error);
640
641                         *sattr = ABS | DEFINED;
642                         *sval = *sval != sval[1];
643                         break;
644                 case '=':
645                         --sattr;
646                         --sval;
647
648                         if ((*sattr & TDB) != (sattr[1] & TDB))
649                                 error(seg_error);
650
651                         *sattr = ABS | DEFINED;
652                         *sval = *sval == sval[1];
653                         break;
654                 // All other binary operators must have two ABS items
655                 // to work with.  They all produce an ABS value.
656                 default:
657                         // GH - Removed for v1.0.15 as part of the fix for indexed loads.
658                         //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
659                         //error(seg_error);
660                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
661
662                         switch ((int)tk[-1])
663                         {
664                         case '*':
665                                 --sval;
666                                 --sattr;                                        // Pop attrib 
667                                 *sval *= sval[1];
668                                 break;
669                         case '/':
670                                 --sval;
671                                 --sattr;                                        // Pop attrib 
672
673                                 if (sval[1] == 0)
674                                         return error("divide by zero");
675
676                                 *sval /= sval[1];
677                                 break;
678                         case '%':
679                                 --sval;
680                                 --sattr;                                        // Pop attrib 
681
682                                 if (sval[1] == 0)
683                                         return error("mod (%) by zero");
684
685                                 *sval %= sval[1];
686                                 break;
687                         case SHL:
688                                 --sval;
689                                 --sattr;                                        // Pop attrib 
690                                 *sval <<= sval[1];
691                                 break;
692                         case SHR:
693                                 --sval;
694                                 --sattr;                                        // Pop attrib 
695                                 *sval >>= sval[1];
696                                 break;
697                         case '&':
698                                 --sval;
699                                 --sattr;                                        // Pop attrib 
700                                 *sval &= sval[1];
701                                 break;
702                         case '^':
703                                 --sval;
704                                 --sattr;                                        // Pop attrib 
705                                 *sval ^= sval[1];
706                                 break;
707                         case '|':
708                                 --sval;
709                                 --sattr;                                        // Pop attrib 
710                                 *sval |= sval[1];
711                                 break;
712                         default:
713                                 interror(5);                            // Bad operator in expression stream
714                         }
715                 }
716         }
717
718         if (esym != NULL)
719                 *sattr &= ~DEFINED;
720
721         if (a_esym != NULL)
722                 *a_esym = esym;
723
724         // sym_seg added in 1.0.16 to solve a problem with forward symbols in
725         // expressions where absolute values also existed. The absolutes were
726         // overiding the symbol segments and not being included :(
727         //*a_attr = *sattr | sym_seg;                                        // Copy value + attrib
728
729         *a_attr = *sattr;                                               // Copy value + attrib
730         *a_value = *sval;
731
732         return OK;
733 }