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;
244 *evalTokenBuffer++ = symbolNum;
245 symbolPtr[symbolNum] = sy;
249 *evalTokenBuffer++ = CONST;
250 *evalTokenBuffer++ = str_value(string[*tok++]);
257 return error("missing close parenthesis ')'");
265 return error("missing close parenthesis ']'");
269 *evalTokenBuffer++ = ACONST; // Attributed const
270 *evalTokenBuffer++ = sloc; // Current location
271 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
274 *evalTokenBuffer++ = ACONST; // Attributed const
278 *evalTokenBuffer++ = orgaddr;
280 *evalTokenBuffer++ = pcloc; // Location at start of line
282 // pcloc == location at start of line
283 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
286 *evalTokenBuffer++ = ABS | DEFINED; // Store attribs
289 return error("bad expression");
297 // Recursive-descent expression analyzer (with some simple speed hacks)
299 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
301 // Passed in values (once derefenced, that is) can all be zero. They are
302 // there so that the expression analyzer can fill them in as needed. The
303 // expression analyzer gets its input from the global token pointer "tok",
304 // and not from anything passed in by the user.
309 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
310 // Also set in various other places too (riscasm.c, e.g.)
312 //printf("expr(): tokens 0-2: %i %i %i (%c %c %c); tc[2] = %i\n", tok[0], tok[1], tok[2], tok[0], tok[1], tok[2], tokenClass[tok[2]]);
313 // Optimize for single constant or single symbol.
314 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
315 // followed by the value 101, it will trigger a bad evaluation here.
316 // This is probably a really bad assumption to be making here...!
317 // (assuming tok[1] == EOL is a single token that is)
318 // if ((tok[1] == EOL)
319 if ((tok[1] == EOL && tok[0] != CONST)
320 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
321 && (tokenClass[tok[2]] < UNARY)))
323 if (*tok >= KW_R0 && *tok <= KW_R31)
325 *evalTokenBuffer++ = CONST;
326 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
327 *a_attr = ABS | DEFINED;
334 else if (*tok == CONST)
336 *evalTokenBuffer++ = CONST;
337 *evalTokenBuffer++ = *a_value = tok[1];
338 *a_attr = ABS | DEFINED;
344 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
346 else if (*tok == '*')
348 *evalTokenBuffer++ = CONST;
351 *evalTokenBuffer++ = *a_value = orgaddr;
353 *evalTokenBuffer++ = *a_value = pcloc;
355 *a_attr = ABS | DEFINED;
362 else if (*tok == STRING || *tok == SYMBOL)
365 j = (*p == '.' ? curenv : 0);
366 symbol = lookup(p, LABEL, j);
368 printf("eval: Looking up symbol [=%08X]\n", symbol);
370 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
374 symbol = NewSymbol(p, LABEL, j);
376 symbol->sattr |= REFERENCED;
378 // Check for undefined register equates
379 if (symbol->sattre & UNDEF_EQUR)
381 errors("undefined register equate '%s'", symbol->sname);
382 //if we return right away, it returns some spurious errors...
386 // Check register bank usage
387 if (symbol->sattre & EQUATEDREG)
389 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
390 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
392 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
393 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
396 *evalTokenBuffer++ = SYMBOL;
398 *evalTokenBuffer++ = (TOKEN)symbol;
401 While this approach works, it's wasteful. It would be better to use something
402 that's already available, like the symbol "order defined" table (which needs to
403 be converted from a linked list into an array).
405 *evalTokenBuffer++ = symbolNum;
406 symbolPtr[symbolNum] = symbol;
410 if (symbol->sattr & DEFINED)
411 *a_value = symbol->svalue;
416 All that extra crap that was put into the svalue when doing the equr stuff is
417 thrown away right here. What the hell is it for?
419 if (symbol->sattre & EQUATEDREG)
422 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
424 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
431 // Unknown type here... Alert the user!
432 error("undefined RISC register in expression");
433 // Prevent spurious error reporting...
438 *evalTokenBuffer++ = ENDEXPR;
445 *evalTokenBuffer++ = ENDEXPR;
446 return evexpr(otk, a_value, a_attr, a_esym);
451 // Evaluate expression.
452 // If the expression involves only ONE external symbol, the expression is
453 // UNDEFINED, but it's value includes everything but the symbol value, and
454 // `a_esym' is set to the external symbol.
456 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
465 sval = evstk; // (Empty) initial stack
467 esym = NULL; // No external symbol involved
470 while (*tk != ENDEXPR)
475 //printf("evexpr(): SYMBOL\n");
476 sy = symbolPtr[*tk++];
477 sy->sattr |= REFERENCED; // Set "referenced" bit
479 if (!(sy->sattr & DEFINED))
481 // Reference to undefined symbol
482 if (!(sy->sattr & GLOBAL))
489 if (esym != NULL) // Check for multiple externals
490 return error(seg_error);
495 if (sy->sattr & DEFINED)
497 *++sval = sy->svalue; // Push symbol's value
501 *++sval = 0; // 0 for undefined symbols
504 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
505 sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
508 //printf("evexpr(): CONST = %i\n", *tk);
509 *++sval = *tk++; // Push value
510 *++sattr = ABS | DEFINED; // Push simple attribs
513 //printf("evexpr(): ACONST = %i\n", *tk);
514 *++sval = *tk++; // Push value
515 *++sattr = (WORD)*tk++; // Push attribs
518 // Binary "+" and "-" matrix:
521 // ----------------------------
522 // ABS | ABS | Sect | Other |
523 // Sect | Sect | [1] | Error |
524 // Other | Other | Error | [1] |
525 // ----------------------------
530 //printf("evexpr(): +\n");
532 --sattr; // Pop attrib
533 *sval += sval[1]; // Compute value
535 if (!(*sattr & (TEXT | DATA | BSS)))
537 else if (sattr[1] & (TEXT | DATA | BSS))
538 return error(seg_error);
542 //printf("evexpr(): -\n");
544 --sattr; // Pop attrib
545 *sval -= sval[1]; // Compute value
547 attr = (WORD)(*sattr & (TEXT | DATA | BSS));
551 else if (sattr[1] & (TEXT | DATA | BSS))
553 if (!(attr & sattr[1]))
554 return error(seg_error);
556 *sattr &= ~(TEXT | DATA | BSS);
560 // Unary operators only work on ABS items
562 //printf("evexpr(): UNMINUS\n");
563 if (*sattr & (TEXT | DATA | BSS))
567 *sattr = ABS | DEFINED; // Expr becomes absolute
570 //printf("evexpr(): !\n");
571 if (*sattr & (TEXT | DATA | BSS))
575 *sattr = ABS | DEFINED; // Expr becomes absolute
578 //printf("evexpr(): ~\n");
579 if (*sattr & (TEXT | DATA | BSS))
583 *sattr = ABS | DEFINED; // Expr becomes absolute
585 // Comparison operators must have two values that
586 // are in the same segment, but that's the only requirement.
588 //printf("evexpr(): LE\n");
592 if ((*sattr & TDB) != (sattr[1] & TDB))
595 *sattr = ABS | DEFINED;
596 *sval = *sval <= sval[1];
599 //printf("evexpr(): GE\n");
603 if ((*sattr & TDB) != (sattr[1] & TDB))
606 *sattr = ABS | DEFINED;
607 *sval = *sval >= sval[1];
610 //printf("evexpr(): >\n");
614 if ((*sattr & TDB) != (sattr[1] & TDB))
617 *sattr = ABS | DEFINED;
618 *sval = *sval > sval[1];
621 //printf("evexpr(): <\n");
625 if ((*sattr & TDB) != (sattr[1] & TDB))
628 *sattr = ABS | DEFINED;
629 *sval = *sval < sval[1];
632 //printf("evexpr(): NE\n");
636 if ((*sattr & TDB) != (sattr[1] & TDB))
639 *sattr = ABS | DEFINED;
640 *sval = *sval != sval[1];
643 //printf("evexpr(): =\n");
647 if ((*sattr & TDB) != (sattr[1] & TDB))
650 *sattr = ABS | DEFINED;
651 *sval = *sval == sval[1];
653 // All other binary operators must have two ABS items
654 // to work with. They all produce an ABS value.
656 //printf("evexpr(): default\n");
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