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 tokenClass[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 * evalTokenBuffer; // Deposit tokens here (this is really a
52 // pointer to exprbuf from direct.c)
53 // (Can also be from others, like riscasm.c)
54 static symbolNum; // Pointer to the entry in symbolPtr[]
58 // Obtain a String Value
60 static VALUE str_value(char * p)
65 v = (v << 8) | (*p & 0xFF);
72 // Initialize Expression Analyzer
74 void InitExpression(void)
77 char * p; // Token pointer
79 // Initialize token-class table (all set to END)
83 for(i=0, p=itokcl; *p!=1; p++)
88 tokenClass[(int)(*p)] = (char)i;
96 // Binary operators (all the same precedence)
105 while (tokenClass[*tok] >= MULT)
112 *evalTokenBuffer++ = t;
120 // Unary operators (detect unary '-')
131 class = tokenClass[*tok];
133 if (*tok == '-' || class == UNARY)
143 *evalTokenBuffer++ = t;
145 else if (class == SUNARY)
150 *evalTokenBuffer++ = CONST;
151 *evalTokenBuffer++ = dos_time();
154 *evalTokenBuffer++ = CONST;
155 *evalTokenBuffer++ = dos_date();
157 case CR_MACDEF: // ^^macdef <macro-name>
158 if (*tok++ != SYMBOL)
159 return error(missym_error);
162 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
163 *evalTokenBuffer++ = CONST;
164 *evalTokenBuffer++ = (TOKEN)w;
172 if (*tok++ != SYMBOL)
173 return error(missym_error);
176 j = (*p == '.' ? curenv : 0);
177 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
178 *evalTokenBuffer++ = CONST;
179 *evalTokenBuffer++ = (TOKEN)w;
182 if (*tok != SYMBOL && *tok != STRING)
183 return error(str_error);
189 return error(comma_error);
191 if (*tok != SYMBOL && *tok != STRING)
192 return error(str_error);
197 w = (WORD)(!strcmp(p, p2));
198 *evalTokenBuffer++ = CONST;
199 *evalTokenBuffer++ = (TOKEN)w;
211 // Terminals (CONSTs) and parenthesis grouping
222 *evalTokenBuffer++ = CONST;
223 *evalTokenBuffer++ = *tok++;
227 j = (*p == '.' ? curenv : 0);
228 sy = lookup(p, LABEL, j);
231 sy = NewSymbol(p, LABEL, j);
233 // Check register bank usage
234 if (sy->sattre & EQUATEDREG)
236 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
237 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
239 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
240 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
243 *evalTokenBuffer++ = SYMBOL;
245 *evalTokenBuffer++ = (TOKEN)sy;
247 *evalTokenBuffer++ = symbolNum;
248 symbolPtr[symbolNum] = sy;
253 *evalTokenBuffer++ = CONST;
254 *evalTokenBuffer++ = str_value(string[*tok++]);
261 return error("missing close parenthesis ')'");
269 return error("missing close parenthesis ']'");
273 *evalTokenBuffer++ = ACONST; // Attributed const
274 *evalTokenBuffer++ = sloc; // Current location
275 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
278 *evalTokenBuffer++ = ACONST; // Attributed const
281 *evalTokenBuffer++ = orgaddr;
283 *evalTokenBuffer++ = pcloc; // Location at start of line
285 *evalTokenBuffer++ = ABS | DEFINED; // Store attribs
288 return error("bad expression");
296 // Recursive-descent expression analyzer (with some simple speed hacks)
298 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
300 // Passed in values (once derefenced, that is) can all be zero. They are
301 // there so that the expression analyzer can fill them in as needed. The
302 // expression analyzer gets its input from the global token pointer "tok",
303 // and not from anything passed in by the user.
308 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
309 // Also set in various other places too (riscasm.c, e.g.)
311 // Optimize for single constant or single symbol.
313 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
314 && (tokenClass[tok[2]] < UNARY)))
316 if (*tok >= KW_R0 && *tok <= KW_R31)
318 *evalTokenBuffer++ = CONST;
319 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
320 *a_attr = ABS | DEFINED;
326 // *evalTokenBuffer++ = ENDEXPR;
329 else if (*tok == CONST)
331 *evalTokenBuffer++ = CONST;
332 *evalTokenBuffer++ = *a_value = tok[1];
333 *a_attr = ABS | DEFINED;
340 else if (*tok == '*')
342 *evalTokenBuffer++ = CONST;
345 *evalTokenBuffer++ = *a_value = orgaddr;
347 *evalTokenBuffer++ = *a_value = pcloc;
349 *a_attr = ABS | DEFINED;
357 else if (*tok == STRING || *tok == SYMBOL)
360 j = (*p == '.' ? curenv : 0);
361 symbol = lookup(p, LABEL, j);
364 symbol = NewSymbol(p, LABEL, j);
366 symbol->sattr |= REFERENCED;
368 // Check for undefined register equates
369 if (symbol->sattre & UNDEF_EQUR)
371 errors("undefined register equate '%s'", symbol->sname);
372 //if we return right away, it returns some spurious errors...
376 // Check register bank usage
377 if (symbol->sattre & EQUATEDREG)
379 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
380 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
382 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
383 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
386 *evalTokenBuffer++ = SYMBOL;
388 *evalTokenBuffer++ = (TOKEN)symbol;
391 While this approach works, it's wasteful. It would be better to use something
392 that's already available, like the symbol "order defined" table (which needs to
393 be converted from a linked list into an array).
395 *evalTokenBuffer++ = symbolNum;
396 symbolPtr[symbolNum] = symbol;
400 if (symbol->sattr & DEFINED)
401 *a_value = symbol->svalue;
406 All that extra crap that was put into the svalue when doing the equr stuff is
407 thrown away right here. What the hell is it for?
409 if (symbol->sattre & EQUATEDREG)
412 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
414 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
421 // Unknown type here... Alert the user!
422 error("undefined RISC register in expression");
423 // Prevent spurious error reporting...
429 *evalTokenBuffer++ = ENDEXPR;
436 *evalTokenBuffer++ = ENDEXPR;
437 return evexpr(otk, a_value, a_attr, a_esym);
442 // Evaluate expression.
443 // If the expression involves only ONE external symbol, the expression is
444 // UNDEFINED, but it's value includes everything but the symbol value, and
445 // `a_esym' is set to the external symbol.
447 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
456 sval = evstk; // (Empty) initial stack
458 esym = NULL; // No external symbol involved
461 while (*tk != ENDEXPR)
466 // sy = (SYM *)*tk++;
467 sy = symbolPtr[*tk++];
468 sy->sattr |= REFERENCED; // Set "referenced" bit
470 if (!(sy->sattr & DEFINED))
472 // Reference to undefined symbol
473 if (!(sy->sattr & GLOBAL))
480 if (esym != NULL) // Check for multiple externals
481 return error(seg_error);
486 if (sy->sattr & DEFINED)
488 *++sval = sy->svalue; // Push symbol's value
492 *++sval = 0; // 0 for undefined symbols
495 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
496 sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
499 *++sval = *tk++; // Push value
500 *++sattr = ABS | DEFINED; // Push simple attribs
503 *++sval = *tk++; // Push value
504 *++sattr = (WORD)*tk++; // Push attribs
507 // Binary "+" and "-" matrix:
510 // ----------------------------
511 // ABS | ABS | Sect | Other |
512 // Sect | Sect | [1] | Error |
513 // Other | Other | Error | [1] |
514 // ----------------------------
520 --sattr; // Pop attrib
521 *sval += sval[1]; // Compute value
523 if (!(*sattr & (TEXT | DATA | BSS)))
525 else if (sattr[1] & (TEXT | DATA | BSS))
526 return error(seg_error);
531 --sattr; // Pop attrib
532 *sval -= sval[1]; // Compute value
534 attr = (WORD)(*sattr & (TEXT | DATA | BSS));
538 else if (sattr[1] & (TEXT | DATA | BSS))
540 if (!(attr & sattr[1]))
541 return error(seg_error);
543 *sattr &= ~(TEXT | DATA | BSS);
547 // Unary operators only work on ABS items
549 if (*sattr & (TEXT | DATA | BSS))
553 *sattr = ABS | DEFINED; // Expr becomes absolute
556 if (*sattr & (TEXT | DATA | BSS))
560 *sattr = ABS | DEFINED; // Expr becomes absolute
563 if (*sattr & (TEXT | DATA | BSS))
567 *sattr = ABS | DEFINED; // Expr becomes absolute
569 // Comparison operators must have two values that
570 // are in the same segment, but that's the only requirement.
575 if ((*sattr & TDB) != (sattr[1] & TDB))
578 *sattr = ABS | DEFINED;
579 *sval = *sval <= sval[1];
585 if ((*sattr & TDB) != (sattr[1] & TDB))
588 *sattr = ABS | DEFINED;
589 *sval = *sval >= sval[1];
595 if ((*sattr & TDB) != (sattr[1] & TDB))
598 *sattr = ABS | DEFINED;
599 *sval = *sval > sval[1];
605 if ((*sattr & TDB) != (sattr[1] & TDB))
608 *sattr = ABS | DEFINED;
609 *sval = *sval < sval[1];
615 if ((*sattr & TDB) != (sattr[1] & TDB))
618 *sattr = ABS | DEFINED;
619 *sval = *sval != sval[1];
625 if ((*sattr & TDB) != (sattr[1] & TDB))
628 *sattr = ABS | DEFINED;
629 *sval = *sval == sval[1];
631 // All other binary operators must have two ABS items
632 // to work with. They all produce an ABS value.
634 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
635 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
637 *sattr = ABS | DEFINED; // Expr becomes absolute
643 --sattr; // Pop attrib
648 --sattr; // Pop attrib
651 return error("divide by zero");
657 --sattr; // Pop attrib
660 return error("mod (%) by zero");
666 --sattr; // Pop attrib
671 --sattr; // Pop attrib
676 --sattr; // Pop attrib
681 --sattr; // Pop attrib
686 --sattr; // Pop attrib
690 interror(5); // Bad operator in expression stream
701 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
702 // expressions where absolute values also existed. The absolutes were
703 // overiding the symbol segments and not being included :(
704 //*a_attr = *sattr | sym_seg; // Copy value + attrib
706 *a_attr = *sattr; // Copy value + attrib