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;
338 else if (*tok == '*')
340 *evalTokenBuffer++ = CONST;
343 *evalTokenBuffer++ = *a_value = orgaddr;
345 *evalTokenBuffer++ = *a_value = pcloc;
347 *a_attr = ABS | DEFINED;
354 else if (*tok == STRING || *tok == SYMBOL)
357 j = (*p == '.' ? curenv : 0);
358 symbol = lookup(p, LABEL, j);
361 symbol = NewSymbol(p, LABEL, j);
363 symbol->sattr |= REFERENCED;
365 // Check for undefined register equates
366 if (symbol->sattre & UNDEF_EQUR)
368 errors("undefined register equate '%s'", symbol->sname);
369 //if we return right away, it returns some spurious errors...
373 // Check register bank usage
374 if (symbol->sattre & EQUATEDREG)
376 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
377 warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
379 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
380 warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
383 *evalTokenBuffer++ = SYMBOL;
385 *evalTokenBuffer++ = (TOKEN)symbol;
388 While this approach works, it's wasteful. It would be better to use something
389 that's already available, like the symbol "order defined" table (which needs to
390 be converted from a linked list into an array).
392 *evalTokenBuffer++ = symbolNum;
393 symbolPtr[symbolNum] = symbol;
397 if (symbol->sattr & DEFINED)
398 *a_value = symbol->svalue;
403 All that extra crap that was put into the svalue when doing the equr stuff is
404 thrown away right here. What the hell is it for?
406 if (symbol->sattre & EQUATEDREG)
409 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
411 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL && a_esym != NULL)
416 // Unknown type here... Alert the user!
417 error("undefined RISC register in expression");
423 *evalTokenBuffer++ = ENDEXPR;
430 *evalTokenBuffer++ = ENDEXPR;
431 return evexpr(otk, a_value, a_attr, a_esym);
436 // Evaluate expression.
437 // If the expression involves only ONE external symbol, the expression is
438 // UNDEFINED, but it's value includes everything but the symbol value, and
439 // `a_esym' is set to the external symbol.
441 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
450 sval = evstk; // (Empty) initial stack
452 esym = NULL; // No external symbol involved
455 while (*tk != ENDEXPR)
460 // sy = (SYM *)*tk++;
461 sy = symbolPtr[*tk++];
462 sy->sattr |= REFERENCED; // Set "referenced" bit
464 if (!(sy->sattr & DEFINED))
466 // Reference to undefined symbol
467 if (!(sy->sattr & GLOBAL))
474 if (esym != NULL) // Check for multiple externals
475 return error(seg_error);
480 if (sy->sattr & DEFINED)
482 *++sval = sy->svalue; // Push symbol's value
486 *++sval = 0; // 0 for undefined symbols
489 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
490 sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
493 *++sval = *tk++; // Push value
494 *++sattr = ABS | DEFINED; // Push simple attribs
497 *++sval = *tk++; // Push value
498 *++sattr = (WORD)*tk++; // Push attribs
501 // Binary "+" and "-" matrix:
504 // ----------------------------
505 // ABS | ABS | Sect | Other |
506 // Sect | Sect | [1] | Error |
507 // Other | Other | Error | [1] |
508 // ----------------------------
514 --sattr; // Pop attrib
515 *sval += sval[1]; // Compute value
517 if (!(*sattr & (TEXT | DATA | BSS)))
519 else if (sattr[1] & (TEXT | DATA | BSS))
520 return error(seg_error);
525 --sattr; // Pop attrib
526 *sval -= sval[1]; // Compute value
528 attr = (WORD)(*sattr & (TEXT | DATA | BSS));
532 else if (sattr[1] & (TEXT | DATA | BSS))
534 if (!(attr & sattr[1]))
535 return error(seg_error);
537 *sattr &= ~(TEXT | DATA | BSS);
541 // Unary operators only work on ABS items
543 if (*sattr & (TEXT | DATA | BSS))
547 *sattr = ABS | DEFINED; // Expr becomes absolute
550 if (*sattr & (TEXT | DATA | BSS))
554 *sattr = ABS | DEFINED; // Expr becomes absolute
557 if (*sattr & (TEXT | DATA | BSS))
561 *sattr = ABS | DEFINED; // Expr becomes absolute
563 // Comparison operators must have two values that
564 // are in the same segment, but that's the only requirement.
569 if ((*sattr & TDB) != (sattr[1] & TDB))
572 *sattr = ABS | DEFINED;
573 *sval = *sval <= sval[1];
579 if ((*sattr & TDB) != (sattr[1] & TDB))
582 *sattr = ABS | DEFINED;
583 *sval = *sval >= sval[1];
589 if ((*sattr & TDB) != (sattr[1] & TDB))
592 *sattr = ABS | DEFINED;
593 *sval = *sval > sval[1];
599 if ((*sattr & TDB) != (sattr[1] & TDB))
602 *sattr = ABS | DEFINED;
603 *sval = *sval < sval[1];
609 if ((*sattr & TDB) != (sattr[1] & TDB))
612 *sattr = ABS | DEFINED;
613 *sval = *sval != sval[1];
619 if ((*sattr & TDB) != (sattr[1] & TDB))
622 *sattr = ABS | DEFINED;
623 *sval = *sval == sval[1];
625 // All other binary operators must have two ABS items
626 // to work with. They all produce an ABS value.
628 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
629 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
631 *sattr = ABS | DEFINED; // Expr becomes absolute
637 --sattr; // Pop attrib
642 --sattr; // Pop attrib
645 return error("divide by zero");
651 --sattr; // Pop attrib
654 return error("mod (%) by zero");
660 --sattr; // Pop attrib
665 --sattr; // Pop attrib
670 --sattr; // Pop attrib
675 --sattr; // Pop attrib
680 --sattr; // Pop attrib
684 interror(5); // Bad operator in expression stream
695 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
696 // expressions where absolute values also existed. The absolutes were
697 // overiding the symbol segments and not being included :(
698 //*a_attr = *sattr | sym_seg; // Copy value + attrib
700 *a_attr = *sattr; // Copy value + attrib