2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2018 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, FCONST, SYMBOL, 0, // ID
33 '(', '[', '{', 0, // OPAR
34 ')', ']', '}', 0, // CPAR
35 CR_DEFINED, CR_REFERENCED, // SUNARY (special unary)
39 '!', '~', UNMINUS, UNLT, UNGT, 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";
52 const char noflt_error[] = "operator not usable with float";
54 // Convert expression to postfix
55 static PTR evalTokenBuffer; // Deposit tokens here (this is really a
56 // pointer to exprbuf from direct.c)
57 // (Can also be from others, like
59 static int symbolNum; // Pointer to the entry in symbolPtr[]
63 // Obtain a string value
65 static uint32_t str_value(char * p)
70 v = (v << 8) | (*p & 0xFF);
77 // Initialize expression analyzer
79 void InitExpression(void)
81 // Initialize token-class table (all set to END)
82 for(int i=0; i<256; i++)
87 for(char * p=itokcl; *p!=1; p++)
92 tokenClass[(int)(*p)] = (char)i;
100 // Binary operators (all the same precedence)
107 while (tokenClass[*tok] >= MULT)
114 *evalTokenBuffer.u32++ = t;
122 // Unary operators (detect unary '-')
123 // ggn: If expression starts with a plus then also eat it up. For some reason
124 // the parser gets confused when this happens and emits a "bad
132 int class = tokenClass[*tok];
134 if (*tok == '-' || *tok == '+' || *tok == '<' || *tok == '>' || class == UNARY)
148 // With leading + we don't have to deposit anything to the buffer
149 // because there's no unary '+' nor we have to do anything about it
151 *evalTokenBuffer.u32++ = t;
153 else if (class == SUNARY)
158 *evalTokenBuffer.u32++ = CONST;
159 *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc;
162 *evalTokenBuffer.u32++ = CONST;
163 *evalTokenBuffer.u64++ = dos_time();
166 *evalTokenBuffer.u32++ = CONST;
167 *evalTokenBuffer.u64++ = dos_date();
169 case CR_MACDEF: // ^^macdef <macro-name>
170 if (*tok++ != SYMBOL)
171 return error(missym_error);
174 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
175 *evalTokenBuffer.u32++ = CONST;
176 *evalTokenBuffer.u64++ = (uint64_t)w;
184 if (*tok++ != SYMBOL)
185 return error(missym_error);
188 int j = (*p == '.' ? curenv : 0);
189 SYM * sy = lookup(p, LABEL, j);
190 w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
191 *evalTokenBuffer.u32++ = CONST;
192 *evalTokenBuffer.u64++ = (uint64_t)w;
195 if (*tok != SYMBOL && *tok != STRING)
196 return error(str_error);
202 return error(comma_error);
204 if (*tok != SYMBOL && *tok != STRING)
205 return error(str_error);
207 char * p2 = string[tok[1]];
210 w = (WORD)(!strcmp(p, p2));
211 *evalTokenBuffer.u32++ = CONST;
212 *evalTokenBuffer.u64++ = (uint64_t)w;
224 // Terminals (CONSTs) and parenthesis grouping
234 *evalTokenBuffer.u32++ = CONST;
235 *evalTokenBuffer.u64++ = *ptk.u64++;
240 *evalTokenBuffer.u32++ = FCONST;
241 *evalTokenBuffer.u64++ = *ptk.u64++;
246 char * p = string[*tok++];
247 int j = (*p == '.' ? curenv : 0);
248 SYM * sy = lookup(p, LABEL, j);
251 sy = NewSymbol(p, LABEL, j);
253 // Check register bank usage
254 if (sy->sattre & EQUATEDREG)
256 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
257 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
259 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
260 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
263 *evalTokenBuffer.u32++ = SYMBOL;
264 *evalTokenBuffer.u32++ = symbolNum;
265 symbolPtr[symbolNum] = sy;
270 *evalTokenBuffer.u32++ = CONST;
271 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
278 return error("missing closing parenthesis ')'");
286 return error("missing closing bracket ']'");
290 if (expr0() != OK) // Eat up first parameter (register or immediate)
293 if (*tok++ != ':') // Demand a ':' there
294 return error("missing colon ':'");
296 if (expr0() != OK) // Eat up second parameter (register or immediate)
300 return error("missing closing brace '}'");
304 *evalTokenBuffer.u32++ = ACONST; // Attributed const
305 *evalTokenBuffer.u32++ = sloc; // Current location
306 *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs
309 *evalTokenBuffer.u32++ = ACONST; // Attributed const
311 // pcloc == location at start of line
312 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
313 // '*' takes attributes of current section, not ABS!
314 *evalTokenBuffer.u32++ = cursect | DEFINED;
317 return error("bad expression");
325 // Recursive-descent expression analyzer (with some simple speed hacks)
327 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
329 // Passed in values (once derefenced, that is) can all be zero. They are
330 // there so that the expression analyzer can fill them in as needed. The
331 // expression analyzer gets its input from the global token pointer "tok",
332 // and not from anything passed in by the user.
338 evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c)
339 // Also set in various other places too (riscasm.c,
342 //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]]);
343 // Optimize for single constant or single symbol.
344 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
345 // followed by the value 101, it will trigger a bad evaluation here.
346 // This is probably a really bad assumption to be making here...!
347 // (assuming tok[1] == EOL is a single token that is)
348 // Seems that even other tokens (SUNARY type) can fuck this up too.
350 // if ((tok[1] == EOL)
351 if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
352 // || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
353 // && (tokenClass[tok[2]] < UNARY)))
354 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
355 && (tokenClass[tok[2]] < UNARY))
356 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
359 // Shamus: Seems to me that this could be greatly simplified by 1st checking if the first token is a multibyte token, *then* checking if there's an EOL after it depending on the actual length of the token (multiple vs. single). Otherwise, we have the horror show that is the following:
361 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
362 || (((tok[0] == SYMBOL)
363 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
364 && (tokenClass[tok[2]] < UNARY))
365 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
367 // Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis niavely checking tok[1] for an EOL. O_o
370 if (*tok >= KW_R0 && *tok <= KW_R31)
372 *evalTokenBuffer.u32++ = CONST;
373 *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
374 *a_attr = ABS | DEFINED;
381 else if (*tok == CONST)
384 *evalTokenBuffer.u32++ = *ptk.u32++;
385 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
386 *a_attr = ABS | DEFINED;
392 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
394 // Not sure that removing float constant here is going to break anything and/or
395 // make things significantly slower, but having this here seems to cause the
396 // complexity of the check to get to this part of the parse to go through the
397 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
399 else if (*tok == FCONST)
401 *evalTokenBuffer.u32++ = *tok++;
402 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
403 *a_attr = ABS | DEFINED | FLOAT;
408 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
411 else if (*tok == '*')
413 *evalTokenBuffer.u32++ = CONST;
416 *evalTokenBuffer.u64++ = *a_value = orgaddr;
418 *evalTokenBuffer.u64++ = *a_value = pcloc;
420 // '*' takes attributes of current section, not ABS!
421 *a_attr = cursect | DEFINED;
428 else if (*tok == STRING || *tok == SYMBOL)
431 j = (*p == '.' ? curenv : 0);
432 symbol = lookup(p, LABEL, j);
434 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
436 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
440 symbol = NewSymbol(p, LABEL, j);
442 symbol->sattr |= REFERENCED;
444 // Check for undefined register equates, but only if it's not part
445 // of a #<SYMBOL> construct, as it could be that the label that's
446 // been undefined may later be used as an address label--which
447 // means it will be fixed up later, and thus, not an error.
448 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
450 error("undefined register equate '%s'", symbol->sname);
451 //if we return right away, it returns some spurious errors...
455 // Check register bank usage
456 if (symbol->sattre & EQUATEDREG)
458 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
459 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
461 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
462 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
465 *evalTokenBuffer.u32++ = SYMBOL;
467 *evalTokenBuffer++ = (TOKEN)symbol;
470 While this approach works, it's wasteful. It would be better to use something
471 that's already available, like the symbol "order defined" table (which needs to
472 be converted from a linked list into an array).
474 *evalTokenBuffer.u32++ = symbolNum;
475 symbolPtr[symbolNum] = symbol;
479 if (symbol->sattr & DEFINED)
480 *a_value = symbol->svalue;
485 All that extra crap that was put into the svalue when doing the equr stuff is
486 thrown away right here. What the hell is it for?
488 if (symbol->sattre & EQUATEDREG)
491 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
493 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
499 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
502 *evalTokenBuffer.u32++ = *tok++;
506 // Unknown type here... Alert the user!,
507 error("undefined RISC register in expression [token=$%X]", *tok);
508 // Prevent spurious error reporting...
513 *evalTokenBuffer.u32++ = ENDEXPR;
520 *evalTokenBuffer.u32++ = ENDEXPR;
521 return evexpr(otk, a_value, a_attr, a_esym);
526 // Evaluate expression.
527 // If the expression involves only ONE external symbol, the expression is
528 // UNDEFINED, but it's value includes everything but the symbol value, and
529 // 'a_esym' is set to the external symbol.
531 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
535 uint64_t * sval = evstk; // (Empty) initial stack
536 WORD * sattr = evattr;
537 SYM * esym = NULL; // No external symbol involved
542 while (*tk.u32 != ENDEXPR)
544 switch ((int)*tk.u32++)
547 //printf("evexpr(): SYMBOL\n");
548 sy = symbolPtr[*tk.u32++];
549 sy->sattr |= REFERENCED; // Set "referenced" bit
551 if (!(sy->sattr & DEFINED))
553 // Reference to undefined symbol
554 if (!(sy->sattr & GLOBAL))
561 if (esym != NULL) // Check for multiple externals
562 return error(seg_error);
567 if (sy->sattr & DEFINED)
568 *++sval = sy->svalue; // Push symbol's value
570 *++sval = 0; // 0 for undefined symbols
572 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
573 sym_seg = (WORD)(sy->sattr & TDB);
578 //printf("evexpr(): CONST = %lX\n", *sval);
579 *++sattr = ABS | DEFINED; // Push simple attribs
583 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
584 // Even though it's a double, we can treat it like a uint64_t since
585 // we're just moving the bits around.
587 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
591 //printf("evexpr(): ACONST = %i\n", *tk.u32);
592 *++sval = *tk.u32++; // Push value
593 *++sattr = (WORD)*tk.u32++; // Push attribs
596 // Binary "+" and "-" matrix:
599 // ----------------------------
600 // ABS | ABS | Sect | Other |
601 // Sect | Sect | [1] | Error |
602 // Other | Other | Error | [1] |
603 // ----------------------------
609 //printf("evexpr(): +\n");
611 --sattr; // Pop attrib
612 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
613 // Get FLOAT attribute, if any
614 attr = (sattr[0] | sattr[1]) & FLOAT;
616 // Since adding an int to a fp value promotes it to a fp value, we
617 // don't care whether it's first or second; we cast to to a double
623 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
625 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
626 *(double *)sval = fpval1 + fpval2;
630 *sval += sval[1]; // Compute value
632 //printf("%i\n", *sval);
635 *sattr = sattr[1] | attr;
636 else if (sattr[1] & TDB)
637 return error(seg_error);
642 //printf("evexpr(): -\n");
644 --sattr; // Pop attrib
645 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
646 // Get FLOAT attribute, if any
647 attr = (sattr[0] | sattr[1]) & FLOAT;
649 // Since subtracting an int to a fp value promotes it to a fp
650 // value, we don't care whether it's first or second; we cast to to
651 // a double regardless.
656 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
658 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
659 *(double *)sval = fpval1 - fpval2;
665 //printf("%i\n", *sval);
667 *sattr |= attr; // Inherit FLOAT attribute
668 attr = (WORD)(*sattr & TDB);
670 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
672 // If symbol1 is ABS, take attributes from symbol2
675 // Otherwise, they're both TDB and so attributes cancel out
676 else if (sattr[1] & TDB)
681 // Unary operators only work on ABS items
683 //printf("evexpr(): UNMINUS\n");
685 return error(seg_error);
689 double * dst = (double *)sval;
691 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
695 *sval = -(int64_t)*sval;
696 *sattr = ABS | DEFINED; // Expr becomes absolute
701 case UNLT: // Unary < (get the low byte of a word)
702 //printf("evexpr(): UNLT\n");
704 return error(seg_error);
707 return error(noflt_error);
709 *sval = (int64_t)((*sval) & 0x00FF);
710 *sattr = ABS | DEFINED; // Expr becomes absolute
713 case UNGT: // Unary > (get the high byte of a word)
714 //printf("evexpr(): UNGT\n");
716 return error(seg_error);
719 return error(noflt_error);
721 *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
722 *sattr = ABS | DEFINED; // Expr becomes absolute
726 //printf("evexpr(): !\n");
728 return error(seg_error);
731 return error("floating point numbers not allowed with operator '!'.");
734 *sattr = ABS | DEFINED; // Expr becomes absolute
738 //printf("evexpr(): ~\n");
740 return error(seg_error);
743 return error("floating point numbers not allowed with operator '~'.");
746 *sattr = ABS | DEFINED; // Expr becomes absolute
749 // Comparison operators must have two values that
750 // are in the same segment, but that's the only requirement.
752 //printf("evexpr(): LE\n");
756 if ((*sattr & TDB) != (sattr[1] & TDB))
757 return error(seg_error);
759 // Get FLOAT attribute, if any
760 attr = (sattr[0] | sattr[1]) & FLOAT;
762 // Cast any ints in the comparison to double, if there's at least
763 // one double in the comparison.
768 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
770 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
771 *sval = (fpval1 <= fpval2);
775 *sval = (*sval <= sval[1]);
778 *sattr = ABS | DEFINED;
782 //printf("evexpr(): GE\n");
786 if ((*sattr & TDB) != (sattr[1] & TDB))
787 return error(seg_error);
789 // Get FLOAT attribute, if any
790 attr = (sattr[0] | sattr[1]) & FLOAT;
792 // Cast any ints in the comparison to double, if there's at least
793 // one double in the comparison.
798 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
800 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
801 *sval = (fpval1 >= fpval2);
805 *sval = (*sval >= sval[1]);
808 *sattr = ABS | DEFINED;
812 //printf("evexpr(): >\n");
816 if ((*sattr & TDB) != (sattr[1] & TDB))
817 return error(seg_error);
819 // Get FLOAT attribute, if any
820 attr = (sattr[0] | sattr[1]) & FLOAT;
822 // Cast any ints in the comparison to double, if there's at least
823 // one double in the comparison.
828 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
830 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
831 *sval = (fpval1 > fpval2);
835 *sval = (*sval > sval[1]);
838 *sattr = ABS | DEFINED;
842 //printf("evexpr(): <\n");
846 if ((*sattr & TDB) != (sattr[1] & TDB))
847 return error(seg_error);
849 // Get FLOAT attribute, if any
850 attr = (sattr[0] | sattr[1]) & FLOAT;
852 // Cast any ints in the comparison to double, if there's at least
853 // one double in the comparison.
858 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
860 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
861 *sval = (fpval1 < fpval2);
865 *sval = (*sval < sval[1]);
868 *sattr = ABS | DEFINED; // Expr forced to ABS
872 //printf("evexpr(): NE\n");
876 if ((*sattr & TDB) != (sattr[1] & TDB))
877 return error(seg_error);
879 // Get FLOAT attribute, if any
880 attr = (sattr[0] | sattr[1]) & FLOAT;
882 // Cast any ints in the comparison to double, if there's at least
883 // one double in the comparison.
888 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
890 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
891 *sval = (fpval1 != fpval2);
895 *sval = (*sval != sval[1]);
898 *sattr = ABS | DEFINED; // Expr forced to ABS
902 //printf("evexpr(): =\n");
906 if ((*sattr & TDB) != (sattr[1] & TDB))
907 return error(seg_error);
909 // Get FLOAT attribute, if any
910 attr = (sattr[0] | sattr[1]) & FLOAT;
912 // Cast any ints in the comparison to double, if there's at least
913 // one double in the comparison.
918 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
920 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
921 *sval = (fpval1 == fpval2);
925 *sval = (*sval == sval[1]);
928 *sattr = ABS | DEFINED; // Expr forced to ABS
932 // All other binary operators must have two ABS items to work with.
933 // They all produce an ABS value.
934 // Shamus: Is this true? There's at least one counterexample of legit
935 // code where this assumption fails to produce correct code.
937 //printf("evexpr(): default\n");
939 switch ((int)tk.u32[-1])
944 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
945 // Get FLOAT attribute, if any
946 attr = (sattr[0] | sattr[1]) & FLOAT;
948 // Since multiplying an int to a fp value promotes it to a fp
949 // value, we don't care whether it's first or second; it will
950 // be cast to a double regardless.
952 An open question here is do we promote ints to floats as signed or unsigned? It makes a difference if, say, the int is put in as -1 but is promoted to a double as $FFFFFFFFFFFFFFFF--you get very different results that way! For now, we promote as signed until proven detrimental otherwise.
958 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
960 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
961 *(double *)sval = fpval1 * fpval2;
967 //printf("%i\n", *sval);
969 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
975 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
976 // Get FLOAT attribute, if any
977 attr = (sattr[0] | sattr[1]) & FLOAT;
983 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
985 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
988 return error("divide by zero");
990 *(double *)sval = fpval1 / fpval2;
995 return error("divide by zero");
996 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
998 // Compiler is picky here: Without casting these, it
999 // discards the sign if dividing a negative # by a
1000 // positive one, creating a bad result. :-/
1001 // Definitely a side effect of using uint32_ts intead of
1003 *sval = (int32_t)sval[0] / (int32_t)sval[1];
1005 //printf("%i\n", *sval);
1007 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1014 if ((*sattr | sattr[1]) & FLOAT)
1015 return error("floating point numbers not allowed with operator '%'.");
1018 return error("mod (%) by zero");
1021 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1026 sattr--; // Pop attrib
1028 if ((*sattr | sattr[1]) & FLOAT)
1029 return error("floating point numbers not allowed with operator '<<'.");
1032 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1037 sattr--; // Pop attrib
1039 if ((*sattr | sattr[1]) & FLOAT)
1040 return error("floating point numbers not allowed with operator '>>'.");
1043 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1048 sattr--; // Pop attrib
1050 if ((*sattr | sattr[1]) & FLOAT)
1051 return error("floating point numbers not allowed with operator '&'.");
1054 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1059 sattr--; // Pop attrib
1061 if ((*sattr | sattr[1]) & FLOAT)
1062 return error("floating point numbers not allowed with operator '^'.");
1065 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1072 if ((*sattr | sattr[1]) & FLOAT)
1073 return error("floating point numbers not allowed with operator '|'.");
1076 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1080 // Bad operator in expression stream (this should never happen!)
1092 // Copy value + attrib into return variables
1101 // Count the # of tokens in the passed in expression
1102 // N.B.: 64-bit constants count as two tokens each
1104 uint16_t ExpressionLength(TOKEN * tk)
1108 for(length=0; tk[length]!=ENDEXPR; length++)
1110 // Add one to length for 2X tokens, two for 3X tokens
1111 if (tk[length] == SYMBOL)
1113 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1117 // Add 1 for ENDEXPR