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
20 #define DEF_KW // Declare keyword values
21 #include "kwtab.h" // Incl generated keyword tables & defs
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
29 // Token-class initialization list
32 CONST, SYMBOL, 0, // ID
33 '(', '[', '{', 0, // OPAR
34 ')', ']', '}', 0, // CPAR
35 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
38 '!', '~', UNMINUS, 0, // UNARY
39 '*', '/', '%', 0, // MULT
42 LE, GE, '<', '>', NE, '=', 0, // REL
49 const char missym_error[] = "missing symbol";
50 const char str_error[] = "missing symbol or string";
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
57 static symbolNum; // Pointer to the entry in symbolPtr[]
61 // Obtain a string value
63 static VALUE str_value(char * p)
68 v = (v << 8) | (*p & 0xFF);
75 // Initialize expression analyzer
77 void InitExpression(void)
82 // Initialize token-class table (all set to END)
86 for(i=0, p=itokcl; *p!=1; p++)
91 tokenClass[(int)(*p)] = (char)i;
99 // Binary operators (all the same precedence)
108 while (tokenClass[*tok] >= MULT)
115 *evalTokenBuffer++ = t;
123 // Unary operators (detect unary '-')
134 class = tokenClass[*tok];
136 if (*tok == '-' || class == UNARY)
146 *evalTokenBuffer++ = t;
148 else if (class == SUNARY)
153 *evalTokenBuffer++ = CONST;
154 *evalTokenBuffer++ = dos_time();
157 *evalTokenBuffer++ = CONST;
158 *evalTokenBuffer++ = dos_date();
160 case CR_MACDEF: // ^^macdef <macro-name>
161 if (*tok++ != SYMBOL)
162 return error(missym_error);
165 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
166 *evalTokenBuffer++ = CONST;
167 *evalTokenBuffer++ = (TOKEN)w;
175 if (*tok++ != SYMBOL)
176 return error(missym_error);
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;
185 if (*tok != SYMBOL && *tok != STRING)
186 return error(str_error);
192 return error(comma_error);
194 if (*tok != SYMBOL && *tok != STRING)
195 return error(str_error);
200 w = (WORD)(!strcmp(p, p2));
201 *evalTokenBuffer++ = CONST;
202 *evalTokenBuffer++ = (TOKEN)w;
214 // Terminals (CONSTs) and parenthesis grouping
225 *evalTokenBuffer++ = CONST;
226 *evalTokenBuffer++ = *tok++;
230 j = (*p == '.' ? curenv : 0);
231 sy = lookup(p, LABEL, j);
234 sy = NewSymbol(p, LABEL, j);
236 // Check register bank usage
237 if (sy->sattre & EQUATEDREG)
239 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
240 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
242 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
243 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
246 *evalTokenBuffer++ = SYMBOL;
247 *evalTokenBuffer++ = symbolNum;
248 symbolPtr[symbolNum] = sy;
252 *evalTokenBuffer++ = CONST;
253 *evalTokenBuffer++ = str_value(string[*tok++]);
260 return error("missing close parenthesis ')'");
268 return error("missing close parenthesis ']'");
272 *evalTokenBuffer++ = ACONST; // Attributed const
273 *evalTokenBuffer++ = sloc; // Current location
274 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
277 *evalTokenBuffer++ = ACONST; // Attributed const
279 // pcloc == location at start of line
280 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
281 // '*' takes attributes of current section, not ABS!
282 *evalTokenBuffer++ = cursect | DEFINED;
285 return error("bad expression");
293 // Recursive-descent expression analyzer (with some simple speed hacks)
295 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
297 // Passed in values (once derefenced, that is) can all be zero. They are
298 // there so that the expression analyzer can fill them in as needed. The
299 // expression analyzer gets its input from the global token pointer "tok",
300 // and not from anything passed in by the user.
305 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
306 // Also set in various other places too (riscasm.c, e.g.)
308 //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]]);
309 // Optimize for single constant or single symbol.
310 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
311 // followed by the value 101, it will trigger a bad evaluation here.
312 // This is probably a really bad assumption to be making here...!
313 // (assuming tok[1] == EOL is a single token that is)
314 // if ((tok[1] == EOL)
315 if ((tok[1] == EOL && tok[0] != CONST)
316 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
317 && (tokenClass[tok[2]] < UNARY)))
319 if (*tok >= KW_R0 && *tok <= KW_R31)
321 *evalTokenBuffer++ = CONST;
322 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
323 *a_attr = ABS | DEFINED;
330 else if (*tok == CONST)
332 *evalTokenBuffer++ = CONST;
333 *evalTokenBuffer++ = *a_value = tok[1];
334 *a_attr = ABS | DEFINED;
340 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
342 else if (*tok == '*')
344 *evalTokenBuffer++ = CONST;
347 *evalTokenBuffer++ = *a_value = orgaddr;
349 *evalTokenBuffer++ = *a_value = pcloc;
351 // '*' takes attributes of current section, not ABS!
352 *a_attr = cursect | DEFINED;
359 else if (*tok == STRING || *tok == SYMBOL)
362 j = (*p == '.' ? curenv : 0);
363 symbol = lookup(p, LABEL, j);
365 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
367 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
371 symbol = NewSymbol(p, LABEL, j);
373 symbol->sattr |= REFERENCED;
375 // Check for undefined register equates, but only if it's not part
376 // of a #<SYMBOL> construct, as it could be that the label that's
377 // been undefined may later be used as an address label--which
378 // means it will be fixed up later, and thus, not an error.
379 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
381 errors("undefined register equate '%s'", symbol->sname);
382 //if we return right away, it returns some spurious errors...
386 // Check register bank usage
387 if (symbol->sattre & EQUATEDREG)
389 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
390 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
392 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
393 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
396 *evalTokenBuffer++ = SYMBOL;
398 *evalTokenBuffer++ = (TOKEN)symbol;
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).
405 *evalTokenBuffer++ = symbolNum;
406 symbolPtr[symbolNum] = symbol;
410 if (symbol->sattr & DEFINED)
411 *a_value = symbol->svalue;
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?
419 if (symbol->sattre & EQUATEDREG)
422 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
424 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
432 // Unknown type here... Alert the user!,
433 error("undefined RISC register in expression");
434 // Prevent spurious error reporting...
439 *evalTokenBuffer++ = ENDEXPR;
446 *evalTokenBuffer++ = ENDEXPR;
447 return evexpr(otk, a_value, a_attr, a_esym);
452 // Evaluate expression.
453 // If the expression involves only ONE external symbol, the expression is
454 // UNDEFINED, but it's value includes everything but the symbol value, and
455 // `a_esym' is set to the external symbol.
457 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
466 sval = evstk; // (Empty) initial stack
468 esym = NULL; // No external symbol involved
471 while (*tk != ENDEXPR)
476 //printf("evexpr(): SYMBOL\n");
477 sy = symbolPtr[*tk++];
478 sy->sattr |= REFERENCED; // Set "referenced" bit
480 if (!(sy->sattr & DEFINED))
482 // Reference to undefined symbol
483 if (!(sy->sattr & GLOBAL))
490 if (esym != NULL) // Check for multiple externals
491 return error(seg_error);
496 if (sy->sattr & DEFINED)
498 *++sval = sy->svalue; // Push symbol's value
502 *++sval = 0; // 0 for undefined symbols
505 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
506 sym_seg = (WORD)(sy->sattr & TDB);
509 //printf("evexpr(): CONST = %i\n", *tk);
510 *++sval = *tk++; // Push value
511 *++sattr = ABS | DEFINED; // Push simple attribs
514 //printf("evexpr(): ACONST = %i\n", *tk);
515 *++sval = *tk++; // Push value
516 *++sattr = (WORD)*tk++; // Push attribs
519 // Binary "+" and "-" matrix:
522 // ----------------------------
523 // ABS | ABS | Sect | Other |
524 // Sect | Sect | [1] | Error |
525 // Other | Other | Error | [1] |
526 // ----------------------------
531 //printf("evexpr(): +\n");
533 --sattr; // Pop attrib
534 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
535 *sval += sval[1]; // Compute value
536 //printf("%i\n", *sval);
540 else if (sattr[1] & TDB)
541 return error(seg_error);
545 //printf("evexpr(): -\n");
547 --sattr; // Pop attrib
548 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
549 *sval -= sval[1]; // Compute value
550 //printf("%i\n", *sval);
552 attr = (WORD)(*sattr & TDB);
554 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
556 // If symbol1 is ABS, take attributes from symbol2
559 // Otherwise, they're both TDB and so attributes cancel out
560 else if (sattr[1] & TDB)
564 // Unary operators only work on ABS items
566 //printf("evexpr(): UNMINUS\n");
571 *sattr = ABS | DEFINED; // Expr becomes absolute
574 //printf("evexpr(): !\n");
579 *sattr = ABS | DEFINED; // Expr becomes absolute
582 //printf("evexpr(): ~\n");
587 *sattr = ABS | DEFINED; // Expr becomes absolute
589 // Comparison operators must have two values that
590 // are in the same segment, but that's the only requirement.
592 //printf("evexpr(): LE\n");
596 if ((*sattr & TDB) != (sattr[1] & TDB))
599 *sattr = ABS | DEFINED;
600 *sval = *sval <= sval[1];
603 //printf("evexpr(): GE\n");
607 if ((*sattr & TDB) != (sattr[1] & TDB))
610 *sattr = ABS | DEFINED;
611 *sval = *sval >= sval[1];
614 //printf("evexpr(): >\n");
618 if ((*sattr & TDB) != (sattr[1] & TDB))
621 *sattr = ABS | DEFINED;
622 *sval = *sval > sval[1];
625 //printf("evexpr(): <\n");
629 if ((*sattr & TDB) != (sattr[1] & TDB))
632 *sattr = ABS | DEFINED;
633 *sval = *sval < sval[1];
636 //printf("evexpr(): NE\n");
640 if ((*sattr & TDB) != (sattr[1] & TDB))
643 *sattr = ABS | DEFINED;
644 *sval = *sval != sval[1];
647 //printf("evexpr(): =\n");
651 if ((*sattr & TDB) != (sattr[1] & TDB))
654 *sattr = ABS | DEFINED;
655 *sval = *sval == sval[1];
657 // All other binary operators must have two ABS items
658 // to work with. They all produce an ABS value.
660 //printf("evexpr(): default\n");
661 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
662 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
664 *sattr = ABS | DEFINED; // Expr becomes absolute
670 --sattr; // Pop attrib
671 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
673 //printf("%i\n", *sval);
677 --sattr; // Pop attrib
680 return error("divide by zero");
682 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
683 // Compiler is picky here: Without casting these, it discards
684 // the sign if dividing a negative # by a positive one,
685 // creating a bad result. :-/
686 // Probably a side effect of using VALUE intead of ints.
687 *sval = (int)sval[0] / (int)sval[1];
688 //printf("%i\n", *sval);
692 --sattr; // Pop attrib
695 return error("mod (%) by zero");
701 --sattr; // Pop attrib
706 --sattr; // Pop attrib
711 --sattr; // Pop attrib
716 --sattr; // Pop attrib
721 --sattr; // Pop attrib
725 interror(5); // Bad operator in expression stream
736 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
737 // expressions where absolute values also existed. The absolutes were
738 // overiding the symbol segments and not being included :(
739 //*a_attr = *sattr | sym_seg; // Copy value + attrib
741 *a_attr = *sattr; // Copy value + attrib