2 // RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2017 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 int 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)
80 // Initialize token-class table (all set to END)
81 for(int i=0; i<256; i++)
86 for(char * p=itokcl; *p!=1; p++)
91 tokenClass[(int)(*p)] = (char)i;
99 // Binary operators (all the same precedence)
108 while (tokenClass[*tok] >= MULT)
115 *evalTokenBuffer++ = t;
123 // Unary operators (detect unary '-')
124 // ggn: If expression starts with a plus then also eat it up.
125 // For some reason the parser gets confused when this happens and
126 // emits a "bad expression".
137 class = tokenClass[*tok];
139 if (*tok == '-' || *tok == '+' || class == UNARY)
149 *evalTokenBuffer++ = t;
151 else if (class == SUNARY)
156 *evalTokenBuffer++ = CONST;
157 *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
160 *evalTokenBuffer++ = CONST;
161 *evalTokenBuffer++ = dos_time();
164 *evalTokenBuffer++ = CONST;
165 *evalTokenBuffer++ = dos_date();
167 case CR_MACDEF: // ^^macdef <macro-name>
168 if (*tok++ != SYMBOL)
169 return error(missym_error);
172 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
173 *evalTokenBuffer++ = CONST;
174 *evalTokenBuffer++ = (TOKEN)w;
182 if (*tok++ != SYMBOL)
183 return error(missym_error);
186 j = (*p == '.' ? curenv : 0);
187 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
188 *evalTokenBuffer++ = CONST;
189 *evalTokenBuffer++ = (TOKEN)w;
192 if (*tok != SYMBOL && *tok != STRING)
193 return error(str_error);
199 return error(comma_error);
201 if (*tok != SYMBOL && *tok != STRING)
202 return error(str_error);
207 w = (WORD)(!strcmp(p, p2));
208 *evalTokenBuffer++ = CONST;
209 *evalTokenBuffer++ = (TOKEN)w;
221 // Terminals (CONSTs) and parenthesis grouping
232 *evalTokenBuffer++ = CONST;
233 *evalTokenBuffer++ = *tok++;
237 j = (*p == '.' ? curenv : 0);
238 sy = lookup(p, LABEL, j);
241 sy = NewSymbol(p, LABEL, j);
243 // Check register bank usage
244 if (sy->sattre & EQUATEDREG)
246 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
247 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
249 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
250 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
253 *evalTokenBuffer++ = SYMBOL;
254 *evalTokenBuffer++ = symbolNum;
255 symbolPtr[symbolNum] = sy;
259 *evalTokenBuffer++ = CONST;
260 *evalTokenBuffer++ = str_value(string[*tok++]);
267 return error("missing close parenthesis ')'");
275 return error("missing close parenthesis ']'");
279 *evalTokenBuffer++ = ACONST; // Attributed const
280 *evalTokenBuffer++ = sloc; // Current location
281 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
284 *evalTokenBuffer++ = ACONST; // Attributed const
286 // pcloc == location at start of line
287 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
288 // '*' takes attributes of current section, not ABS!
289 *evalTokenBuffer++ = cursect | DEFINED;
292 if (expr0() != OK) // Eat up first parameter (register or immediate)
295 if (*tok++ != ':') // Demand a ':' there
296 return error("missing colon ':'");
298 if (expr0() != OK) // Eat up second parameter (register or immediate)
302 return error("missing close bracket '}'");
306 return error("bad expression");
314 // Recursive-descent expression analyzer (with some simple speed hacks)
316 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
318 // Passed in values (once derefenced, that is) can all be zero. They are
319 // there so that the expression analyzer can fill them in as needed. The
320 // expression analyzer gets its input from the global token pointer "tok",
321 // and not from anything passed in by the user.
326 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
327 // Also set in various other places too (riscasm.c, e.g.)
329 //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]]);
330 // Optimize for single constant or single symbol.
331 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
332 // followed by the value 101, it will trigger a bad evaluation here.
333 // This is probably a really bad assumption to be making here...!
334 // (assuming tok[1] == EOL is a single token that is)
335 // Seems that even other tokens (SUNARY type) can fuck this up too.
336 // if ((tok[1] == EOL)
337 if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
338 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
339 && (tokenClass[tok[2]] < UNARY)))
341 if (*tok >= KW_R0 && *tok <= KW_R31)
343 *evalTokenBuffer++ = CONST;
344 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
345 *a_attr = ABS | DEFINED;
352 else if (*tok == CONST)
354 *evalTokenBuffer++ = CONST;
355 *evalTokenBuffer++ = *a_value = tok[1];
356 *a_attr = ABS | DEFINED;
362 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
364 else if (*tok == '*')
366 *evalTokenBuffer++ = CONST;
369 *evalTokenBuffer++ = *a_value = orgaddr;
371 *evalTokenBuffer++ = *a_value = pcloc;
373 // '*' takes attributes of current section, not ABS!
374 *a_attr = cursect | DEFINED;
381 else if (*tok == STRING || *tok == SYMBOL)
384 j = (*p == '.' ? curenv : 0);
385 symbol = lookup(p, LABEL, j);
387 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
389 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
393 symbol = NewSymbol(p, LABEL, j);
395 symbol->sattr |= REFERENCED;
397 // Check for undefined register equates, but only if it's not part
398 // of a #<SYMBOL> construct, as it could be that the label that's
399 // been undefined may later be used as an address label--which
400 // means it will be fixed up later, and thus, not an error.
401 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
403 errors("undefined register equate '%s'", symbol->sname);
404 //if we return right away, it returns some spurious errors...
408 // Check register bank usage
409 if (symbol->sattre & EQUATEDREG)
411 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
412 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
414 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
415 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
418 *evalTokenBuffer++ = SYMBOL;
420 *evalTokenBuffer++ = (TOKEN)symbol;
423 While this approach works, it's wasteful. It would be better to use something
424 that's already available, like the symbol "order defined" table (which needs to
425 be converted from a linked list into an array).
427 *evalTokenBuffer++ = symbolNum;
428 symbolPtr[symbolNum] = symbol;
432 if (symbol->sattr & DEFINED)
433 *a_value = symbol->svalue;
438 All that extra crap that was put into the svalue when doing the equr stuff is
439 thrown away right here. What the hell is it for?
441 if (symbol->sattre & EQUATEDREG)
444 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
446 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
454 // Unknown type here... Alert the user!,
455 error("undefined RISC register in expression");
456 // Prevent spurious error reporting...
461 *evalTokenBuffer++ = ENDEXPR;
468 *evalTokenBuffer++ = ENDEXPR;
469 return evexpr(otk, a_value, a_attr, a_esym);
474 // Evaluate expression.
475 // If the expression involves only ONE external symbol, the expression is
476 // UNDEFINED, but it's value includes everything but the symbol value, and
477 // `a_esym' is set to the external symbol.
479 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
483 VALUE * sval = evstk; // (Empty) initial stack
484 WORD * sattr = evattr;
485 SYM * esym = NULL; // No external symbol involved
488 while (*tk != ENDEXPR)
493 //printf("evexpr(): SYMBOL\n");
494 sy = symbolPtr[*tk++];
495 sy->sattr |= REFERENCED; // Set "referenced" bit
497 if (!(sy->sattr & DEFINED))
499 // Reference to undefined symbol
500 if (!(sy->sattr & GLOBAL))
507 if (esym != NULL) // Check for multiple externals
508 return error(seg_error);
513 if (sy->sattr & DEFINED)
515 *++sval = sy->svalue; // Push symbol's value
519 *++sval = 0; // 0 for undefined symbols
522 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
523 sym_seg = (WORD)(sy->sattr & TDB);
526 //printf("evexpr(): CONST = %i\n", *tk);
527 *++sval = *tk++; // Push value
528 *++sattr = ABS | DEFINED; // Push simple attribs
531 //printf("evexpr(): ACONST = %i\n", *tk);
532 *++sval = *tk++; // Push value
533 *++sattr = (WORD)*tk++; // Push attribs
536 // Binary "+" and "-" matrix:
539 // ----------------------------
540 // ABS | ABS | Sect | Other |
541 // Sect | Sect | [1] | Error |
542 // Other | Other | Error | [1] |
543 // ----------------------------
548 //printf("evexpr(): +\n");
550 --sattr; // Pop attrib
551 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
552 *sval += sval[1]; // Compute value
553 //printf("%i\n", *sval);
557 else if (sattr[1] & TDB)
558 return error(seg_error);
562 //printf("evexpr(): -\n");
564 --sattr; // Pop attrib
565 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
566 *sval -= sval[1]; // Compute value
567 //printf("%i\n", *sval);
569 attr = (WORD)(*sattr & TDB);
571 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
573 // If symbol1 is ABS, take attributes from symbol2
576 // Otherwise, they're both TDB and so attributes cancel out
577 else if (sattr[1] & TDB)
581 // Unary operators only work on ABS items
583 //printf("evexpr(): UNMINUS\n");
588 *sattr = ABS | DEFINED; // Expr becomes absolute
591 //printf("evexpr(): !\n");
596 *sattr = ABS | DEFINED; // Expr becomes absolute
599 //printf("evexpr(): ~\n");
604 *sattr = ABS | DEFINED; // Expr becomes absolute
606 // Comparison operators must have two values that
607 // are in the same segment, but that's the only requirement.
609 //printf("evexpr(): LE\n");
613 if ((*sattr & TDB) != (sattr[1] & TDB))
616 *sattr = ABS | DEFINED;
617 *sval = *sval <= sval[1];
620 //printf("evexpr(): GE\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(): <\n");
646 if ((*sattr & TDB) != (sattr[1] & TDB))
649 *sattr = ABS | DEFINED;
650 *sval = *sval < sval[1];
653 //printf("evexpr(): NE\n");
657 if ((*sattr & TDB) != (sattr[1] & TDB))
660 *sattr = ABS | DEFINED;
661 *sval = *sval != sval[1];
664 //printf("evexpr(): =\n");
668 if ((*sattr & TDB) != (sattr[1] & TDB))
671 *sattr = ABS | DEFINED;
672 *sval = *sval == sval[1];
674 // All other binary operators must have two ABS items
675 // to work with. They all produce an ABS value.
677 //printf("evexpr(): default\n");
678 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
679 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
681 *sattr = ABS | DEFINED; // Expr becomes absolute
687 sattr--; // Pop attrib
688 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
690 //printf("%i\n", *sval);
694 sattr--; // Pop attrib
697 return error("divide by zero");
699 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
700 // Compiler is picky here: Without casting these, it discards
701 // the sign if dividing a negative # by a positive one,
702 // creating a bad result. :-/
703 // Probably a side effect of using VALUE intead of ints.
704 *sval = (int)sval[0] / (int)sval[1];
705 //printf("%i\n", *sval);
709 sattr--; // Pop attrib
712 return error("mod (%) by zero");
718 sattr--; // Pop attrib
723 sattr--; // Pop attrib
728 sattr--; // Pop attrib
733 sattr--; // Pop attrib
738 sattr--; // Pop attrib
742 interror(5); // Bad operator in expression stream
753 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
754 // expressions where absolute values also existed. The absolutes were
755 // overiding the symbol segments and not being included :(
756 //*a_attr = *sattr | sym_seg; // Copy value + attrib
758 *a_attr = *sattr; // Copy value + attrib