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 static char tokcl[128]; // Generated table of token classes
24 static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
25 static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
27 // Token-class initialization list
30 CONST, SYMBOL, 0, // ID
31 '(', '[', '{', 0, // OPAR
32 ')', ']', '}', 0, // CPAR
33 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
36 '!', '~', UNMINUS, 0, // UNARY
37 '*', '/', '%', 0, // MULT
40 LE, GE, '<', '>', NE, '=', 0, // REL
47 const char missym_error[] = "missing symbol";
48 const char str_error[] = "missing symbol or string";
50 // Convert expression to postfix
51 static TOKEN * tk; // Deposit tokens here (this is really a
52 // pointer to exprbuf from direct.c)
53 static symbolNum; // Pointer to the entry in symbolPtr[]
57 // Obtain a String Value
59 static VALUE str_value(char * p)
64 v = (v << 8) | (*p & 0xFF);
71 // Initialize Expression Analyzer
76 char * p; // Token pointer
78 // Initialize token-class table
79 for(i=0; i<128; ++i) // Mark all entries END
82 for(i=0, p=itokcl; *p!=1; p++)
87 tokcl[(int)(*p)] = (char)i;
95 // Binary operators (all the same precedence)
104 while (tokcl[*tok] >= MULT)
119 // Unary operators (detect unary '-')
132 if (*tok == '-' || class == UNARY)
144 else if (class == SUNARY)
156 case CR_MACDEF: // ^^macdef <macro-name>
157 if (*tok++ != SYMBOL)
158 return error(missym_error);
167 if (lookup(p, MACRO, 0) == NULL)
172 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
184 if (*tok++ != SYMBOL)
185 return error(missym_error);
198 if ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w))
203 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
210 if (*tok != SYMBOL && *tok != STRING)
211 return error(str_error);
221 return error(comma_error);
223 if (*tok != SYMBOL && *tok != STRING)
224 return error(str_error);
233 w = (WORD)(!strcmp(p, p2));
247 // Terminals (CONSTs) and parenthesis grouping
272 sy = lookup(p, LABEL, j);
275 sy = NewSymbol(p, LABEL, j);
277 // Check register bank usage
278 if (sy->sattre & EQUATEDREG)
280 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
281 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
283 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
284 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
292 symbolPtr[symbolNum] = sy;
299 *tk++ = str_value((char *)*tok++);
301 *tk++ = str_value(string[*tok++]);
309 return error("missing close parenthesis ')'");
317 return error("missing close parenthesis ']'");
321 *tk++ = ACONST; // Attributed const
322 *tk++ = sloc; // Current location
323 *tk++ = cursect | DEFINED; // Store attribs
326 *tk++ = ACONST; // Attributed const
331 *tk++ = pcloc; // Location at start of line
333 *tk++ = ABS | DEFINED; // Store attribs
336 return error("bad expression");
344 // Recursive-descent expression analyzer (with some simple speed hacks)
346 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
352 tk = otk; // Set token pointer to 'exprbuf' (direct.c)
353 // symbolNum = 0; // Set symbol number in symbolPtr[] to 0
355 // Optimize for single constant or single symbol.
357 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
358 && (tokcl[tok[2]] < UNARY)))
360 if (*tok >= KW_R0 && *tok <= KW_R31)
363 *tk++ = *a_value = (*tok - KW_R0);
364 *a_attr = ABS | DEFINED;
373 else if (*tok == CONST)
376 *tk++ = *a_value = tok[1];
377 *a_attr = ABS | DEFINED;
382 else if (*tok == '*')
387 *tk++ = *a_value = orgaddr;
389 *tk++ = *a_value = pcloc;
391 *a_attr = ABS | DEFINED;
411 sy = lookup(p, LABEL, j);
414 sy = NewSymbol(p, LABEL, j);
416 sy->sattr |= REFERENCED;
418 // Check register bank usage
419 if (sy->sattre & EQUATEDREG)
421 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
422 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
424 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
425 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
433 symbolPtr[symbolNum] = sy;
437 if (sy->sattr & DEFINED)
438 *a_value = sy->svalue;
442 if (sy->sattre & EQUATEDREG)
445 *a_attr = (WORD)(sy->sattr & ~GLOBAL);
447 if ((sy->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
460 return evexpr(otk, a_value, a_attr, a_esym);
465 // Evaluate expression.
466 // If the expression involves only ONE external symbol, the expression is
467 // UNDEFINED, but it's value includes everything but the symbol value, and
468 // `a_esym' is set to the external symbol.
470 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
479 sval = evstk; // (Empty) initial stack
481 esym = NULL; // No external symbol involved
484 while (*tk != ENDEXPR)
489 // sy = (SYM *)*tk++;
490 sy = symbolPtr[*tk++];
491 sy->sattr |= REFERENCED; // Set "referenced" bit
493 if (!(sy->sattr & DEFINED))
495 // Reference to undefined symbol
496 if (!(sy->sattr & GLOBAL))
503 if (esym != NULL) // Check for multiple externals
504 return error(seg_error);
509 if (sy->sattr & DEFINED)
511 *++sval = sy->svalue; // Push symbol's value
515 *++sval = 0; // 0 for undefined symbols
518 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
519 sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
522 *++sval = *tk++; // Push value
523 *++sattr = ABS | DEFINED; // Push simple attribs
526 *++sval = *tk++; // Push value
527 *++sattr = (WORD)*tk++; // Push attribs
530 // Binary "+" and "-" matrix:
533 // ----------------------------
534 // ABS | ABS | Sect | Other |
535 // Sect | Sect | [1] | Error |
536 // Other | Other | Error | [1] |
537 // ----------------------------
543 --sattr; // Pop attrib
544 *sval += sval[1]; // Compute value
546 if (!(*sattr & (TEXT | DATA | BSS)))
548 else if (sattr[1] & (TEXT | DATA | BSS))
549 return error(seg_error);
554 --sattr; // Pop attrib
555 *sval -= sval[1]; // Compute value
557 attr = (WORD)(*sattr & (TEXT | DATA | BSS));
561 else if (sattr[1] & (TEXT | DATA | BSS))
563 if (!(attr & sattr[1]))
564 return error(seg_error);
566 *sattr &= ~(TEXT | DATA | BSS);
570 // Unary operators only work on ABS items
572 if (*sattr & (TEXT | DATA | BSS))
576 *sattr = ABS | DEFINED; // Expr becomes absolute
579 if (*sattr & (TEXT | DATA | BSS))
583 *sattr = ABS | DEFINED; // Expr becomes absolute
586 if (*sattr & (TEXT | DATA | BSS))
590 *sattr = ABS | DEFINED; // Expr becomes absolute
592 // Comparison operators must have two values that
593 // are in the same segment, but that's the only requirement.
598 if ((*sattr & TDB) != (sattr[1] & TDB))
601 *sattr = ABS | DEFINED;
602 *sval = *sval <= sval[1];
608 if ((*sattr & TDB) != (sattr[1] & TDB))
611 *sattr = ABS | DEFINED;
612 *sval = *sval >= sval[1];
618 if ((*sattr & TDB) != (sattr[1] & TDB))
621 *sattr = ABS | DEFINED;
622 *sval = *sval > sval[1];
628 if ((*sattr & TDB) != (sattr[1] & TDB))
631 *sattr = ABS | DEFINED;
632 *sval = *sval < sval[1];
638 if ((*sattr & TDB) != (sattr[1] & TDB))
641 *sattr = ABS | DEFINED;
642 *sval = *sval != sval[1];
648 if ((*sattr & TDB) != (sattr[1] & TDB))
651 *sattr = ABS | DEFINED;
652 *sval = *sval == sval[1];
654 // All other binary operators must have two ABS items
655 // to work with. They all produce an ABS value.
657 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
658 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
660 *sattr = ABS | DEFINED; // Expr becomes absolute
666 --sattr; // Pop attrib
671 --sattr; // Pop attrib
674 return error("divide by zero");
680 --sattr; // Pop attrib
683 return error("mod (%) by zero");
689 --sattr; // Pop attrib
694 --sattr; // Pop attrib
699 --sattr; // Pop attrib
704 --sattr; // Pop attrib
709 --sattr; // Pop attrib
713 interror(5); // Bad operator in expression stream
724 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
725 // expressions where absolute values also existed. The absolutes were
726 // overiding the symbol segments and not being included :(
727 //*a_attr = *sattr | sym_seg; // Copy value + attrib
729 *a_attr = *sattr; // Copy value + attrib