2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2019 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)
160 *evalTokenBuffer.u32++ = CONST;
161 *evalTokenBuffer.u64++ = sect[ABS].sloc;
165 *evalTokenBuffer.u32++ = CONST;
166 *evalTokenBuffer.u64++ = sloc;
170 *evalTokenBuffer.u32++ = CONST;
171 *evalTokenBuffer.u64++ = dos_time();
174 *evalTokenBuffer.u32++ = CONST;
175 *evalTokenBuffer.u64++ = dos_date();
177 case CR_MACDEF: // ^^macdef <macro-name>
178 if (*tok++ != SYMBOL)
179 return error(missym_error);
182 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
183 *evalTokenBuffer.u32++ = CONST;
184 *evalTokenBuffer.u64++ = (uint64_t)w;
192 if (*tok++ != SYMBOL)
193 return error(missym_error);
196 int j = (*p == '.' ? curenv : 0);
197 SYM * sy = lookup(p, LABEL, j);
198 w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
199 *evalTokenBuffer.u32++ = CONST;
200 *evalTokenBuffer.u64++ = (uint64_t)w;
203 if (*tok != SYMBOL && *tok != STRING)
204 return error(str_error);
210 return error(comma_error);
212 if (*tok != SYMBOL && *tok != STRING)
213 return error(str_error);
215 char * p2 = string[tok[1]];
218 w = (WORD)(!strcmp(p, p2));
219 *evalTokenBuffer.u32++ = CONST;
220 *evalTokenBuffer.u64++ = (uint64_t)w;
232 // Terminals (CONSTs) and parenthesis grouping
242 *evalTokenBuffer.u32++ = CONST;
243 *evalTokenBuffer.u64++ = *ptk.u64++;
248 *evalTokenBuffer.u32++ = FCONST;
249 *evalTokenBuffer.u64++ = *ptk.u64++;
254 char * p = string[*tok++];
255 int j = (*p == '.' ? curenv : 0);
256 SYM * sy = lookup(p, LABEL, j);
259 sy = NewSymbol(p, LABEL, j);
261 // Check register bank usage
262 if (sy->sattre & EQUATEDREG)
264 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
265 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
267 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
268 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
271 *evalTokenBuffer.u32++ = SYMBOL;
272 *evalTokenBuffer.u32++ = symbolNum;
273 symbolPtr[symbolNum] = sy;
278 *evalTokenBuffer.u32++ = CONST;
279 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
286 return error("missing closing parenthesis ')'");
294 return error("missing closing bracket ']'");
298 if (expr0() != OK) // Eat up first parameter (register or immediate)
301 if (*tok++ != ':') // Demand a ':' there
302 return error("missing colon ':'");
304 if (expr0() != OK) // Eat up second parameter (register or immediate)
308 return error("missing closing brace '}'");
312 *evalTokenBuffer.u32++ = ACONST; // Attributed const
313 *evalTokenBuffer.u32++ = sloc; // Current location
314 *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs
317 *evalTokenBuffer.u32++ = ACONST; // Attributed const
319 // pcloc == location at start of line
320 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
321 // '*' takes attributes of current section, not ABS!
322 *evalTokenBuffer.u32++ = cursect | DEFINED;
325 return error("bad expression");
333 // Recursive-descent expression analyzer (with some simple speed hacks)
335 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
337 // Passed in values (once derefenced, that is) can all be zero. They are
338 // there so that the expression analyzer can fill them in as needed. The
339 // expression analyzer gets its input from the global token pointer "tok",
340 // and not from anything passed in by the user.
346 evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c)
347 // Also set in various other places too (riscasm.c,
350 //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]]);
351 // Optimize for single constant or single symbol.
352 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
353 // followed by the value 101, it will trigger a bad evaluation here.
354 // This is probably a really bad assumption to be making here...!
355 // (assuming tok[1] == EOL is a single token that is)
356 // Seems that even other tokens (SUNARY type) can fuck this up too.
358 // if ((tok[1] == EOL)
359 if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
360 // || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
361 // && (tokenClass[tok[2]] < UNARY)))
362 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
363 && (tokenClass[tok[2]] < UNARY))
364 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
367 // 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:
369 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
370 || (((tok[0] == SYMBOL)
371 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
372 && (tokenClass[tok[2]] < UNARY))
373 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
375 // 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
378 if (*tok >= KW_R0 && *tok <= KW_R31)
380 *evalTokenBuffer.u32++ = CONST;
381 *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
382 *a_attr = ABS | DEFINED;
389 else if (*tok == CONST)
392 *evalTokenBuffer.u32++ = *ptk.u32++;
393 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
394 *a_attr = ABS | DEFINED;
400 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
402 // Not sure that removing float constant here is going to break anything and/or
403 // make things significantly slower, but having this here seems to cause the
404 // complexity of the check to get to this part of the parse to go through the
405 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
407 else if (*tok == FCONST)
409 *evalTokenBuffer.u32++ = *tok++;
410 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
411 *a_attr = ABS | DEFINED | FLOAT;
416 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
419 else if (*tok == '*')
421 *evalTokenBuffer.u32++ = CONST;
424 *evalTokenBuffer.u64++ = *a_value = orgaddr;
426 *evalTokenBuffer.u64++ = *a_value = pcloc;
428 // '*' takes attributes of current section, not ABS!
429 *a_attr = cursect | DEFINED;
436 else if (*tok == STRING || *tok == SYMBOL)
439 j = (*p == '.' ? curenv : 0);
440 symbol = lookup(p, LABEL, j);
442 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
444 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
448 symbol = NewSymbol(p, LABEL, j);
450 symbol->sattr |= REFERENCED;
452 // Check for undefined register equates, but only if it's not part
453 // of a #<SYMBOL> construct, as it could be that the label that's
454 // been undefined may later be used as an address label--which
455 // means it will be fixed up later, and thus, not an error.
456 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
458 error("undefined register equate '%s'", symbol->sname);
459 //if we return right away, it returns some spurious errors...
463 // Check register bank usage
464 if (symbol->sattre & EQUATEDREG)
466 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
467 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
469 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
470 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
473 *evalTokenBuffer.u32++ = SYMBOL;
475 *evalTokenBuffer++ = (TOKEN)symbol;
478 While this approach works, it's wasteful. It would be better to use something
479 that's already available, like the symbol "order defined" table (which needs to
480 be converted from a linked list into an array).
482 *evalTokenBuffer.u32++ = symbolNum;
483 symbolPtr[symbolNum] = symbol;
487 if (symbol->sattr & DEFINED)
488 *a_value = symbol->svalue;
493 All that extra crap that was put into the svalue when doing the equr stuff is
494 thrown away right here. What the hell is it for?
496 if (symbol->sattre & EQUATEDREG)
499 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
501 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
507 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
510 *evalTokenBuffer.u32++ = *tok++;
514 // Unknown type here... Alert the user!,
515 error("undefined RISC register in expression [token=$%X]", *tok);
516 // Prevent spurious error reporting...
521 *evalTokenBuffer.u32++ = ENDEXPR;
528 *evalTokenBuffer.u32++ = ENDEXPR;
529 return evexpr(otk, a_value, a_attr, a_esym);
534 // Evaluate expression.
535 // If the expression involves only ONE external symbol, the expression is
536 // UNDEFINED, but it's value includes everything but the symbol value, and
537 // 'a_esym' is set to the external symbol.
539 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
543 uint64_t * sval = evstk; // (Empty) initial stack
544 WORD * sattr = evattr;
545 SYM * esym = NULL; // No external symbol involved
550 while (*tk.u32 != ENDEXPR)
552 switch ((int)*tk.u32++)
555 //printf("evexpr(): SYMBOL\n");
556 sy = symbolPtr[*tk.u32++];
557 sy->sattr |= REFERENCED; // Set "referenced" bit
559 if (!(sy->sattr & DEFINED))
561 // Reference to undefined symbol
562 if (!(sy->sattr & GLOBAL))
569 if (esym != NULL) // Check for multiple externals
570 return error(seg_error);
575 if (sy->sattr & DEFINED)
576 *++sval = sy->svalue; // Push symbol's value
578 *++sval = 0; // 0 for undefined symbols
580 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
581 sym_seg = (WORD)(sy->sattr & TDB);
586 //printf("evexpr(): CONST = %lX\n", *sval);
587 *++sattr = ABS | DEFINED; // Push simple attribs
591 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
592 // Even though it's a double, we can treat it like a uint64_t since
593 // we're just moving the bits around.
595 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
599 //printf("evexpr(): ACONST = %i\n", *tk.u32);
600 *++sval = *tk.u32++; // Push value
601 *++sattr = (WORD)*tk.u32++; // Push attribs
604 // Binary "+" and "-" matrix:
607 // ----------------------------
608 // ABS | ABS | Sect | Other |
609 // Sect | Sect | [1] | Error |
610 // Other | Other | Error | [1] |
611 // ----------------------------
617 //printf("evexpr(): +\n");
619 --sattr; // Pop attrib
620 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
621 // Get FLOAT attribute, if any
622 attr = (sattr[0] | sattr[1]) & FLOAT;
624 // Since adding an int to a fp value promotes it to a fp value, we
625 // don't care whether it's first or second; we cast to to a double
631 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
633 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
634 *(double *)sval = fpval1 + fpval2;
638 *sval += sval[1]; // Compute value
640 //printf("%i\n", *sval);
643 *sattr = sattr[1] | attr;
644 else if (sattr[1] & TDB)
645 return error(seg_error);
650 //printf("evexpr(): -\n");
652 --sattr; // Pop attrib
653 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
654 // Get FLOAT attribute, if any
655 attr = (sattr[0] | sattr[1]) & FLOAT;
657 // Since subtracting an int to a fp value promotes it to a fp
658 // value, we don't care whether it's first or second; we cast to to
659 // a double regardless.
664 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
666 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
667 *(double *)sval = fpval1 - fpval2;
673 //printf("%i\n", *sval);
675 *sattr |= attr; // Inherit FLOAT attribute
676 attr = (WORD)(*sattr & TDB);
678 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
680 // If symbol1 is ABS, take attributes from symbol2
683 // Otherwise, they're both TDB and so attributes cancel out
684 else if (sattr[1] & TDB)
689 // Unary operators only work on ABS items
691 //printf("evexpr(): UNMINUS\n");
693 return error(seg_error);
697 double * dst = (double *)sval;
699 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
703 *sval = -(int64_t)*sval;
704 *sattr = ABS | DEFINED; // Expr becomes absolute
709 case UNLT: // Unary < (get the low byte of a word)
710 //printf("evexpr(): UNLT\n");
712 return error(seg_error);
715 return error(noflt_error);
717 *sval = (int64_t)((*sval) & 0x00FF);
718 *sattr = ABS | DEFINED; // Expr becomes absolute
721 case UNGT: // Unary > (get the high byte of a word)
722 //printf("evexpr(): UNGT\n");
724 return error(seg_error);
727 return error(noflt_error);
729 *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
730 *sattr = ABS | DEFINED; // Expr becomes absolute
734 //printf("evexpr(): !\n");
736 return error(seg_error);
739 return error("floating point numbers not allowed with operator '!'.");
742 *sattr = ABS | DEFINED; // Expr becomes absolute
746 //printf("evexpr(): ~\n");
748 return error(seg_error);
751 return error("floating point numbers not allowed with operator '~'.");
754 *sattr = ABS | DEFINED; // Expr becomes absolute
757 // Comparison operators must have two values that
758 // are in the same segment, but that's the only requirement.
760 //printf("evexpr(): LE\n");
764 if ((*sattr & TDB) != (sattr[1] & TDB))
765 return error(seg_error);
767 // Get FLOAT attribute, if any
768 attr = (sattr[0] | sattr[1]) & FLOAT;
770 // Cast any ints in the comparison to double, if there's at least
771 // one double in the comparison.
776 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
778 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
779 *sval = (fpval1 <= fpval2);
783 *sval = (*sval <= sval[1]);
786 *sattr = ABS | DEFINED;
790 //printf("evexpr(): GE\n");
794 if ((*sattr & TDB) != (sattr[1] & TDB))
795 return error(seg_error);
797 // Get FLOAT attribute, if any
798 attr = (sattr[0] | sattr[1]) & FLOAT;
800 // Cast any ints in the comparison to double, if there's at least
801 // one double in the comparison.
806 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
808 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
809 *sval = (fpval1 >= fpval2);
813 *sval = (*sval >= sval[1]);
816 *sattr = ABS | DEFINED;
820 //printf("evexpr(): >\n");
824 if ((*sattr & TDB) != (sattr[1] & TDB))
825 return error(seg_error);
827 // Get FLOAT attribute, if any
828 attr = (sattr[0] | sattr[1]) & FLOAT;
830 // Cast any ints in the comparison to double, if there's at least
831 // one double in the comparison.
836 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
838 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
839 *sval = (fpval1 > fpval2);
843 *sval = (*sval > sval[1]);
846 *sattr = ABS | DEFINED;
850 //printf("evexpr(): <\n");
854 if ((*sattr & TDB) != (sattr[1] & TDB))
855 return error(seg_error);
857 // Get FLOAT attribute, if any
858 attr = (sattr[0] | sattr[1]) & FLOAT;
860 // Cast any ints in the comparison to double, if there's at least
861 // one double in the comparison.
866 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
868 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
869 *sval = (fpval1 < fpval2);
873 *sval = (*sval < sval[1]);
876 *sattr = ABS | DEFINED; // Expr forced to ABS
880 //printf("evexpr(): NE\n");
884 if ((*sattr & TDB) != (sattr[1] & TDB))
885 return error(seg_error);
887 // Get FLOAT attribute, if any
888 attr = (sattr[0] | sattr[1]) & FLOAT;
890 // Cast any ints in the comparison to double, if there's at least
891 // one double in the comparison.
896 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
898 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
899 *sval = (fpval1 != fpval2);
903 *sval = (*sval != sval[1]);
906 *sattr = ABS | DEFINED; // Expr forced to ABS
910 //printf("evexpr(): =\n");
914 if ((*sattr & TDB) != (sattr[1] & TDB))
915 return error(seg_error);
917 // Get FLOAT attribute, if any
918 attr = (sattr[0] | sattr[1]) & FLOAT;
920 // Cast any ints in the comparison to double, if there's at least
921 // one double in the comparison.
926 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
928 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
929 *sval = (fpval1 == fpval2);
933 *sval = (*sval == sval[1]);
936 *sattr = ABS | DEFINED; // Expr forced to ABS
940 // All other binary operators must have two ABS items to work with.
941 // They all produce an ABS value.
942 // Shamus: Is this true? There's at least one counterexample of legit
943 // code where this assumption fails to produce correct code.
945 //printf("evexpr(): default\n");
947 switch ((int)tk.u32[-1])
952 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
953 // Get FLOAT attribute, if any
954 attr = (sattr[0] | sattr[1]) & FLOAT;
956 // Since multiplying an int to a fp value promotes it to a fp
957 // value, we don't care whether it's first or second; it will
958 // be cast to a double regardless.
960 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.
966 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
968 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
969 *(double *)sval = fpval1 * fpval2;
975 //printf("%i\n", *sval);
977 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
983 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
984 // Get FLOAT attribute, if any
985 attr = (sattr[0] | sattr[1]) & FLOAT;
991 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
993 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
996 return error("divide by zero");
998 *(double *)sval = fpval1 / fpval2;
1003 return error("divide by zero");
1004 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1006 // Compiler is picky here: Without casting these, it
1007 // discards the sign if dividing a negative # by a
1008 // positive one, creating a bad result. :-/
1009 // Definitely a side effect of using uint32_ts intead of
1011 *sval = (int32_t)sval[0] / (int32_t)sval[1];
1013 //printf("%i\n", *sval);
1015 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1022 if ((*sattr | sattr[1]) & FLOAT)
1023 return error("floating point numbers not allowed with operator '%'.");
1026 return error("mod (%) by zero");
1029 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1034 sattr--; // Pop attrib
1036 if ((*sattr | sattr[1]) & FLOAT)
1037 return error("floating point numbers not allowed with operator '<<'.");
1040 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1045 sattr--; // Pop attrib
1047 if ((*sattr | sattr[1]) & FLOAT)
1048 return error("floating point numbers not allowed with operator '>>'.");
1051 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1056 sattr--; // Pop attrib
1058 if ((*sattr | sattr[1]) & FLOAT)
1059 return error("floating point numbers not allowed with operator '&'.");
1062 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1067 sattr--; // Pop attrib
1069 if ((*sattr | sattr[1]) & FLOAT)
1070 return error("floating point numbers not allowed with operator '^'.");
1073 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1080 if ((*sattr | sattr[1]) & FLOAT)
1081 return error("floating point numbers not allowed with operator '|'.");
1084 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1088 // Bad operator in expression stream (this should never happen!)
1100 // Copy value + attrib into return variables
1109 // Count the # of tokens in the passed in expression
1110 // N.B.: 64-bit constants count as two tokens each
1112 uint16_t ExpressionLength(TOKEN * tk)
1116 for(length=0; tk[length]!=ENDEXPR; length++)
1118 // Add one to length for 2X tokens, two for 3X tokens
1119 if (tk[length] == SYMBOL)
1121 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1125 // Add 1 for ENDEXPR