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
18 #define DEF_KW // Declare keyword values
19 #include "kwtab.h" // Incl generated keyword tables & defs
21 static char tokcl[128]; // Generated table of token classes
22 static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
23 static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
25 // Token-class initialization list
28 CONST, SYMBOL, 0, // ID
29 '(', '[', '{', 0, // OPAR
30 ')', ']', '}', 0, // CPAR
31 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
34 '!', '~', UNMINUS, 0, // UNARY
35 '*', '/', '%', 0, // MULT
38 LE, GE, '<', '>', NE, '=', 0, // REL
45 char missym_error[] = "missing symbol";
46 char *str_error = "missing symbol or string";
48 // Convert expression to postfix
49 static TOKEN *tk; // Deposit tokens here
54 // --- Obtain a String Value -----------------------------------------------------------------------
57 static VALUE str_value(char *p) {
61 v = (v << 8) | (*p & 0xff);
66 // --- Initialize Expression Analyzer --------------------------------------------------------------
69 void init_expr(void) {
71 char *p; // Token pointer
73 // Initialize token-class table
74 for(i = 0; i < 128; ++i) // Mark all entries END
77 for(i = 0, p = itokcl; *p != 1; ++p)
81 tokcl[(int)(*p)] = (char)i;
85 // --- Binary operators (all the same precedence) --------------------------------------------------
93 while(tokcl[*tok] >= MULT) {
103 // --- Unary operators (detect unary '-') ----------------------------------------------------------
116 if(*tok == '-' || class == UNARY) {
123 } else if(class == SUNARY)
124 switch((int)*tok++) {
133 case CR_MACDEF: // ^^macdef <macro-name>
134 if(*tok++ != SYMBOL) return(error(missym_error));
136 if(lookup(p, MACRO, 0) == NULL) w = 0;
150 if(*tok++ != SYMBOL) return(error(missym_error));
153 if(*p == '.') j = curenv;
154 if((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w)) w = 1;
161 if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
165 if(*tok++ != ',') return(error(comma_error));
167 if(*tok != SYMBOL && *tok != STRING) return(error(str_error));
171 w = (WORD)(!strcmp(p, p2));
183 // --- Terminals (CONSTs) and parenthesis grouping -------------------------------------------------
191 switch((int)*tok++) {
201 sy = lookup(p, LABEL, j);
203 sy = newsym(p, LABEL, j);
205 if(sy->sattre & EQUATEDREG) { // Check register bank usage
206 if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
207 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
208 if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
209 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
217 *tk++ = str_value((char *)*tok++);
223 return(error("missing close parenthesis ')'"));
229 return(error("missing close parenthesis ']'"));
232 *tk++ = ACONST; // Attributed const
233 *tk++ = sloc; // Current location
234 *tk++ = cursect | DEFINED; // Store attribs
237 *tk++ = ACONST; // Attributed const
241 *tk++ = pcloc; // Location at start of line
242 *tk++ = ABS | DEFINED; // Store attribs
245 return(error("bad expression"));
251 // --- Recursive-descent expression analyzer (with some simple speed hacks) ------------------------
254 int expr(TOKEN *otk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
261 // Optimize for single constant or single symbol.
262 if((tok[1] == EOL) ||
263 (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31)) &&
264 (tokcl[tok[2]] < UNARY))) {
266 if(*tok >= KW_R0 && *tok <= KW_R31) {
268 *tk++ = *a_value = (*tok - KW_R0);
269 *a_attr = ABS | DEFINED;
275 } else if(*tok == CONST) {
277 *tk++ = *a_value = tok[1];
278 *a_attr = ABS | DEFINED;
281 } else if(*tok == '*') {
284 *tk++ = *a_value = orgaddr;
286 *tk++ = *a_value = pcloc;
287 *a_attr = ABS | DEFINED;
297 sy = lookup(p, LABEL, j);
300 sy = newsym(p, LABEL, j);
301 sy->sattr |= REFERENCED;
303 if(sy->sattre & EQUATEDREG) { // Check register bank usage
304 if((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
305 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
306 if((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
307 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
313 if(sy->sattr & DEFINED)
314 *a_value = sy->svalue;
317 if(sy->sattre & EQUATEDREG)
320 *a_attr = (WORD)(sy->sattr & ~GLOBAL);
322 if((sy->sattr & (GLOBAL|DEFINED)) == GLOBAL && a_esym != NULL) {
334 return(evexpr(otk, a_value, a_attr, a_esym));
338 // -------------------------------------------------------------------------------------------------
339 // Evaluate expression.
340 // If the expression involves only ONE external symbol, the expression is UNDEFINED, but it's value
341 // includes everything but the symbol value, and `a_esym' is set to the external symbol.
342 // -------------------------------------------------------------------------------------------------
345 int evexpr(TOKEN *tk, VALUE *a_value, WORD *a_attr, SYM **a_esym) {
353 sval = evstk; // (Empty) initial stack
355 esym = NULL; // No external symbol involved
358 while(*tk != ENDEXPR)
362 sy->sattr |= REFERENCED; // Set "referenced" bit
364 if(!(sy->sattr & DEFINED)) {
365 if(!(sy->sattr & GLOBAL)) { // Reference to undefined symbol
370 if(esym != NULL) // Check for multiple externals
371 return(error(seg_error));
375 if(sy->sattr & DEFINED) {
376 *++sval = sy->svalue; // Push symbol's value
378 *++sval = 0; // 0 for undefined symbols
381 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
382 sym_seg = (WORD)(sy->sattr & (TEXT|DATA|BSS));
385 *++sval = *tk++; // Push value
386 *++sattr = ABS|DEFINED; // Push simple attribs
389 *++sval = *tk++; // Push value
390 *++sattr = (WORD)*tk++; // Push attribs
393 // Binary "+" and "-" matrix:
396 // ----------------------------
397 // ABS | ABS | Sect | Other |
398 // Sect | Sect | [1] | Error |
399 // Other | Other | Error | [1] |
400 // ----------------------------
406 --sattr; // Pop attrib
407 *sval += sval[1]; // Compute value
409 if(!(*sattr & (TEXT|DATA|BSS)))
411 else if(sattr[1] & (TEXT|DATA|BSS))
412 return(error(seg_error));
416 --sattr; // Pop attrib
417 *sval -= sval[1]; // Compute value
419 attr = (WORD)(*sattr & (TEXT|DATA|BSS));
422 else if(sattr[1] & (TEXT|DATA|BSS)) {
423 if(!(attr & sattr[1])) {
424 return(error(seg_error));
426 *sattr &= ~(TEXT|DATA|BSS);
430 // Unary operators only work on ABS items
432 if(*sattr & (TEXT|DATA|BSS))
435 *sattr = ABS|DEFINED; // Expr becomes absolute
438 if(*sattr & (TEXT|DATA|BSS))
441 *sattr = ABS|DEFINED; // Expr becomes absolute
444 if(*sattr & (TEXT|DATA|BSS))
447 *sattr = ABS|DEFINED; // Expr becomes absolute
449 // Comparison operators must have two values that
450 // are in the same segment, but that's the only requirement.
454 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
455 *sattr = ABS|DEFINED;
456 *sval = *sval <= sval[1];
461 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
462 *sattr = ABS|DEFINED;
463 *sval = *sval >= sval[1];
468 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
469 *sattr = ABS|DEFINED;
470 *sval = *sval > sval[1];
475 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
476 *sattr = ABS|DEFINED;
477 *sval = *sval < sval[1];
482 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
483 *sattr = ABS|DEFINED;
484 *sval = *sval != sval[1];
489 if((*sattr & TDB) != (sattr[1] & TDB)) error(seg_error);
490 *sattr = ABS|DEFINED;
491 *sval = *sval == sval[1];
493 // All other binary operators must have two ABS items
494 // to work with. They all produce an ABS value.
496 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
497 //if((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
500 *sattr = ABS|DEFINED; // Expr becomes absolute
501 switch((int)tk[-1]) {
504 --sattr; // Pop attrib
509 --sattr; // Pop attrib
511 return(error("divide by zero"));
516 --sattr; // Pop attrib
518 return(error("mod (%) by zero"));
523 --sattr; // Pop attrib
528 --sattr; // Pop attrib
533 --sattr; // Pop attrib
538 --sattr; // Pop attrib
543 --sattr; // Pop attrib
547 interror(5); // Bad operator in expression stream
551 if(esym != NULL) *sattr &= ~DEFINED;
552 if(a_esym != NULL) *a_esym = esym;
554 // sym_seg added in 1.0.16 to solve a problem with forward symbols in expressions where absolute
555 // values also existed. The absolutes were overiding the symbol segments and not being included :(
556 //*a_attr = *sattr | sym_seg; // Copy value + attrib
558 *a_attr = *sattr; // Copy value + attrib