]> Shamusworld >> Repos - rmac/blob - expr.c
Fixed word reversed fixup problem.
[rmac] / expr.c
1 //
2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source Utilised with the Kind Permission of Landon Dyer
7 //
8
9 #include "expr.h"
10 #include "direct.h"
11 #include "error.h"
12 #include "listing.h"
13 #include "mach.h"
14 #include "procln.h"
15 #include "riscasm.h"
16 #include "sect.h"
17 #include "symbol.h"
18 #include "token.h"
19
20 #define DEF_KW                                                  // Declare keyword values 
21 #include "kwtab.h"                                              // Incl generated keyword tables & defs
22
23 static char tokenClass[128];                    // Generated table of token classes
24 static VALUE evstk[EVSTACKSIZE];                // Evaluator value stack
25 static WORD evattr[EVSTACKSIZE];                // Evaluator attribute stack
26
27 // Token-class initialization list
28 char itokcl[] = {
29         0,                                                                      // END
30         CONST, SYMBOL, 0,                                       // ID 
31         '(', '[', '{', 0,                                       // OPAR
32         ')', ']', '}', 0,                                       // CPAR 
33         CR_DEFINED, CR_REFERENCED,                      // SUNARY (special unary)
34         CR_STREQ, CR_MACDEF,
35         CR_DATE, CR_TIME, 0,
36         '!', '~', UNMINUS, 0,                           // UNARY
37         '*', '/', '%', 0,                                       // MULT 
38         '+', '-', 0,                                            // ADD 
39         SHL, SHR, 0,                                            // SHIFT 
40         LE, GE, '<', '>', NE, '=', 0,           // REL 
41         '&', 0,                                                         // AND 
42         '^', 0,                                                         // XOR 
43         '|', 0,                                                         // OR 
44         1                                                                       // (the end) 
45 };
46
47 const char missym_error[] = "missing symbol";
48 const char str_error[] = "missing symbol or string";
49
50 // Convert expression to postfix
51 static TOKEN * evalTokenBuffer;                 // Deposit tokens here (this is really a
52                                                                                 // pointer to exprbuf from direct.c)
53                                                                                 // (Can also be from others, like riscasm.c)
54 static symbolNum;                                               // Pointer to the entry in symbolPtr[]
55
56
57 //
58 // Obtain a String Value
59 //
60 static VALUE str_value(char * p)
61 {
62         VALUE v;
63
64         for(v=0; *p; p++)
65                 v = (v << 8) | (*p & 0xFF);
66
67         return v;
68 }
69
70
71 //
72 // Initialize Expression Analyzer
73 //
74 void InitExpression(void)
75 {
76         int i;                                                                  // Iterator
77         char * p;                                                               // Token pointer
78
79         // Initialize token-class table (all set to END)
80         for(i=0; i<128; i++)
81                 tokenClass[i] = END;
82
83         for(i=0, p=itokcl; *p!=1; p++)
84         {
85                 if (*p == 0)
86                         i++;
87                 else 
88                         tokenClass[(int)(*p)] = (char)i;
89         }
90
91         symbolNum = 0;
92 }
93
94
95 //
96 // Binary operators (all the same precedence)
97 //
98 int expr0(void)
99 {
100         TOKEN t;
101
102         if (expr1() != OK)
103                 return ERROR;
104         
105         while (tokenClass[*tok] >= MULT)
106         {
107                 t = *tok++;
108
109                 if (expr1() != OK)
110                         return ERROR;
111
112                 *evalTokenBuffer++ = t;
113         }
114
115         return OK;
116 }
117
118
119 //
120 // Unary operators (detect unary '-')
121 //
122 int expr1(void)
123 {
124         int class;
125         TOKEN t;
126         SYM * sy;
127         char * p, * p2;
128         WORD w;
129         int j;
130
131         class = tokenClass[*tok];
132
133         if (*tok == '-' || class == UNARY)
134         {
135                 t = *tok++;
136
137                 if (expr2() != OK)
138                         return ERROR;
139
140                 if (t == '-')
141                         t = UNMINUS;
142
143                 *evalTokenBuffer++ = t;
144         }
145         else if (class == SUNARY)
146         {
147                 switch ((int)*tok++)
148                 {
149                 case CR_TIME:
150                         *evalTokenBuffer++ = CONST;
151                         *evalTokenBuffer++ = dos_time();
152                         break;
153                 case CR_DATE:
154                         *evalTokenBuffer++ = CONST;
155                         *evalTokenBuffer++ = dos_date();
156                         break;
157                 case CR_MACDEF:                                    // ^^macdef <macro-name>
158                         if (*tok++ != SYMBOL)
159                                 return error(missym_error);
160
161                         p = string[*tok++];
162                         w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
163                         *evalTokenBuffer++ = CONST;
164                         *evalTokenBuffer++ = (TOKEN)w;
165                         break;
166                 case CR_DEFINED:
167                         w = DEFINED;
168                         goto getsym;
169                 case CR_REFERENCED:
170                         w = REFERENCED;
171 getsym:
172                         if (*tok++ != SYMBOL)
173                                 return error(missym_error);
174
175                         p = string[*tok++];
176                         j = (*p == '.' ? curenv : 0);
177                         w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
178                         *evalTokenBuffer++ = CONST;
179                         *evalTokenBuffer++ = (TOKEN)w;
180                         break;
181                 case CR_STREQ:
182                         if (*tok != SYMBOL && *tok != STRING)
183                                 return error(str_error);
184
185                         p = string[tok[1]];
186                         tok +=2;
187
188                         if (*tok++ != ',')
189                                 return error(comma_error);
190
191                         if (*tok != SYMBOL && *tok != STRING)
192                                 return error(str_error);
193
194                         p = string[tok[1]];
195                         tok += 2;
196
197                         w = (WORD)(!strcmp(p, p2));
198                         *evalTokenBuffer++ = CONST;
199                         *evalTokenBuffer++ = (TOKEN)w;
200                         break;
201                 }
202         }
203         else 
204                 return expr2();
205
206         return OK;
207 }
208
209
210 //
211 // Terminals (CONSTs) and parenthesis grouping
212 //
213 int expr2(void)
214 {
215         char * p;
216         SYM * sy;
217         int j;
218
219         switch ((int)*tok++)
220         {
221         case CONST:
222                 *evalTokenBuffer++ = CONST;
223                 *evalTokenBuffer++ = *tok++;
224                 break;
225         case SYMBOL:
226                 p = string[*tok++];
227                 j = (*p == '.' ? curenv : 0);
228                 sy = lookup(p, LABEL, j);
229
230                 if (sy == NULL)
231                         sy = NewSymbol(p, LABEL, j);
232
233                 // Check register bank usage
234                 if (sy->sattre & EQUATEDREG)
235                 {
236                         if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)   
237                                 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
238
239                         if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
240                                 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
241                 }
242
243                 *evalTokenBuffer++ = SYMBOL;
244                 *evalTokenBuffer++ = symbolNum;
245                 symbolPtr[symbolNum] = sy;
246                 symbolNum++;
247                 break;
248         case STRING:
249                 *evalTokenBuffer++ = CONST;
250                 *evalTokenBuffer++ = str_value(string[*tok++]);
251                 break;
252         case '(':
253                 if (expr0() != OK)
254                         return ERROR;
255
256                 if (*tok++ != ')')
257                         return error("missing close parenthesis ')'");
258
259                 break;
260         case '[':
261                 if (expr0() != OK)
262                         return ERROR;
263
264                 if (*tok++ != ']')
265                         return error("missing close parenthesis ']'");
266
267                 break;
268         case '$':
269                 *evalTokenBuffer++ = ACONST;                            // Attributed const
270                 *evalTokenBuffer++ = sloc;                                      // Current location
271                 *evalTokenBuffer++ = cursect | DEFINED;         // Store attribs
272                 break;
273         case '*':
274                 *evalTokenBuffer++ = ACONST;                            // Attributed const
275
276 #if 0
277                 if (orgactive)
278                         *evalTokenBuffer++ = orgaddr;
279                 else
280                         *evalTokenBuffer++ = pcloc;                             // Location at start of line
281 #else
282                 // pcloc == location at start of line
283                 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
284 #endif
285
286                 *evalTokenBuffer++ = ABS | DEFINED;                     // Store attribs
287                 break;
288         default:
289                 return error("bad expression");
290         }
291
292         return OK;
293 }
294
295
296 //
297 // Recursive-descent expression analyzer (with some simple speed hacks)
298 //
299 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
300 {
301         // Passed in values (once derefenced, that is) can all be zero. They are
302         // there so that the expression analyzer can fill them in as needed. The
303         // expression analyzer gets its input from the global token pointer "tok",
304         // and not from anything passed in by the user.
305         SYM * symbol;
306         char * p;
307         int j;
308
309         evalTokenBuffer = otk;  // Set token pointer to 'exprbuf' (direct.c)
310                                                         // Also set in various other places too (riscasm.c, e.g.)
311
312 //printf("expr(): tokens 0-2: %i %i %i (%c %c %c); tc[2] = %i\n", tok[0], tok[1], tok[2], tok[0], tok[1], tok[2], tokenClass[tok[2]]);
313         // Optimize for single constant or single symbol.
314         // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
315         //         followed by the value 101, it will trigger a bad evaluation here.
316         //         This is probably a really bad assumption to be making here...!
317         //         (assuming tok[1] == EOL is a single token that is)
318 //      if ((tok[1] == EOL)
319         if ((tok[1] == EOL && tok[0] != CONST)
320                 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
321                 && (tokenClass[tok[2]] < UNARY)))
322         {
323                 if (*tok >= KW_R0 && *tok <= KW_R31)
324                 {
325                         *evalTokenBuffer++ = CONST;
326                         *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
327                         *a_attr = ABS | DEFINED;
328
329                         if (a_esym != NULL)
330                                 *a_esym = NULL;
331
332                         tok++;
333                 }
334                 else if (*tok == CONST)
335                 {
336                         *evalTokenBuffer++ = CONST;
337                         *evalTokenBuffer++ = *a_value = tok[1];
338                         *a_attr = ABS | DEFINED;
339
340                         if (a_esym != NULL)
341                                 *a_esym = NULL;
342
343                         tok += 2;
344 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
345                 }
346                 else if (*tok == '*')
347                 {
348                         *evalTokenBuffer++ = CONST;
349
350                         if (orgactive)
351                                 *evalTokenBuffer++ = *a_value = orgaddr;
352                         else
353                                 *evalTokenBuffer++ = *a_value = pcloc;
354
355                         *a_attr = ABS | DEFINED;
356
357                         if (a_esym != NULL)
358                                 *a_esym = NULL;
359
360                         tok++;
361                 }
362                 else if (*tok == STRING || *tok == SYMBOL)
363                 {
364                         p = string[tok[1]];
365                         j = (*p == '.' ? curenv : 0);
366                         symbol = lookup(p, LABEL, j);
367 #if 0
368 printf("eval: Looking up symbol [=%08X]\n", symbol);
369 if (symbol)
370         printf("      attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
371 #endif
372
373                         if (symbol == NULL)
374                                 symbol = NewSymbol(p, LABEL, j);
375
376                         symbol->sattr |= REFERENCED;
377
378                         // Check for undefined register equates
379                         if (symbol->sattre & UNDEF_EQUR)
380                         {
381                                 errors("undefined register equate '%s'", symbol->sname);
382 //if we return right away, it returns some spurious errors...
383 //                              return ERROR;
384                         }
385
386                         // Check register bank usage
387                         if (symbol->sattre & EQUATEDREG)
388                         {
389                                 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)   
390                                         warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
391
392                                 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
393                                         warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
394                         }
395
396                         *evalTokenBuffer++ = SYMBOL;
397 #if 0
398                         *evalTokenBuffer++ = (TOKEN)symbol;
399 #else
400 /*
401 While this approach works, it's wasteful. It would be better to use something
402 that's already available, like the symbol "order defined" table (which needs to
403 be converted from a linked list into an array).
404 */
405                         *evalTokenBuffer++ = symbolNum;
406                         symbolPtr[symbolNum] = symbol;
407                         symbolNum++;
408 #endif
409
410                         if (symbol->sattr & DEFINED)
411                                 *a_value = symbol->svalue;
412                         else
413                                 *a_value = 0;
414
415 /*
416 All that extra crap that was put into the svalue when doing the equr stuff is
417 thrown away right here. What the hell is it for?
418 */
419                         if (symbol->sattre & EQUATEDREG) 
420                                 *a_value &= 0x1F;
421
422                         *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
423
424                         if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
425                                 *a_esym = symbol;
426
427                         tok += 2;
428                 }
429                 else
430                 {
431                         // Unknown type here... Alert the user!
432                         error("undefined RISC register in expression");
433                         // Prevent spurious error reporting...
434                         tok++;
435                         return ERROR;
436                 }
437
438                 *evalTokenBuffer++ = ENDEXPR;
439                 return OK;
440         }
441
442         if (expr0() != OK)
443                 return ERROR;
444
445         *evalTokenBuffer++ = ENDEXPR;
446         return evexpr(otk, a_value, a_attr, a_esym);
447 }
448
449
450 //
451 // Evaluate expression.
452 // If the expression involves only ONE external symbol, the expression is
453 // UNDEFINED, but it's value includes everything but the symbol value, and
454 // `a_esym' is set to the external symbol.
455 //
456 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
457 {
458         WORD * sattr;
459         VALUE * sval;
460         WORD attr;
461         SYM * sy;
462         SYM * esym;
463         WORD sym_seg;
464
465         sval = evstk;                                                   // (Empty) initial stack
466         sattr = evattr;
467         esym = NULL;                                                    // No external symbol involved
468         sym_seg = 0;
469
470         while (*tk != ENDEXPR)
471         {
472                 switch ((int)*tk++)
473                 {
474                 case SYMBOL:
475 //printf("evexpr(): SYMBOL\n");
476                         sy = symbolPtr[*tk++];
477                         sy->sattr |= REFERENCED;                // Set "referenced" bit 
478
479                         if (!(sy->sattr & DEFINED))
480                         {
481                                 // Reference to undefined symbol
482                                 if (!(sy->sattr & GLOBAL))
483                                 {
484                                         *a_attr = 0;
485                                         *a_value = 0;
486                                         return OK;
487                                 }
488
489                                 if (esym != NULL)                       // Check for multiple externals
490                                         return error(seg_error);
491
492                                 esym = sy;
493                         }
494
495                         if (sy->sattr & DEFINED)
496                         {
497                                 *++sval = sy->svalue;           // Push symbol's value
498                         }
499                         else
500                         {
501                                 *++sval = 0;                            // 0 for undefined symbols 
502                         }
503
504                         *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
505                         sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
506                         break;
507                 case CONST:
508 //printf("evexpr(): CONST = %i\n", *tk);
509                         *++sval = *tk++;                                // Push value
510                         *++sattr = ABS | DEFINED;               // Push simple attribs
511                         break;
512                 case ACONST:
513 //printf("evexpr(): ACONST = %i\n", *tk);
514                         *++sval = *tk++;                                // Push value
515                         *++sattr = (WORD)*tk++;                 // Push attribs
516                         break;
517
518                         // Binary "+" and "-" matrix:
519                         // 
520                         //                ABS    Sect     Other
521                         //     ----------------------------
522                         //   ABS     |  ABS   |  Sect  |  Other |
523                         //   Sect    |  Sect  |  [1]   |  Error |
524                         //   Other   |  Other |  Error |  [1]   |
525                         //      ----------------------------
526                         // 
527                         //   [1] + : Error
528                         //       - : ABS
529                 case '+':
530 //printf("evexpr(): +\n");
531                         --sval;                                                 // Pop value
532                         --sattr;                                                // Pop attrib 
533                         *sval += sval[1];                               // Compute value
534
535                         if (!(*sattr & (TEXT | DATA | BSS)))
536                                 *sattr = sattr[1];
537                         else if (sattr[1] & (TEXT | DATA | BSS))
538                                 return error(seg_error);
539
540                         break;
541                 case '-':
542 //printf("evexpr(): -\n");
543                         --sval;                                                 // Pop value
544                         --sattr;                                                // Pop attrib 
545                         *sval -= sval[1];                               // Compute value
546
547                         attr = (WORD)(*sattr & (TEXT | DATA | BSS));
548
549                         if (!attr)
550                                 *sattr = sattr[1];
551                         else if (sattr[1] & (TEXT | DATA | BSS))
552                         {
553                                 if (!(attr & sattr[1]))
554                                         return error(seg_error);
555                                 else
556                                         *sattr &= ~(TEXT | DATA | BSS);
557                         }
558
559                         break;
560                 // Unary operators only work on ABS items
561                 case UNMINUS:
562 //printf("evexpr(): UNMINUS\n");
563                         if (*sattr & (TEXT | DATA | BSS))
564                                 error(seg_error);
565
566                         *sval = -(int)*sval;
567                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
568                         break;
569                 case '!':
570 //printf("evexpr(): !\n");
571                         if (*sattr & (TEXT | DATA | BSS))
572                                 error(seg_error);
573
574                         *sval = !*sval;
575                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
576                         break;
577                 case '~':
578 //printf("evexpr(): ~\n");
579                         if (*sattr & (TEXT | DATA | BSS))
580                                 error(seg_error);
581
582                         *sval = ~*sval;
583                         *sattr = ABS | DEFINED;                 // Expr becomes absolute
584                         break;
585                 // Comparison operators must have two values that
586                 // are in the same segment, but that's the only requirement.
587                 case LE:
588 //printf("evexpr(): LE\n");
589                         --sattr;
590                         --sval;
591
592                         if ((*sattr & TDB) != (sattr[1] & TDB))
593                                 error(seg_error);
594
595                         *sattr = ABS | DEFINED;
596                         *sval = *sval <= sval[1];
597                         break;
598                 case GE:
599 //printf("evexpr(): GE\n");
600                         --sattr;
601                         --sval;
602
603                         if ((*sattr & TDB) != (sattr[1] & TDB))
604                                 error(seg_error);
605
606                         *sattr = ABS | DEFINED;
607                         *sval = *sval >= sval[1];
608                         break;
609                 case '>':
610 //printf("evexpr(): >\n");
611                         --sattr;
612                         --sval;
613
614                         if ((*sattr & TDB) != (sattr[1] & TDB))
615                                 error(seg_error);
616
617                         *sattr = ABS | DEFINED;
618                         *sval = *sval > sval[1];
619                         break;
620                 case '<':
621 //printf("evexpr(): <\n");
622                         --sattr;
623                         --sval;
624
625                         if ((*sattr & TDB) != (sattr[1] & TDB))
626                                 error(seg_error);
627
628                         *sattr = ABS | DEFINED;
629                         *sval = *sval < sval[1];
630                         break;
631                 case NE:
632 //printf("evexpr(): NE\n");
633                         --sattr;
634                         --sval;
635
636                         if ((*sattr & TDB) != (sattr[1] & TDB))
637                                 error(seg_error);
638
639                         *sattr = ABS | DEFINED;
640                         *sval = *sval != sval[1];
641                         break;
642                 case '=':
643 //printf("evexpr(): =\n");
644                         --sattr;
645                         --sval;
646
647                         if ((*sattr & TDB) != (sattr[1] & TDB))
648                                 error(seg_error);
649
650                         *sattr = ABS | DEFINED;
651                         *sval = *sval == sval[1];
652                         break;
653                 // All other binary operators must have two ABS items
654                 // to work with.  They all produce an ABS value.
655                 default:
656 //printf("evexpr(): default\n");
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 }