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
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;
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 *evalTokenBuffer++ = ENDEXPR;
423 *evalTokenBuffer++ = ENDEXPR;
424 return evexpr(otk, a_value, a_attr, a_esym);
429 // Evaluate expression.
430 // If the expression involves only ONE external symbol, the expression is
431 // UNDEFINED, but it's value includes everything but the symbol value, and
432 // `a_esym' is set to the external symbol.
434 int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
443 sval = evstk; // (Empty) initial stack
445 esym = NULL; // No external symbol involved
448 while (*tk != ENDEXPR)
453 // sy = (SYM *)*tk++;
454 sy = symbolPtr[*tk++];
455 sy->sattr |= REFERENCED; // Set "referenced" bit
457 if (!(sy->sattr & DEFINED))
459 // Reference to undefined symbol
460 if (!(sy->sattr & GLOBAL))
467 if (esym != NULL) // Check for multiple externals
468 return error(seg_error);
473 if (sy->sattr & DEFINED)
475 *++sval = sy->svalue; // Push symbol's value
479 *++sval = 0; // 0 for undefined symbols
482 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
483 sym_seg = (WORD)(sy->sattr & (TEXT | DATA | BSS));
486 *++sval = *tk++; // Push value
487 *++sattr = ABS | DEFINED; // Push simple attribs
490 *++sval = *tk++; // Push value
491 *++sattr = (WORD)*tk++; // Push attribs
494 // Binary "+" and "-" matrix:
497 // ----------------------------
498 // ABS | ABS | Sect | Other |
499 // Sect | Sect | [1] | Error |
500 // Other | Other | Error | [1] |
501 // ----------------------------
507 --sattr; // Pop attrib
508 *sval += sval[1]; // Compute value
510 if (!(*sattr & (TEXT | DATA | BSS)))
512 else if (sattr[1] & (TEXT | DATA | BSS))
513 return error(seg_error);
518 --sattr; // Pop attrib
519 *sval -= sval[1]; // Compute value
521 attr = (WORD)(*sattr & (TEXT | DATA | BSS));
525 else if (sattr[1] & (TEXT | DATA | BSS))
527 if (!(attr & sattr[1]))
528 return error(seg_error);
530 *sattr &= ~(TEXT | DATA | BSS);
534 // Unary operators only work on ABS items
536 if (*sattr & (TEXT | DATA | BSS))
540 *sattr = ABS | DEFINED; // Expr becomes absolute
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
556 // Comparison operators must have two values that
557 // are in the same segment, but that's the only requirement.
562 if ((*sattr & TDB) != (sattr[1] & TDB))
565 *sattr = ABS | DEFINED;
566 *sval = *sval <= sval[1];
572 if ((*sattr & TDB) != (sattr[1] & TDB))
575 *sattr = ABS | DEFINED;
576 *sval = *sval >= sval[1];
582 if ((*sattr & TDB) != (sattr[1] & TDB))
585 *sattr = ABS | DEFINED;
586 *sval = *sval > sval[1];
592 if ((*sattr & TDB) != (sattr[1] & TDB))
595 *sattr = ABS | DEFINED;
596 *sval = *sval < sval[1];
602 if ((*sattr & TDB) != (sattr[1] & TDB))
605 *sattr = ABS | DEFINED;
606 *sval = *sval != sval[1];
612 if ((*sattr & TDB) != (sattr[1] & TDB))
615 *sattr = ABS | DEFINED;
616 *sval = *sval == sval[1];
618 // All other binary operators must have two ABS items
619 // to work with. They all produce an ABS value.
621 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
622 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
624 *sattr = ABS | DEFINED; // Expr becomes absolute
630 --sattr; // Pop attrib
635 --sattr; // Pop attrib
638 return error("divide by zero");
644 --sattr; // Pop attrib
647 return error("mod (%) by zero");
653 --sattr; // Pop attrib
658 --sattr; // Pop attrib
663 --sattr; // Pop attrib
668 --sattr; // Pop attrib
673 --sattr; // Pop attrib
677 interror(5); // Bad operator in expression stream
688 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
689 // expressions where absolute values also existed. The absolutes were
690 // overiding the symbol segments and not being included :(
691 //*a_attr = *sattr | sym_seg; // Copy value + attrib
693 *a_attr = *sattr; // Copy value + attrib