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
56 // Obtain a String Value
58 static VALUE str_value(char * p)
63 v = (v << 8) | (*p & 0xFF);
70 // Initialize Expression Analyzer
75 char * p; // Token pointer
77 // Initialize token-class table
78 for(i=0; i<128; ++i) // Mark all entries END
81 for(i=0, p=itokcl; *p!=1; ++p)
86 tokcl[(int)(*p)] = (char)i;
92 // Binary operators (all the same precedence)
101 while (tokcl[*tok] >= MULT)
116 // Unary operators (detect unary '-')
129 if (*tok == '-' || class == UNARY)
141 else if (class == SUNARY)
153 case CR_MACDEF: // ^^macdef <macro-name>
154 if (*tok++ != SYMBOL)
155 return error(missym_error);
159 if (lookup(p, MACRO, 0) == NULL)
173 if (*tok++ != SYMBOL)
174 return error(missym_error);
182 if ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w))
191 if (*tok != SYMBOL && *tok != STRING)
192 return error(str_error);
198 return error(comma_error);
200 if (*tok != SYMBOL && *tok != STRING)
201 return error(str_error);
206 w = (WORD)(!strcmp(p, p2));
220 // Terminals (CONSTs) and parenthesis grouping
241 sy = lookup(p, LABEL, j);
244 sy = newsym(p, LABEL, j);
246 // Check register bank usage
247 if (sy->sattre & EQUATEDREG)
249 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
250 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
252 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
253 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
261 *tk++ = str_value((char *)*tok++);
268 return error("missing close parenthesis ')'");
276 return error("missing close parenthesis ']'");
280 *tk++ = ACONST; // Attributed const
281 *tk++ = sloc; // Current location
282 *tk++ = cursect | DEFINED; // Store attribs
285 *tk++ = ACONST; // Attributed const
290 *tk++ = pcloc; // Location at start of line
292 *tk++ = ABS | DEFINED; // Store attribs
295 return error("bad expression");
303 // Recursive-descent expression analyzer (with some simple speed hacks)
305 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
313 // Optimize for single constant or single symbol.
315 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
316 && (tokcl[tok[2]] < UNARY)))
318 if (*tok >= KW_R0 && *tok <= KW_R31)
321 *tk++ = *a_value = (*tok - KW_R0);
322 *a_attr = ABS | DEFINED;
331 else if (*tok == CONST)
334 *tk++ = *a_value = tok[1];
335 *a_attr = ABS | DEFINED;
340 else if (*tok == '*')
345 *tk++ = *a_value = orgaddr;
347 *tk++ = *a_value = pcloc;
349 *a_attr = ABS | DEFINED;
365 sy = lookup(p, LABEL, j);
368 sy = newsym(p, LABEL, j);
370 sy->sattr |= REFERENCED;
372 // Check register bank usage
373 if (sy->sattre & EQUATEDREG)
375 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
376 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
378 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
379 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
385 if (sy->sattr & DEFINED)
386 *a_value = sy->svalue;
390 if (sy->sattre & EQUATEDREG)
393 *a_attr = (WORD)(sy->sattr & ~GLOBAL);
395 if ((sy->sattr & (GLOBAL|DEFINED)) == GLOBAL && a_esym != NULL)
408 return evexpr(otk, a_value, a_attr, a_esym);
413 // Evaluate expression.
414 // If the expression involves only ONE external symbol, the expression is
415 // UNDEFINED, but it's value includes everything but the symbol value, and
416 // `a_esym' is set to the external symbol.
418 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
427 sval = evstk; // (Empty) initial stack
429 esym = NULL; // No external symbol involved
432 while (*tk != ENDEXPR)
438 sy->sattr |= REFERENCED; // Set "referenced" bit
440 if (!(sy->sattr & DEFINED))
442 if (!(sy->sattr & GLOBAL))
443 { // Reference to undefined symbol
449 if (esym != NULL) // Check for multiple externals
450 return error(seg_error);
455 if (sy->sattr & DEFINED)
457 *++sval = sy->svalue; // Push symbol's value
461 *++sval = 0; // 0 for undefined symbols
464 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
465 sym_seg = (WORD)(sy->sattr & (TEXT|DATA|BSS));
468 *++sval = *tk++; // Push value
469 *++sattr = ABS|DEFINED; // Push simple attribs
472 *++sval = *tk++; // Push value
473 *++sattr = (WORD)*tk++; // Push attribs
476 // Binary "+" and "-" matrix:
479 // ----------------------------
480 // ABS | ABS | Sect | Other |
481 // Sect | Sect | [1] | Error |
482 // Other | Other | Error | [1] |
483 // ----------------------------
489 --sattr; // Pop attrib
490 *sval += sval[1]; // Compute value
492 if (!(*sattr & (TEXT|DATA|BSS)))
494 else if (sattr[1] & (TEXT|DATA|BSS))
495 return error(seg_error);
500 --sattr; // Pop attrib
501 *sval -= sval[1]; // Compute value
503 attr = (WORD)(*sattr & (TEXT|DATA|BSS));
507 else if (sattr[1] & (TEXT|DATA|BSS))
509 if (!(attr & sattr[1]))
510 return error(seg_error);
512 *sattr &= ~(TEXT|DATA|BSS);
516 // Unary operators only work on ABS items
518 if (*sattr & (TEXT|DATA|BSS))
522 *sattr = ABS|DEFINED; // Expr becomes absolute
525 if (*sattr & (TEXT|DATA|BSS))
529 *sattr = ABS|DEFINED; // Expr becomes absolute
532 if (*sattr & (TEXT|DATA|BSS))
536 *sattr = ABS|DEFINED; // Expr becomes absolute
538 // Comparison operators must have two values that
539 // are in the same segment, but that's the only requirement.
544 if ((*sattr & TDB) != (sattr[1] & TDB))
547 *sattr = ABS|DEFINED;
548 *sval = *sval <= sval[1];
554 if ((*sattr & TDB) != (sattr[1] & TDB))
557 *sattr = ABS|DEFINED;
558 *sval = *sval >= sval[1];
564 if ((*sattr & TDB) != (sattr[1] & TDB))
567 *sattr = ABS|DEFINED;
568 *sval = *sval > sval[1];
574 if ((*sattr & TDB) != (sattr[1] & TDB))
577 *sattr = ABS|DEFINED;
578 *sval = *sval < sval[1];
584 if ((*sattr & TDB) != (sattr[1] & TDB))
587 *sattr = ABS|DEFINED;
588 *sval = *sval != sval[1];
594 if ((*sattr & TDB) != (sattr[1] & TDB))
597 *sattr = ABS|DEFINED;
598 *sval = *sval == sval[1];
600 // All other binary operators must have two ABS items
601 // to work with. They all produce an ABS value.
603 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
604 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
606 *sattr = ABS|DEFINED; // Expr becomes absolute
612 --sattr; // Pop attrib
617 --sattr; // Pop attrib
620 return error("divide by zero");
626 --sattr; // Pop attrib
629 return error("mod (%) by zero");
635 --sattr; // Pop attrib
640 --sattr; // Pop attrib
645 --sattr; // Pop attrib
650 --sattr; // Pop attrib
655 --sattr; // Pop attrib
659 interror(5); // Bad operator in expression stream
670 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
671 // expressions where absolute values also existed. The absolutes were
672 // overiding the symbol segments and not being included :(
673 //*a_attr = *sattr | sym_seg; // Copy value + attrib
675 *a_attr = *sattr; // Copy value + attrib