2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-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 uint64_t 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 uint32_t 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++ = 0; // Set HI LONG to zero
158 *evalTokenBuffer++ = (LONG)sect[ABS].sloc;
161 *evalTokenBuffer++ = CONST;
162 *evalTokenBuffer++ = 0; // Set HI LONG to zero
163 *evalTokenBuffer++ = dos_time();
166 *evalTokenBuffer++ = CONST;
167 *evalTokenBuffer++ = 0; // Set HI LONG to zero
168 *evalTokenBuffer++ = dos_date();
170 case CR_MACDEF: // ^^macdef <macro-name>
171 if (*tok++ != SYMBOL)
172 return error(missym_error);
175 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
176 *evalTokenBuffer++ = CONST;
177 *evalTokenBuffer++ = 0; // Set HI LONG to zero
178 *evalTokenBuffer++ = (TOKEN)w;
186 if (*tok++ != SYMBOL)
187 return error(missym_error);
190 j = (*p == '.' ? curenv : 0);
191 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
192 *evalTokenBuffer++ = CONST;
193 *evalTokenBuffer++ = 0; // Set HI LONG to zero
194 *evalTokenBuffer++ = (TOKEN)w;
197 if (*tok != SYMBOL && *tok != STRING)
198 return error(str_error);
204 return error(comma_error);
206 if (*tok != SYMBOL && *tok != STRING)
207 return error(str_error);
212 w = (WORD)(!strcmp(p, p2));
213 *evalTokenBuffer++ = CONST;
214 *evalTokenBuffer++ = 0; // Set HI LONG to zero
215 *evalTokenBuffer++ = (TOKEN)w;
227 // Terminals (CONSTs) and parenthesis grouping
238 *evalTokenBuffer++ = CONST;
239 *evalTokenBuffer++ = *tok++; // HI LONG of constant
240 *evalTokenBuffer++ = *tok++; // LO LONG of constant
244 j = (*p == '.' ? curenv : 0);
245 sy = lookup(p, LABEL, j);
248 sy = NewSymbol(p, LABEL, j);
250 // Check register bank usage
251 if (sy->sattre & EQUATEDREG)
253 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
254 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
256 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
257 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
260 *evalTokenBuffer++ = SYMBOL;
261 *evalTokenBuffer++ = symbolNum;
262 symbolPtr[symbolNum] = sy;
266 *evalTokenBuffer++ = CONST;
267 *evalTokenBuffer++ = 0; // Set HI LONG to zero
268 *evalTokenBuffer++ = str_value(string[*tok++]);
275 return error("missing closing parenthesis ')'");
283 return error("missing closing bracket ']'");
287 *evalTokenBuffer++ = ACONST; // Attributed const
288 *evalTokenBuffer++ = sloc; // Current location
289 *evalTokenBuffer++ = cursect | DEFINED; // Store attribs
292 *evalTokenBuffer++ = ACONST; // Attributed const
294 // pcloc == location at start of line
295 *evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
296 // '*' takes attributes of current section, not ABS!
297 *evalTokenBuffer++ = cursect | DEFINED;
300 if (expr0() != OK) // Eat up first parameter (register or immediate)
303 if (*tok++ != ':') // Demand a ':' there
304 return error("missing colon ':'");
306 if (expr0() != OK) // Eat up second parameter (register or immediate)
310 return error("missing closing brace '}'");
314 return error("bad expression");
322 // Recursive-descent expression analyzer (with some simple speed hacks)
324 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
326 // Passed in values (once derefenced, that is) can all be zero. They are
327 // there so that the expression analyzer can fill them in as needed. The
328 // expression analyzer gets its input from the global token pointer "tok",
329 // and not from anything passed in by the user.
334 evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
335 // Also set in various other places too (riscasm.c,
338 //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]]);
339 // Optimize for single constant or single symbol.
340 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
341 // followed by the value 101, it will trigger a bad evaluation here.
342 // This is probably a really bad assumption to be making here...!
343 // (assuming tok[1] == EOL is a single token that is)
344 // Seems that even other tokens (SUNARY type) can fuck this up too.
345 // if ((tok[1] == EOL)
346 if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
347 // || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
348 // && (tokenClass[tok[2]] < UNARY)))
349 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
350 && (tokenClass[tok[2]] < UNARY))
351 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
354 if (*tok >= KW_R0 && *tok <= KW_R31)
356 *evalTokenBuffer++ = CONST;
357 *evalTokenBuffer++ = 0; // Set HI LONG to zero
358 *evalTokenBuffer++ = *a_value = (*tok - KW_R0);
359 *a_attr = ABS | DEFINED;
366 else if (*tok == CONST)
368 *evalTokenBuffer++ = CONST;
369 *evalTokenBuffer++ = tok[1];
370 *evalTokenBuffer++ = tok[2];
371 *a_value = (((uint64_t)tok[1]) << 32) | tok[2];
372 *a_attr = ABS | DEFINED;
378 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
380 else if (*tok == '*')
382 *evalTokenBuffer++ = CONST;
383 *evalTokenBuffer++ = 0; // Set HI LONG to zero
386 *evalTokenBuffer++ = *a_value = orgaddr;
388 *evalTokenBuffer++ = *a_value = pcloc;
390 // '*' takes attributes of current section, not ABS!
391 *a_attr = cursect | DEFINED;
398 else if (*tok == STRING || *tok == SYMBOL)
401 j = (*p == '.' ? curenv : 0);
402 symbol = lookup(p, LABEL, j);
404 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
406 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
410 symbol = NewSymbol(p, LABEL, j);
412 symbol->sattr |= REFERENCED;
414 // Check for undefined register equates, but only if it's not part
415 // of a #<SYMBOL> construct, as it could be that the label that's
416 // been undefined may later be used as an address label--which
417 // means it will be fixed up later, and thus, not an error.
418 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
420 error("undefined register equate '%s'", symbol->sname);
421 //if we return right away, it returns some spurious errors...
425 // Check register bank usage
426 if (symbol->sattre & EQUATEDREG)
428 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
429 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
431 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
432 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
435 *evalTokenBuffer++ = SYMBOL;
437 *evalTokenBuffer++ = (TOKEN)symbol;
440 While this approach works, it's wasteful. It would be better to use something
441 that's already available, like the symbol "order defined" table (which needs to
442 be converted from a linked list into an array).
444 *evalTokenBuffer++ = symbolNum;
445 symbolPtr[symbolNum] = symbol;
449 if (symbol->sattr & DEFINED)
450 *a_value = symbol->svalue;
455 All that extra crap that was put into the svalue when doing the equr stuff is
456 thrown away right here. What the hell is it for?
458 if (symbol->sattre & EQUATEDREG)
461 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
463 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
471 // Unknown type here... Alert the user!,
472 error("undefined RISC register in expression");
473 // Prevent spurious error reporting...
478 *evalTokenBuffer++ = ENDEXPR;
485 *evalTokenBuffer++ = ENDEXPR;
486 return evexpr(otk, a_value, a_attr, a_esym);
491 // Evaluate expression.
492 // If the expression involves only ONE external symbol, the expression is
493 // UNDEFINED, but it's value includes everything but the symbol value, and
494 // `a_esym' is set to the external symbol.
496 int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
500 uint64_t * sval = evstk; // (Empty) initial stack
501 WORD * sattr = evattr;
502 SYM * esym = NULL; // No external symbol involved
505 while (*tk != ENDEXPR)
510 //printf("evexpr(): SYMBOL\n");
511 sy = symbolPtr[*tk++];
512 sy->sattr |= REFERENCED; // Set "referenced" bit
514 if (!(sy->sattr & DEFINED))
516 // Reference to undefined symbol
517 if (!(sy->sattr & GLOBAL))
524 if (esym != NULL) // Check for multiple externals
525 return error(seg_error);
530 if (sy->sattr & DEFINED)
532 *++sval = sy->svalue; // Push symbol's value
536 *++sval = 0; // 0 for undefined symbols
539 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
540 sym_seg = (WORD)(sy->sattr & TDB);
543 *++sval = ((uint64_t)*tk++) << 32; // Push value
544 *sval |= *tk++; // & LO LONG (will this work???--should)
545 //printf("evexpr(): CONST = %lX\n", *sval);
546 *++sattr = ABS | DEFINED; // Push simple attribs
549 //printf("evexpr(): ACONST = %i\n", *tk);
550 *++sval = *tk++; // Push value
551 *++sattr = (WORD)*tk++; // Push attribs
554 // Binary "+" and "-" matrix:
557 // ----------------------------
558 // ABS | ABS | Sect | Other |
559 // Sect | Sect | [1] | Error |
560 // Other | Other | Error | [1] |
561 // ----------------------------
566 //printf("evexpr(): +\n");
568 --sattr; // Pop attrib
569 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
570 *sval += sval[1]; // Compute value
571 //printf("%i\n", *sval);
575 else if (sattr[1] & TDB)
576 return error(seg_error);
580 //printf("evexpr(): -\n");
582 --sattr; // Pop attrib
583 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
584 *sval -= sval[1]; // Compute value
585 //printf("%i\n", *sval);
587 attr = (WORD)(*sattr & TDB);
589 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
591 // If symbol1 is ABS, take attributes from symbol2
594 // Otherwise, they're both TDB and so attributes cancel out
595 else if (sattr[1] & TDB)
599 // Unary operators only work on ABS items
601 //printf("evexpr(): UNMINUS\n");
606 *sattr = ABS | DEFINED; // Expr becomes absolute
609 //printf("evexpr(): !\n");
614 *sattr = ABS | DEFINED; // Expr becomes absolute
617 //printf("evexpr(): ~\n");
622 *sattr = ABS | DEFINED; // Expr becomes absolute
624 // Comparison operators must have two values that
625 // are in the same segment, but that's the only requirement.
627 //printf("evexpr(): LE\n");
631 if ((*sattr & TDB) != (sattr[1] & TDB))
634 *sattr = ABS | DEFINED;
635 *sval = *sval <= sval[1];
638 //printf("evexpr(): GE\n");
642 if ((*sattr & TDB) != (sattr[1] & TDB))
645 *sattr = ABS | DEFINED;
646 *sval = *sval >= sval[1];
649 //printf("evexpr(): >\n");
653 if ((*sattr & TDB) != (sattr[1] & TDB))
656 *sattr = ABS | DEFINED;
657 *sval = *sval > sval[1];
660 //printf("evexpr(): <\n");
664 if ((*sattr & TDB) != (sattr[1] & TDB))
667 *sattr = ABS | DEFINED;
668 *sval = *sval < sval[1];
671 //printf("evexpr(): NE\n");
675 if ((*sattr & TDB) != (sattr[1] & TDB))
678 *sattr = ABS | DEFINED;
679 *sval = *sval != sval[1];
682 //printf("evexpr(): =\n");
686 if ((*sattr & TDB) != (sattr[1] & TDB))
689 *sattr = ABS | DEFINED;
690 *sval = *sval == sval[1];
692 // All other binary operators must have two ABS items
693 // to work with. They all produce an ABS value.
695 //printf("evexpr(): default\n");
696 // GH - Removed for v1.0.15 as part of the fix for indexed loads.
697 //if ((*sattr & (TEXT|DATA|BSS)) || (*--sattr & (TEXT|DATA|BSS)))
699 *sattr = ABS | DEFINED; // Expr becomes absolute
705 sattr--; // Pop attrib
706 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
708 //printf("%i\n", *sval);
712 sattr--; // Pop attrib
715 return error("division by zero");
717 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
718 // Compiler is picky here: Without casting these, it discards
719 // the sign if dividing a negative # by a positive one,
720 // creating a bad result. :-/
721 // Definitely a side effect of using uint32_ts intead of ints.
722 *sval = (int32_t)sval[0] / (int32_t)sval[1];
723 //printf("%i\n", *sval);
727 sattr--; // Pop attrib
730 return error("mod (%) by zero");
736 sattr--; // Pop attrib
741 sattr--; // Pop attrib
746 sattr--; // Pop attrib
751 sattr--; // Pop attrib
756 sattr--; // Pop attrib
760 interror(5); // Bad operator in expression stream
771 // sym_seg added in 1.0.16 to solve a problem with forward symbols in
772 // expressions where absolute values also existed. The absolutes were
773 // overiding the symbol segments and not being included :(
774 //*a_attr = *sattr | sym_seg; // Copy value + attrib
776 *a_attr = *sattr; // Copy value + attrib