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 // Seems that even other tokens (SUNARY type) can fuck this up too.
315 // if ((tok[1] == EOL)
316 if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
317 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
318 && (tokenClass[tok[2]] < UNARY)))
320 if (*tok >= KW_R0 && *tok <= KW_R31)
322 *evalTokenBuffer++ = CONST;
323 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
324 *a_attr = ABS | DEFINED;
331 else if (*tok == CONST)
333 *evalTokenBuffer++ = CONST;
334 *evalTokenBuffer++ = *a_value = tok[1];
335 *a_attr = ABS | DEFINED;
341 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
343 else if (*tok == '*')
345 *evalTokenBuffer++ = CONST;
348 *evalTokenBuffer++ = *a_value = orgaddr;
350 *evalTokenBuffer++ = *a_value = pcloc;
352 // '*' takes attributes of current section, not ABS!
353 *a_attr = cursect | DEFINED;
360 else if (*tok == STRING || *tok == SYMBOL)
363 j = (*p == '.' ? curenv : 0);
364 symbol = lookup(p, LABEL, j);
366 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
368 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
372 symbol = NewSymbol(p, LABEL, j);
374 symbol->sattr |= REFERENCED;
376 // Check for undefined register equates, but only if it's not part
377 // of a #<SYMBOL> construct, as it could be that the label that's
378 // been undefined may later be used as an address label--which
379 // means it will be fixed up later, and thus, not an error.
380 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
382 errors("undefined register equate '%s'", symbol->sname);
383 //if we return right away, it returns some spurious errors...
387 // Check register bank usage
388 if (symbol->sattre & EQUATEDREG)
390 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
391 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
393 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
394 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
397 *evalTokenBuffer++ = SYMBOL;
399 *evalTokenBuffer++ = (TOKEN)symbol;
402 While this approach works, it's wasteful. It would be better to use something
403 that's already available, like the symbol "order defined" table (which needs to
404 be converted from a linked list into an array).
406 *evalTokenBuffer++ = symbolNum;
407 symbolPtr[symbolNum] = symbol;
411 if (symbol->sattr & DEFINED)
412 *a_value = symbol->svalue;
417 All that extra crap that was put into the svalue when doing the equr stuff is
418 thrown away right here. What the hell is it for?
420 if (symbol->sattre & EQUATEDREG)
423 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
425 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
433 // Unknown type here... Alert the user!,
434 error("undefined RISC register in expression");
435 // Prevent spurious error reporting...
440 *evalTokenBuffer++ = ENDEXPR;
447 *evalTokenBuffer++ = ENDEXPR;
448 return evexpr(otk, a_value, a_attr, a_esym);
453 // Evaluate expression.
454 // If the expression involves only ONE external symbol, the expression is
455 // UNDEFINED, but it's value includes everything but the symbol value, and
456 // `a_esym' is set to the external symbol.
458 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
467 sval = evstk; // (Empty) initial stack
469 esym = NULL; // No external symbol involved
472 while (*tk != ENDEXPR)
477 //printf("evexpr(): SYMBOL\n");
478 sy = symbolPtr[*tk++];
479 sy->sattr |= REFERENCED; // Set "referenced" bit
481 if (!(sy->sattr & DEFINED))
483 // Reference to undefined symbol
484 if (!(sy->sattr & GLOBAL))
491 if (esym != NULL) // Check for multiple externals
492 return error(seg_error);
497 if (sy->sattr & DEFINED)
499 *++sval = sy->svalue; // Push symbol's value
503 *++sval = 0; // 0 for undefined symbols
506 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
507 sym_seg = (WORD)(sy->sattr & TDB);
510 //printf("evexpr(): CONST = %i\n", *tk);
511 *++sval = *tk++; // Push value
512 *++sattr = ABS | DEFINED; // Push simple attribs
515 //printf("evexpr(): ACONST = %i\n", *tk);
516 *++sval = *tk++; // Push value
517 *++sattr = (WORD)*tk++; // Push attribs
520 // Binary "+" and "-" matrix:
523 // ----------------------------
524 // ABS | ABS | Sect | Other |
525 // Sect | Sect | [1] | Error |
526 // Other | Other | Error | [1] |
527 // ----------------------------
532 //printf("evexpr(): +\n");
534 --sattr; // Pop attrib
535 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
536 *sval += sval[1]; // Compute value
537 //printf("%i\n", *sval);
541 else if (sattr[1] & TDB)
542 return error(seg_error);
546 //printf("evexpr(): -\n");
548 --sattr; // Pop attrib
549 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
550 *sval -= sval[1]; // Compute value
551 //printf("%i\n", *sval);
553 attr = (WORD)(*sattr & TDB);
555 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
557 // If symbol1 is ABS, take attributes from symbol2
560 // Otherwise, they're both TDB and so attributes cancel out
561 else if (sattr[1] & TDB)
565 // Unary operators only work on ABS items
567 //printf("evexpr(): UNMINUS\n");
572 *sattr = ABS | DEFINED; // Expr becomes absolute
575 //printf("evexpr(): !\n");
580 *sattr = ABS | DEFINED; // Expr becomes absolute
583 //printf("evexpr(): ~\n");
588 *sattr = ABS | DEFINED; // Expr becomes absolute
590 // Comparison operators must have two values that
591 // are in the same segment, but that's the only requirement.
593 //printf("evexpr(): LE\n");
597 if ((*sattr & TDB) != (sattr[1] & TDB))
600 *sattr = ABS | DEFINED;
601 *sval = *sval <= sval[1];
604 //printf("evexpr(): GE\n");
608 if ((*sattr & TDB) != (sattr[1] & TDB))
611 *sattr = ABS | DEFINED;
612 *sval = *sval >= sval[1];
615 //printf("evexpr(): >\n");
619 if ((*sattr & TDB) != (sattr[1] & TDB))
622 *sattr = ABS | DEFINED;
623 *sval = *sval > sval[1];
626 //printf("evexpr(): <\n");
630 if ((*sattr & TDB) != (sattr[1] & TDB))
633 *sattr = ABS | DEFINED;
634 *sval = *sval < sval[1];
637 //printf("evexpr(): NE\n");
641 if ((*sattr & TDB) != (sattr[1] & TDB))
644 *sattr = ABS | DEFINED;
645 *sval = *sval != sval[1];
648 //printf("evexpr(): =\n");
652 if ((*sattr & TDB) != (sattr[1] & TDB))
655 *sattr = ABS | DEFINED;
656 *sval = *sval == sval[1];
658 // All other binary operators must have two ABS items
659 // to work with. They all produce an ABS value.
661 //printf("evexpr(): default\n");
662 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
663 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
665 *sattr = ABS | DEFINED; // Expr becomes absolute
671 --sattr; // Pop attrib
672 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
674 //printf("%i\n", *sval);
678 --sattr; // Pop attrib
681 return error("divide by zero");
683 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
684 // Compiler is picky here: Without casting these, it discards
685 // the sign if dividing a negative # by a positive one,
686 // creating a bad result. :-/
687 // Probably a side effect of using VALUE intead of ints.
688 *sval = (int)sval[0] / (int)sval[1];
689 //printf("%i\n", *sval);
693 --sattr; // Pop attrib
696 return error("mod (%) by zero");
702 --sattr; // Pop attrib
707 --sattr; // Pop attrib
712 --sattr; // Pop attrib
717 --sattr; // Pop attrib
722 --sattr; // Pop attrib
726 interror(5); // Bad operator in expression stream
737 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
738 // expressions where absolute values also existed. The absolutes were
739 // overiding the symbol segments and not being included :(
740 //*a_attr = *sattr | sym_seg; // Copy value + attrib
742 *a_attr = *sattr; // Copy value + attrib