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 // N.B.: The size of tokenClass should be identical to the largest value of
24 // a token; we're assuming 256 but not 100% sure!
25 static char tokenClass[256]; // Generated table of token classes
26 static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
27 static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
29 // Token-class initialization list
32 CONST, SYMBOL, 0, // ID
33 '(', '[', '{', 0, // OPAR
34 ')', ']', '}', 0, // CPAR
35 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
39 '!', '~', UNMINUS, 0, // UNARY
40 '*', '/', '%', 0, // MULT
43 LE, GE, '<', '>', NE, '=', 0, // REL
50 const char missym_error[] = "missing symbol";
51 const char str_error[] = "missing symbol or string";
53 // Convert expression to postfix
54 static TOKEN * evalTokenBuffer; // Deposit tokens here (this is really a
55 // pointer to exprbuf from direct.c)
56 // (Can also be from others, like
58 static symbolNum; // Pointer to the entry in symbolPtr[]
62 // Obtain a string value
64 static VALUE str_value(char * p)
69 v = (v << 8) | (*p & 0xFF);
76 // Initialize expression analyzer
78 void InitExpression(void)
83 // Initialize token-class table (all set to END)
87 for(i=0, p=itokcl; *p!=1; p++)
92 tokenClass[(int)(*p)] = (char)i;
100 // Binary operators (all the same precedence)
109 while (tokenClass[*tok] >= MULT)
116 *evalTokenBuffer++ = t;
124 // Unary operators (detect unary '-')
135 class = tokenClass[*tok];
137 if (*tok == '-' || class == UNARY)
147 *evalTokenBuffer++ = t;
149 else if (class == SUNARY)
154 *evalTokenBuffer++ = CONST;
155 *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
158 *evalTokenBuffer++ = CONST;
159 *evalTokenBuffer++ = dos_time();
162 *evalTokenBuffer++ = CONST;
163 *evalTokenBuffer++ = dos_date();
165 case CR_MACDEF: // ^^macdef <macro-name>
166 if (*tok++ != SYMBOL)
167 return error(missym_error);
170 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
171 *evalTokenBuffer++ = CONST;
172 *evalTokenBuffer++ = (TOKEN)w;
180 if (*tok++ != SYMBOL)
181 return error(missym_error);
184 j = (*p == '.' ? curenv : 0);
185 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
186 *evalTokenBuffer++ = CONST;
187 *evalTokenBuffer++ = (TOKEN)w;
190 if (*tok != SYMBOL && *tok != STRING)
191 return error(str_error);
197 return error(comma_error);
199 if (*tok != SYMBOL && *tok != STRING)
200 return error(str_error);
205 w = (WORD)(!strcmp(p, p2));
206 *evalTokenBuffer++ = CONST;
207 *evalTokenBuffer++ = (TOKEN)w;
219 // Terminals (CONSTs) and parenthesis grouping
230 *evalTokenBuffer++ = CONST;
231 *evalTokenBuffer++ = *tok++;
235 j = (*p == '.' ? curenv : 0);
236 sy = lookup(p, LABEL, j);
239 sy = NewSymbol(p, LABEL, j);
241 // Check register bank usage
242 if (sy->sattre & EQUATEDREG)
244 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
245 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
247 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
248 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
251 *evalTokenBuffer++ = SYMBOL;
252 *evalTokenBuffer++ = symbolNum;
253 symbolPtr[symbolNum] = sy;
257 *evalTokenBuffer++ = CONST;
258 *evalTokenBuffer++ = str_value(string[*tok++]);
265 return error("missing close parenthesis ')'");
273 return error("missing close parenthesis ']'");
277 *evalTokenBuffer++ = ACONST; // Attributed const
278 *evalTokenBuffer++ = sloc; // Current location
279 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
282 *evalTokenBuffer++ = ACONST; // Attributed const
284 // pcloc == location at start of line
285 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
286 // '*' takes attributes of current section, not ABS!
287 *evalTokenBuffer++ = cursect | DEFINED;
290 return error("bad expression");
298 // Recursive-descent expression analyzer (with some simple speed hacks)
300 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
302 // Passed in values (once derefenced, that is) can all be zero. They are
303 // there so that the expression analyzer can fill them in as needed. The
304 // expression analyzer gets its input from the global token pointer "tok",
305 // and not from anything passed in by the user.
310 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
311 // Also set in various other places too (riscasm.c, e.g.)
313 //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]]);
314 // Optimize for single constant or single symbol.
315 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
316 // followed by the value 101, it will trigger a bad evaluation here.
317 // This is probably a really bad assumption to be making here...!
318 // (assuming tok[1] == EOL is a single token that is)
319 // Seems that even other tokens (SUNARY type) can fuck this up too.
320 // if ((tok[1] == EOL)
321 if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
322 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
323 && (tokenClass[tok[2]] < UNARY)))
325 if (*tok >= KW_R0 && *tok <= KW_R31)
327 *evalTokenBuffer++ = CONST;
328 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
329 *a_attr = ABS | DEFINED;
336 else if (*tok == CONST)
338 *evalTokenBuffer++ = CONST;
339 *evalTokenBuffer++ = *a_value = tok[1];
340 *a_attr = ABS | DEFINED;
346 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
348 else if (*tok == '*')
350 *evalTokenBuffer++ = CONST;
353 *evalTokenBuffer++ = *a_value = orgaddr;
355 *evalTokenBuffer++ = *a_value = pcloc;
357 // '*' takes attributes of current section, not ABS!
358 *a_attr = cursect | DEFINED;
365 else if (*tok == STRING || *tok == SYMBOL)
368 j = (*p == '.' ? curenv : 0);
369 symbol = lookup(p, LABEL, j);
371 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
373 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
377 symbol = NewSymbol(p, LABEL, j);
379 symbol->sattr |= REFERENCED;
381 // Check for undefined register equates, but only if it's not part
382 // of a #<SYMBOL> construct, as it could be that the label that's
383 // been undefined may later be used as an address label--which
384 // means it will be fixed up later, and thus, not an error.
385 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
387 errors("undefined register equate '%s'", symbol->sname);
388 //if we return right away, it returns some spurious errors...
392 // Check register bank usage
393 if (symbol->sattre & EQUATEDREG)
395 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
396 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
398 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
399 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
402 *evalTokenBuffer++ = SYMBOL;
404 *evalTokenBuffer++ = (TOKEN)symbol;
407 While this approach works, it's wasteful. It would be better to use something
408 that's already available, like the symbol "order defined" table (which needs to
409 be converted from a linked list into an array).
411 *evalTokenBuffer++ = symbolNum;
412 symbolPtr[symbolNum] = symbol;
416 if (symbol->sattr & DEFINED)
417 *a_value = symbol->svalue;
422 All that extra crap that was put into the svalue when doing the equr stuff is
423 thrown away right here. What the hell is it for?
425 if (symbol->sattre & EQUATEDREG)
428 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
430 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
438 // Unknown type here... Alert the user!,
439 error("undefined RISC register in expression");
440 // Prevent spurious error reporting...
445 *evalTokenBuffer++ = ENDEXPR;
452 *evalTokenBuffer++ = ENDEXPR;
453 return evexpr(otk, a_value, a_attr, a_esym);
458 // Evaluate expression.
459 // If the expression involves only ONE external symbol, the expression is
460 // UNDEFINED, but it's value includes everything but the symbol value, and
461 // `a_esym' is set to the external symbol.
463 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
472 sval = evstk; // (Empty) initial stack
474 esym = NULL; // No external symbol involved
477 while (*tk != ENDEXPR)
482 //printf("evexpr(): SYMBOL\n");
483 sy = symbolPtr[*tk++];
484 sy->sattr |= REFERENCED; // Set "referenced" bit
486 if (!(sy->sattr & DEFINED))
488 // Reference to undefined symbol
489 if (!(sy->sattr & GLOBAL))
496 if (esym != NULL) // Check for multiple externals
497 return error(seg_error);
502 if (sy->sattr & DEFINED)
504 *++sval = sy->svalue; // Push symbol's value
508 *++sval = 0; // 0 for undefined symbols
511 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
512 sym_seg = (WORD)(sy->sattr & TDB);
515 //printf("evexpr(): CONST = %i\n", *tk);
516 *++sval = *tk++; // Push value
517 *++sattr = ABS | DEFINED; // Push simple attribs
520 //printf("evexpr(): ACONST = %i\n", *tk);
521 *++sval = *tk++; // Push value
522 *++sattr = (WORD)*tk++; // Push attribs
525 // Binary "+" and "-" matrix:
528 // ----------------------------
529 // ABS | ABS | Sect | Other |
530 // Sect | Sect | [1] | Error |
531 // Other | Other | Error | [1] |
532 // ----------------------------
537 //printf("evexpr(): +\n");
539 --sattr; // Pop attrib
540 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
541 *sval += sval[1]; // Compute value
542 //printf("%i\n", *sval);
546 else if (sattr[1] & TDB)
547 return error(seg_error);
551 //printf("evexpr(): -\n");
553 --sattr; // Pop attrib
554 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
555 *sval -= sval[1]; // Compute value
556 //printf("%i\n", *sval);
558 attr = (WORD)(*sattr & TDB);
560 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
562 // If symbol1 is ABS, take attributes from symbol2
565 // Otherwise, they're both TDB and so attributes cancel out
566 else if (sattr[1] & TDB)
570 // Unary operators only work on ABS items
572 //printf("evexpr(): UNMINUS\n");
577 *sattr = ABS | DEFINED; // Expr becomes absolute
580 //printf("evexpr(): !\n");
585 *sattr = ABS | DEFINED; // Expr becomes absolute
588 //printf("evexpr(): ~\n");
593 *sattr = ABS | DEFINED; // Expr becomes absolute
595 // Comparison operators must have two values that
596 // are in the same segment, but that's the only requirement.
598 //printf("evexpr(): LE\n");
602 if ((*sattr & TDB) != (sattr[1] & TDB))
605 *sattr = ABS | DEFINED;
606 *sval = *sval <= sval[1];
609 //printf("evexpr(): GE\n");
613 if ((*sattr & TDB) != (sattr[1] & TDB))
616 *sattr = ABS | DEFINED;
617 *sval = *sval >= sval[1];
620 //printf("evexpr(): >\n");
624 if ((*sattr & TDB) != (sattr[1] & TDB))
627 *sattr = ABS | DEFINED;
628 *sval = *sval > sval[1];
631 //printf("evexpr(): <\n");
635 if ((*sattr & TDB) != (sattr[1] & TDB))
638 *sattr = ABS | DEFINED;
639 *sval = *sval < sval[1];
642 //printf("evexpr(): NE\n");
646 if ((*sattr & TDB) != (sattr[1] & TDB))
649 *sattr = ABS | DEFINED;
650 *sval = *sval != sval[1];
653 //printf("evexpr(): =\n");
657 if ((*sattr & TDB) != (sattr[1] & TDB))
660 *sattr = ABS | DEFINED;
661 *sval = *sval == sval[1];
663 // All other binary operators must have two ABS items
664 // to work with. They all produce an ABS value.
666 //printf("evexpr(): default\n");
667 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
668 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
670 *sattr = ABS | DEFINED; // Expr becomes absolute
676 --sattr; // Pop attrib
677 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
679 //printf("%i\n", *sval);
683 --sattr; // Pop attrib
686 return error("divide by zero");
688 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
689 // Compiler is picky here: Without casting these, it discards
690 // the sign if dividing a negative # by a positive one,
691 // creating a bad result. :-/
692 // Probably a side effect of using VALUE intead of ints.
693 *sval = (int)sval[0] / (int)sval[1];
694 //printf("%i\n", *sval);
698 --sattr; // Pop attrib
701 return error("mod (%) by zero");
707 --sattr; // Pop attrib
712 --sattr; // Pop attrib
717 --sattr; // Pop attrib
722 --sattr; // Pop attrib
727 --sattr; // Pop attrib
731 interror(5); // Bad operator in expression stream
742 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
743 // expressions where absolute values also existed. The absolutes were
744 // overiding the symbol segments and not being included :(
745 //*a_attr = *sattr | sym_seg; // Copy value + attrib
747 *a_attr = *sattr; // Copy value + attrib