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
19 #define DEF_KW // Declare keyword values
20 #include "kwtab.h" // Incl generated keyword tables & defs
22 static char tokcl[128]; // Generated table of token classes
23 static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
24 static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
26 // Token-class initialization list
29 CONST, SYMBOL, 0, // ID
30 '(', '[', '{', 0, // OPAR
31 ')', ']', '}', 0, // CPAR
32 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
35 '!', '~', UNMINUS, 0, // UNARY
36 '*', '/', '%', 0, // MULT
39 LE, GE, '<', '>', NE, '=', 0, // REL
46 char missym_error[] = "missing symbol";
47 char *str_error = "missing symbol or string";
49 // Convert expression to postfix
50 static TOKEN *tk; // Deposit tokens here
55 // --- Obtain a String Value -----------------------------------------------------------------------
58 static VALUE str_value(char *p) {
62 v = (v << 8) | (*p & 0xff);
67 // --- Initialize Expression Analyzer --------------------------------------------------------------
70 void init_expr(void) {
72 char *p; // Token pointer
74 // Initialize token-class table
75 for(i = 0; i < 128; ++i) // Mark all entries END
78 for(i = 0, p = itokcl; *p != 1; ++p)
82 tokcl[(int)(*p)] = (char)i;
86 // --- Binary operators (all the same precedence) --------------------------------------------------
94 while(tokcl[*tok] >= MULT) {
104 // --- Unary operators (detect unary '-') ----------------------------------------------------------
117 if(*tok == '-' || class == UNARY) {
124 } else if(class == SUNARY)
125 switch((int)*tok++) {
134 case CR_MACDEF: // ^^macdef <macro-name>
135 if(*tok++ != SYMBOL) return(error(missym_error));
137 if(lookup(p, MACRO, 0) == NULL) w = 0;
151 if(*tok++ != SYMBOL) return(error(missym_error));
154 if(*p == '.') j = curenv;
155 if((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w)) w = 1;
162 if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
166 if(*tok++ != ',') return(error(comma_error));
168 if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
172 w = (WORD)(!strcmp(p, p2));
184 // --- Terminals (CONSTs) and parenthesis grouping -------------------------------------------------
192 switch((int)*tok++) {
202 sy = lookup(p, LABEL, j);
204 sy = newsym(p, LABEL, j);
206 if(sy->sattre & EQUATEDREG) { // Check register bank usage
207 if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
208 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
209 if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
210 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
218 *tk++ = str_value((char *)*tok++);
224 return(error("missing close parenthesis ')'"));
230 return(error("missing close parenthesis ']'"));
233 *tk++ = ACONST; // Attributed const
234 *tk++ = sloc; // Current location
235 *tk++ = cursect | DEFINED; // Store attribs
238 *tk++ = ACONST; // Attributed const
242 *tk++ = pcloc; // Location at start of line
243 *tk++ = ABS | DEFINED; // Store attribs
246 return(error("bad expression"));
252 // --- Recursive-descent expression analyzer (with some simple speed hacks) ------------------------
255 int expr(TOKEN *otk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
262 // Optimize for single constant or single symbol.
263 if((tok[1] == EOL) ||
264 (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31)) &&
265 (tokcl[tok[2]] < UNARY))) {
267 if(*tok >= KW_R0 && *tok <= KW_R31) {
269 *tk++ = *a_value = (*tok - KW_R0);
270 *a_attr = ABS | DEFINED;
276 } else if(*tok == CONST) {
278 *tk++ = *a_value = tok[1];
279 *a_attr = ABS | DEFINED;
282 } else if(*tok == '*') {
285 *tk++ = *a_value = orgaddr;
287 *tk++ = *a_value = pcloc;
288 *a_attr = ABS | DEFINED;
298 sy = lookup(p, LABEL, j);
301 sy = newsym(p, LABEL, j);
302 sy->sattr |= REFERENCED;
304 if(sy->sattre & EQUATEDREG) { // Check register bank usage
305 if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
306 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
307 if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
308 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
314 if(sy->sattr & DEFINED)
315 *a_value = sy->svalue;
318 if(sy->sattre & EQUATEDREG)
321 *a_attr = (WORD)(sy->sattr & ~GLOBAL);
323 if((sy->sattr & (GLOBAL|DEFINED)) == GLOBAL && a_esym != NULL) {
335 return(evexpr(otk, a_value, a_attr, a_esym));
339 // -------------------------------------------------------------------------------------------------
340 // Evaluate expression.
341 // If the expression involves only ONE external symbol, the expression is UNDEFINED, but it's value
342 // includes everything but the symbol value, and `a_esym' is set to the external symbol.
343 // -------------------------------------------------------------------------------------------------
346 int evexpr(TOKEN *tk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
354 sval = evstk; // (Empty) initial stack
356 esym = NULL; // No external symbol involved
359 while(*tk != ENDEXPR)
363 sy->sattr |= REFERENCED; // Set "referenced" bit
365 if(!(sy->sattr & DEFINED)) {
366 if(!(sy->sattr & GLOBAL)) { // Reference to undefined symbol
371 if(esym != NULL) // Check for multiple externals
372 return(error(seg_error));
376 if(sy->sattr & DEFINED) {
377 *++sval = sy->svalue; // Push symbol's value
379 *++sval = 0; // 0 for undefined symbols
382 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
383 sym_seg = (WORD)(sy->sattr & (TEXT|DATA|BSS));
386 *++sval = *tk++; // Push value
387 *++sattr = ABS|DEFINED; // Push simple attribs
390 *++sval = *tk++; // Push value
391 *++sattr = (WORD)*tk++; // Push attribs
394 // Binary "+" and "-" matrix:
397 // ----------------------------
398 // ABS | ABS | Sect | Other |
399 // Sect | Sect | [1] | Error |
400 // Other | Other | Error | [1] |
401 // ----------------------------
407 --sattr; // Pop attrib
408 *sval += sval[1]; // Compute value
410 if(!(*sattr & (TEXT|DATA|BSS)))
412 else if(sattr[1] & (TEXT|DATA|BSS))
413 return(error(seg_error));
417 --sattr; // Pop attrib
418 *sval -= sval[1]; // Compute value
420 attr = (WORD)(*sattr & (TEXT|DATA|BSS));
423 else if(sattr[1] & (TEXT|DATA|BSS)) {
424 if(!(attr & sattr[1])) {
425 return(error(seg_error));
427 *sattr &= ~(TEXT|DATA|BSS);
431 // Unary operators only work on ABS items
433 if(*sattr & (TEXT|DATA|BSS))
436 *sattr = ABS|DEFINED; // Expr becomes absolute
439 if(*sattr & (TEXT|DATA|BSS))
442 *sattr = ABS|DEFINED; // Expr becomes absolute
445 if(*sattr & (TEXT|DATA|BSS))
448 *sattr = ABS|DEFINED; // Expr becomes absolute
450 // Comparison operators must have two values that
451 // are in the same segment, but that's the only requirement.
455 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
456 *sattr = ABS|DEFINED;
457 *sval = *sval <= sval[1];
462 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
463 *sattr = ABS|DEFINED;
464 *sval = *sval >= sval[1];
469 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
470 *sattr = ABS|DEFINED;
471 *sval = *sval > sval[1];
476 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
477 *sattr = ABS|DEFINED;
478 *sval = *sval < sval[1];
483 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
484 *sattr = ABS|DEFINED;
485 *sval = *sval != sval[1];
490 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
491 *sattr = ABS|DEFINED;
492 *sval = *sval == sval[1];
494 // All other binary operators must have two ABS items
495 // to work with. They all produce an ABS value.
497 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
498 //if((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
501 *sattr = ABS|DEFINED; // Expr becomes absolute
502 switch((int)tk[-1]) {
505 --sattr; // Pop attrib
510 --sattr; // Pop attrib
512 return(error("divide by zero"));
517 --sattr; // Pop attrib
519 return(error("mod (%) by zero"));
524 --sattr; // Pop attrib
529 --sattr; // Pop attrib
534 --sattr; // Pop attrib
539 --sattr; // Pop attrib
544 --sattr; // Pop attrib
548 interror(5); // Bad operator in expression stream
552 if(esym != NULL) *sattr &= ~DEFINED;
553 if(a_esym != NULL) *a_esym = esym;
555 // sym_seg added in 1.0.16 to solve a problem with forward symbols in expressions where absolute
556 // values also existed. The absolutes were overiding the symbol segments and not being included :(
557 //*a_attr = *sattr | sym_seg; // Copy value + attrib
559 *a_attr = *sattr; // Copy value + attrib