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)
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 '-')
125 // ggn: If expression starts with a plus then also eat it up.
126 // For some reason the parser gets confused when this happens and
127 // emits a "bad expression".
138 class = tokenClass[*tok];
140 if (*tok == '-' || *tok == '+' || class == UNARY)
150 *evalTokenBuffer++ = t;
152 else if (class == SUNARY)
157 *evalTokenBuffer++ = CONST;
158 *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
161 *evalTokenBuffer++ = CONST;
162 *evalTokenBuffer++ = dos_time();
165 *evalTokenBuffer++ = CONST;
166 *evalTokenBuffer++ = dos_date();
168 case CR_MACDEF: // ^^macdef <macro-name>
169 if (*tok++ != SYMBOL)
170 return error(missym_error);
173 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
174 *evalTokenBuffer++ = CONST;
175 *evalTokenBuffer++ = (TOKEN)w;
183 if (*tok++ != SYMBOL)
184 return error(missym_error);
187 j = (*p == '.' ? curenv : 0);
188 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
189 *evalTokenBuffer++ = CONST;
190 *evalTokenBuffer++ = (TOKEN)w;
193 if (*tok != SYMBOL && *tok != STRING)
194 return error(str_error);
200 return error(comma_error);
202 if (*tok != SYMBOL && *tok != STRING)
203 return error(str_error);
208 w = (WORD)(!strcmp(p, p2));
209 *evalTokenBuffer++ = CONST;
210 *evalTokenBuffer++ = (TOKEN)w;
222 // Terminals (CONSTs) and parenthesis grouping
233 *evalTokenBuffer++ = CONST;
234 *evalTokenBuffer++ = *tok++;
238 j = (*p == '.' ? curenv : 0);
239 sy = lookup(p, LABEL, j);
242 sy = NewSymbol(p, LABEL, j);
244 // Check register bank usage
245 if (sy->sattre & EQUATEDREG)
247 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
248 warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
250 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
251 warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
254 *evalTokenBuffer++ = SYMBOL;
255 *evalTokenBuffer++ = symbolNum;
256 symbolPtr[symbolNum] = sy;
260 *evalTokenBuffer++ = CONST;
261 *evalTokenBuffer++ = str_value(string[*tok++]);
268 return error("missing close parenthesis ')'");
276 return error("missing close parenthesis ']'");
280 *evalTokenBuffer++ = ACONST; // Attributed const
281 *evalTokenBuffer++ = sloc; // Current location
282 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
285 *evalTokenBuffer++ = ACONST; // Attributed const
287 // pcloc == location at start of line
288 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
289 // '*' takes attributes of current section, not ABS!
290 *evalTokenBuffer++ = cursect | DEFINED;
293 return error("bad expression");
301 // Recursive-descent expression analyzer (with some simple speed hacks)
303 int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
305 // Passed in values (once derefenced, that is) can all be zero. They are
306 // there so that the expression analyzer can fill them in as needed. The
307 // expression analyzer gets its input from the global token pointer "tok",
308 // and not from anything passed in by the user.
313 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
314 // Also set in various other places too (riscasm.c, e.g.)
316 //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]]);
317 // Optimize for single constant or single symbol.
318 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
319 // followed by the value 101, it will trigger a bad evaluation here.
320 // This is probably a really bad assumption to be making here...!
321 // (assuming tok[1] == EOL is a single token that is)
322 // Seems that even other tokens (SUNARY type) can fuck this up too.
323 // if ((tok[1] == EOL)
324 if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
325 || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
326 && (tokenClass[tok[2]] < UNARY)))
328 if (*tok >= KW_R0 && *tok <= KW_R31)
330 *evalTokenBuffer++ = CONST;
331 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
332 *a_attr = ABS | DEFINED;
339 else if (*tok == CONST)
341 *evalTokenBuffer++ = CONST;
342 *evalTokenBuffer++ = *a_value = tok[1];
343 *a_attr = ABS | DEFINED;
349 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
351 else if (*tok == '*')
353 *evalTokenBuffer++ = CONST;
356 *evalTokenBuffer++ = *a_value = orgaddr;
358 *evalTokenBuffer++ = *a_value = pcloc;
360 // '*' takes attributes of current section, not ABS!
361 *a_attr = cursect | DEFINED;
368 else if (*tok == STRING || *tok == SYMBOL)
371 j = (*p == '.' ? curenv : 0);
372 symbol = lookup(p, LABEL, j);
374 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
376 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
380 symbol = NewSymbol(p, LABEL, j);
382 symbol->sattr |= REFERENCED;
384 // Check for undefined register equates, but only if it's not part
385 // of a #<SYMBOL> construct, as it could be that the label that's
386 // been undefined may later be used as an address label--which
387 // means it will be fixed up later, and thus, not an error.
388 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
390 errors("undefined register equate '%s'", symbol->sname);
391 //if we return right away, it returns some spurious errors...
395 // Check register bank usage
396 if (symbol->sattre & EQUATEDREG)
398 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
399 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
401 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
402 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
405 *evalTokenBuffer++ = SYMBOL;
407 *evalTokenBuffer++ = (TOKEN)symbol;
410 While this approach works, it's wasteful. It would be better to use something
411 that's already available, like the symbol "order defined" table (which needs to
412 be converted from a linked list into an array).
414 *evalTokenBuffer++ = symbolNum;
415 symbolPtr[symbolNum] = symbol;
419 if (symbol->sattr & DEFINED)
420 *a_value = symbol->svalue;
425 All that extra crap that was put into the svalue when doing the equr stuff is
426 thrown away right here. What the hell is it for?
428 if (symbol->sattre & EQUATEDREG)
431 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
433 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
441 // Unknown type here... Alert the user!,
442 error("undefined RISC register in expression");
443 // Prevent spurious error reporting...
448 *evalTokenBuffer++ = ENDEXPR;
455 *evalTokenBuffer++ = ENDEXPR;
456 return evexpr(otk, a_value, a_attr, a_esym);
461 // Evaluate expression.
462 // If the expression involves only ONE external symbol, the expression is
463 // UNDEFINED, but it's value includes everything but the symbol value, and
464 // `a_esym' is set to the external symbol.
466 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
475 sval = evstk; // (Empty) initial stack
477 esym = NULL; // No external symbol involved
480 while (*tk != ENDEXPR)
485 //printf("evexpr(): SYMBOL\n");
486 sy = symbolPtr[*tk++];
487 sy->sattr |= REFERENCED; // Set "referenced" bit
489 if (!(sy->sattr & DEFINED))
491 // Reference to undefined symbol
492 if (!(sy->sattr & GLOBAL))
499 if (esym != NULL) // Check for multiple externals
500 return error(seg_error);
505 if (sy->sattr & DEFINED)
507 *++sval = sy->svalue; // Push symbol's value
511 *++sval = 0; // 0 for undefined symbols
514 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
515 sym_seg = (WORD)(sy->sattr & TDB);
518 //printf("evexpr(): CONST = %i\n", *tk);
519 *++sval = *tk++; // Push value
520 *++sattr = ABS | DEFINED; // Push simple attribs
523 //printf("evexpr(): ACONST = %i\n", *tk);
524 *++sval = *tk++; // Push value
525 *++sattr = (WORD)*tk++; // Push attribs
528 // Binary "+" and "-" matrix:
531 // ----------------------------
532 // ABS | ABS | Sect | Other |
533 // Sect | Sect | [1] | Error |
534 // Other | Other | Error | [1] |
535 // ----------------------------
540 //printf("evexpr(): +\n");
542 --sattr; // Pop attrib
543 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
544 *sval += sval[1]; // Compute value
545 //printf("%i\n", *sval);
549 else if (sattr[1] & TDB)
550 return error(seg_error);
554 //printf("evexpr(): -\n");
556 --sattr; // Pop attrib
557 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
558 *sval -= sval[1]; // Compute value
559 //printf("%i\n", *sval);
561 attr = (WORD)(*sattr & TDB);
563 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
565 // If symbol1 is ABS, take attributes from symbol2
568 // Otherwise, they're both TDB and so attributes cancel out
569 else if (sattr[1] & TDB)
573 // Unary operators only work on ABS items
575 //printf("evexpr(): UNMINUS\n");
580 *sattr = ABS | DEFINED; // Expr becomes absolute
583 //printf("evexpr(): !\n");
588 *sattr = ABS | DEFINED; // Expr becomes absolute
591 //printf("evexpr(): ~\n");
596 *sattr = ABS | DEFINED; // Expr becomes absolute
598 // Comparison operators must have two values that
599 // are in the same segment, but that's the only requirement.
601 //printf("evexpr(): LE\n");
605 if ((*sattr & TDB) != (sattr[1] & TDB))
608 *sattr = ABS | DEFINED;
609 *sval = *sval <= sval[1];
612 //printf("evexpr(): GE\n");
616 if ((*sattr & TDB) != (sattr[1] & TDB))
619 *sattr = ABS | DEFINED;
620 *sval = *sval >= sval[1];
623 //printf("evexpr(): >\n");
627 if ((*sattr & TDB) != (sattr[1] & TDB))
630 *sattr = ABS | DEFINED;
631 *sval = *sval > sval[1];
634 //printf("evexpr(): <\n");
638 if ((*sattr & TDB) != (sattr[1] & TDB))
641 *sattr = ABS | DEFINED;
642 *sval = *sval < sval[1];
645 //printf("evexpr(): NE\n");
649 if ((*sattr & TDB) != (sattr[1] & TDB))
652 *sattr = ABS | DEFINED;
653 *sval = *sval != sval[1];
656 //printf("evexpr(): =\n");
660 if ((*sattr & TDB) != (sattr[1] & TDB))
663 *sattr = ABS | DEFINED;
664 *sval = *sval == sval[1];
666 // All other binary operators must have two ABS items
667 // to work with. They all produce an ABS value.
669 //printf("evexpr(): default\n");
670 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
671 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
673 *sattr = ABS | DEFINED; // Expr becomes absolute
679 sattr--; // Pop attrib
680 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
682 //printf("%i\n", *sval);
686 sattr--; // Pop attrib
689 return error("divide by zero");
691 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
692 // Compiler is picky here: Without casting these, it discards
693 // the sign if dividing a negative # by a positive one,
694 // creating a bad result. :-/
695 // Probably a side effect of using VALUE intead of ints.
696 *sval = (int)sval[0] / (int)sval[1];
697 //printf("%i\n", *sval);
701 sattr--; // Pop attrib
704 return error("mod (%) by zero");
710 sattr--; // Pop attrib
715 sattr--; // Pop attrib
720 sattr--; // Pop attrib
725 sattr--; // Pop attrib
730 sattr--; // Pop attrib
734 interror(5); // Bad operator in expression stream
745 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
746 // expressions where absolute values also existed. The absolutes were
747 // overiding the symbol segments and not being included :(
748 //*a_attr = *sattr | sym_seg; // Copy value + attrib
750 *a_attr = *sattr; // Copy value + attrib