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