2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2021 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)
38 CR_ABSCOUNT, CR_FILESIZE, 0,
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 if (*tok++ != STRING)
171 return error("^^FILESIZE expects filename inside string");
172 *evalTokenBuffer.u32++ = CONST;
173 // @@copypasted from d_incbin, maybe factor this out somehow?
174 // Attempt to open the include file in the current directory, then (if that
175 // failed) try list of include files passed in the enviroment string or by
180 if ((fd = open(string[*tok], _OPEN_INC)) < 0)
182 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
186 // Append path char if necessary
187 if ((fd > 0) && (buf1[fd - 1] != SLASHCHAR))
188 strcat(buf1, SLASHSTRING);
190 strcat(buf1, string[*tok]);
192 if ((fd = open(buf1, _OPEN_INC)) >= 0)
196 return error("cannot open: \"%s\"", string[tok[1]]);
200 *evalTokenBuffer.u64++ = (uint64_t)lseek(fd, 0L, SEEK_END);
203 // Advance tok because of consumed string token
207 *evalTokenBuffer.u32++ = CONST;
208 *evalTokenBuffer.u64++ = dos_time();
211 *evalTokenBuffer.u32++ = CONST;
212 *evalTokenBuffer.u64++ = dos_date();
214 case CR_MACDEF: // ^^macdef <macro-name>
215 if (*tok++ != SYMBOL)
216 return error(missym_error);
219 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
220 *evalTokenBuffer.u32++ = CONST;
221 *evalTokenBuffer.u64++ = (uint64_t)w;
229 if (*tok++ != SYMBOL)
230 return error(missym_error);
233 int j = (*p == '.' ? curenv : 0);
234 SYM * sy = lookup(p, LABEL, j);
235 w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
236 *evalTokenBuffer.u32++ = CONST;
237 *evalTokenBuffer.u64++ = (uint64_t)w;
240 if (*tok != SYMBOL && *tok != STRING)
241 return error(str_error);
247 return error(comma_error);
249 if (*tok != SYMBOL && *tok != STRING)
250 return error(str_error);
252 char * p2 = string[tok[1]];
255 w = (WORD)(!strcmp(p, p2));
256 *evalTokenBuffer.u32++ = CONST;
257 *evalTokenBuffer.u64++ = (uint64_t)w;
269 // Terminals (CONSTs) and parenthesis grouping
279 *evalTokenBuffer.u32++ = CONST;
280 *evalTokenBuffer.u64++ = *ptk.u64++;
285 *evalTokenBuffer.u32++ = FCONST;
286 *evalTokenBuffer.u64++ = *ptk.u64++;
291 char * p = string[*tok++];
292 int j = (*p == '.' ? curenv : 0);
293 SYM * sy = lookup(p, LABEL, j);
296 sy = NewSymbol(p, LABEL, j);
298 // Check register bank usage
299 if (sy->sattre & EQUATEDREG)
301 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
302 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
304 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
305 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
308 *evalTokenBuffer.u32++ = SYMBOL;
309 *evalTokenBuffer.u32++ = symbolNum;
310 symbolPtr[symbolNum] = sy;
315 *evalTokenBuffer.u32++ = CONST;
316 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
323 return error("missing closing parenthesis ')'");
331 return error("missing closing bracket ']'");
335 if (expr0() != OK) // Eat up first parameter (register or immediate)
338 if (*tok++ != ':') // Demand a ':' there
339 return error("missing colon ':'");
341 if (expr0() != OK) // Eat up second parameter (register or immediate)
345 return error("missing closing brace '}'");
349 *evalTokenBuffer.u32++ = ACONST; // Attributed const
350 *evalTokenBuffer.u32++ = sloc; // Current location
351 *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs
354 *evalTokenBuffer.u32++ = ACONST; // Attributed const
356 // pcloc == location at start of line
357 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
358 // '*' takes attributes of current section, not ABS!
359 *evalTokenBuffer.u32++ = cursect | DEFINED;
362 return error("bad expression");
370 // Recursive-descent expression analyzer (with some simple speed hacks)
372 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
374 // Passed in values (once derefenced, that is) can all be zero. They are
375 // there so that the expression analyzer can fill them in as needed. The
376 // expression analyzer gets its input from the global token pointer "tok",
377 // and not from anything passed in by the user.
383 evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c)
384 // Also set in various other places too (riscasm.c,
387 // Optimize for single constant or single symbol.
388 // 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:
390 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
391 || ((tok[0] == SYMBOL)
392 && (tokenClass[tok[2]] < UNARY))
393 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
395 // 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 naively checking tok[1] for an EOL. O_o
400 *evalTokenBuffer.u32++ = *ptk.u32++;
401 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
402 *a_attr = ABS | DEFINED;
408 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
410 // Not sure that removing float constant here is going to break anything and/or
411 // make things significantly slower, but having this here seems to cause the
412 // complexity of the check to get to this part of the parse to go through the
413 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
415 else if (*tok == FCONST)
417 *evalTokenBuffer.u32++ = *tok++;
418 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
419 *a_attr = ABS | DEFINED | FLOAT;
424 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
427 else if (*tok == '*')
429 *evalTokenBuffer.u32++ = CONST;
432 *evalTokenBuffer.u64++ = *a_value = orgaddr;
434 *evalTokenBuffer.u64++ = *a_value = pcloc;
436 // '*' takes attributes of current section, not ABS!
437 *a_attr = cursect | DEFINED;
444 else if (*tok == STRING || *tok == SYMBOL)
447 j = (*p == '.' ? curenv : 0);
448 symbol = lookup(p, LABEL, j);
450 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
452 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
456 symbol = NewSymbol(p, LABEL, j);
458 symbol->sattr |= REFERENCED;
460 // Check for undefined register equates, but only if it's not part
461 // of a #<SYMBOL> construct, as it could be that the label that's
462 // been undefined may later be used as an address label--which
463 // means it will be fixed up later, and thus, not an error.
464 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
466 error("undefined register equate '%s'", symbol->sname);
467 //if we return right away, it returns some spurious errors...
471 // Check register bank usage
472 if (symbol->sattre & EQUATEDREG)
474 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
475 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
477 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
478 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
481 *evalTokenBuffer.u32++ = SYMBOL;
483 *evalTokenBuffer++ = (TOKEN)symbol;
486 While this approach works, it's wasteful. It would be better to use something
487 that's already available, like the symbol "order defined" table (which needs to
488 be converted from a linked list into an array).
490 *evalTokenBuffer.u32++ = symbolNum;
491 symbolPtr[symbolNum] = symbol;
495 *a_value = (symbol->sattr & DEFINED ? symbol->svalue : 0);
496 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
499 All that extra crap that was put into the svalue when doing the equr stuff is
500 thrown away right here. What the hell is it for?
502 if (symbol->sattre & EQUATEDREG)
505 *a_attr |= RISCREG; // Mark it as a register, 'cause it is
509 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
515 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
518 *evalTokenBuffer.u32++ = *tok++;
522 // Unknown type here... Alert the user!,
523 error("undefined RISC register in expression [token=$%X]", *tok);
524 // Prevent spurious error reporting...
529 *evalTokenBuffer.u32++ = ENDEXPR;
536 *evalTokenBuffer.u32++ = ENDEXPR;
537 return evexpr(otk, a_value, a_attr, a_esym);
542 // Evaluate expression.
543 // If the expression involves only ONE external symbol, the expression is
544 // UNDEFINED, but it's value includes everything but the symbol value, and
545 // 'a_esym' is set to the external symbol.
547 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
551 uint64_t * sval = evstk; // (Empty) initial stack
552 WORD * sattr = evattr;
553 SYM * esym = NULL; // No external symbol involved
558 while (*tk.u32 != ENDEXPR)
560 switch ((int)*tk.u32++)
563 //printf("evexpr(): SYMBOL\n");
564 sy = symbolPtr[*tk.u32++];
565 sy->sattr |= REFERENCED; // Set "referenced" bit
567 if (!(sy->sattr & DEFINED))
569 // Reference to undefined symbol
570 if (!(sy->sattr & GLOBAL))
577 if (esym != NULL) // Check for multiple externals
578 return error(seg_error);
583 if (sy->sattr & DEFINED)
584 *++sval = sy->svalue; // Push symbol's value
586 *++sval = 0; // 0 for undefined symbols
588 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
589 sym_seg = (WORD)(sy->sattr & TDB);
594 //printf("evexpr(): CONST = %lX\n", *sval);
595 *++sattr = ABS | DEFINED; // Push simple attribs
599 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
600 // Even though it's a double, we can treat it like a uint64_t since
601 // we're just moving the bits around.
603 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
607 //printf("evexpr(): ACONST = %i\n", *tk.u32);
608 *++sval = *tk.u32++; // Push value
609 *++sattr = (WORD)*tk.u32++; // Push attribs
612 // Binary "+" and "-" matrix:
615 // ----------------------------
616 // ABS | ABS | Sect | Other |
617 // Sect | Sect | [1] | Error |
618 // Other | Other | Error | [1] |
619 // ----------------------------
625 //printf("evexpr(): +\n");
627 --sattr; // Pop attrib
628 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
629 // Get FLOAT attribute, if any
630 attr = (sattr[0] | sattr[1]) & FLOAT;
632 // Since adding an int to a fp value promotes it to a fp value, we
633 // don't care whether it's first or second; we cast to to a double
639 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
641 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
642 *(double *)sval = fpval1 + fpval2;
646 *sval += sval[1]; // Compute value
648 //printf("%i\n", *sval);
651 *sattr = sattr[1] | attr;
652 else if (sattr[1] & TDB)
653 return error(seg_error);
658 //printf("evexpr(): -\n");
660 --sattr; // Pop attrib
661 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
662 // Get FLOAT attribute, if any
663 attr = (sattr[0] | sattr[1]) & FLOAT;
665 // Since subtracting an int to a fp value promotes it to a fp
666 // value, we don't care whether it's first or second; we cast to to
667 // a double regardless.
672 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
674 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
675 *(double *)sval = fpval1 - fpval2;
681 //printf("%i\n", *sval);
683 *sattr |= attr; // Inherit FLOAT attribute
684 attr = (WORD)(*sattr & TDB);
686 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
688 // If symbol1 is ABS, take attributes from symbol2
691 // Otherwise, they're both TDB and so attributes cancel out
692 else if (sattr[1] & TDB)
697 // Unary operators only work on ABS items
699 //printf("evexpr(): UNMINUS\n");
701 return error(seg_error);
705 double * dst = (double *)sval;
707 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
711 *sval = -(int64_t)*sval;
712 *sattr = ABS | DEFINED; // Expr becomes absolute
717 case UNLT: // Unary < (get the low byte of a word)
718 //printf("evexpr(): UNLT\n");
720 return error(seg_error);
723 return error(noflt_error);
725 *sval = (int64_t)((*sval) & 0x00FF);
726 *sattr = ABS | DEFINED; // Expr becomes absolute
729 case UNGT: // Unary > (get the high byte of a word)
730 //printf("evexpr(): UNGT\n");
732 return error(seg_error);
735 return error(noflt_error);
737 *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
738 *sattr = ABS | DEFINED; // Expr becomes absolute
742 //printf("evexpr(): !\n");
744 return error(seg_error);
747 return error("floating point numbers not allowed with operator '!'.");
750 *sattr = ABS | DEFINED; // Expr becomes absolute
754 //printf("evexpr(): ~\n");
756 return error(seg_error);
759 return error("floating point numbers not allowed with operator '~'.");
762 *sattr = ABS | DEFINED; // Expr becomes absolute
765 // Comparison operators must have two values that
766 // are in the same segment, but that's the only requirement.
768 //printf("evexpr(): LE\n");
772 if ((*sattr & TDB) != (sattr[1] & TDB))
773 return error(seg_error);
775 // Get FLOAT attribute, if any
776 attr = (sattr[0] | sattr[1]) & FLOAT;
778 // Cast any ints in the comparison to double, if there's at least
779 // one double in the comparison.
784 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
786 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
787 *sval = (fpval1 <= fpval2);
791 *sval = (*sval <= sval[1]);
794 *sattr = ABS | DEFINED;
798 //printf("evexpr(): GE\n");
802 if ((*sattr & TDB) != (sattr[1] & TDB))
803 return error(seg_error);
805 // Get FLOAT attribute, if any
806 attr = (sattr[0] | sattr[1]) & FLOAT;
808 // Cast any ints in the comparison to double, if there's at least
809 // one double in the comparison.
814 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
816 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
817 *sval = (fpval1 >= fpval2);
821 *sval = (*sval >= sval[1]);
824 *sattr = ABS | DEFINED;
828 //printf("evexpr(): >\n");
832 if ((*sattr & TDB) != (sattr[1] & TDB))
833 return error(seg_error);
835 // Get FLOAT attribute, if any
836 attr = (sattr[0] | sattr[1]) & FLOAT;
838 // Cast any ints in the comparison to double, if there's at least
839 // one double in the comparison.
844 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
846 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
847 *sval = (fpval1 > fpval2);
851 *sval = (*sval > sval[1]);
854 *sattr = ABS | DEFINED;
858 //printf("evexpr(): <\n");
862 if ((*sattr & TDB) != (sattr[1] & TDB))
863 return error(seg_error);
865 // Get FLOAT attribute, if any
866 attr = (sattr[0] | sattr[1]) & FLOAT;
868 // Cast any ints in the comparison to double, if there's at least
869 // one double in the comparison.
874 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
876 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
877 *sval = (fpval1 < fpval2);
881 *sval = (*sval < sval[1]);
884 *sattr = ABS | DEFINED; // Expr forced to ABS
888 //printf("evexpr(): NE\n");
892 if ((*sattr & TDB) != (sattr[1] & TDB))
893 return error(seg_error);
895 // Get FLOAT attribute, if any
896 attr = (sattr[0] | sattr[1]) & FLOAT;
898 // Cast any ints in the comparison to double, if there's at least
899 // one double in the comparison.
904 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
906 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
907 *sval = (fpval1 != fpval2);
911 *sval = (*sval != sval[1]);
914 *sattr = ABS | DEFINED; // Expr forced to ABS
918 //printf("evexpr(): =\n");
922 if ((*sattr & TDB) != (sattr[1] & TDB))
923 return error(seg_error);
925 // Get FLOAT attribute, if any
926 attr = (sattr[0] | sattr[1]) & FLOAT;
928 // Cast any ints in the comparison to double, if there's at least
929 // one double in the comparison.
934 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
936 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
937 *sval = (fpval1 == fpval2);
941 *sval = (*sval == sval[1]);
944 *sattr = ABS | DEFINED; // Expr forced to ABS
948 // All other binary operators must have two ABS items to work with.
949 // They all produce an ABS value.
950 // Shamus: Is this true? There's at least one counterexample of legit
951 // code where this assumption fails to produce correct code.
953 //printf("evexpr(): default\n");
955 switch ((int)tk.u32[-1])
960 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
961 // Get FLOAT attribute, if any
962 attr = (sattr[0] | sattr[1]) & FLOAT;
964 // Since multiplying an int to a fp value promotes it to a fp
965 // value, we don't care whether it's first or second; it will
966 // be cast to a double regardless.
968 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.
974 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
976 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
977 *(double *)sval = fpval1 * fpval2;
983 //printf("%i\n", *sval);
985 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
991 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
992 // Get FLOAT attribute, if any
993 attr = (sattr[0] | sattr[1]) & FLOAT;
999 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
1001 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
1004 return error("divide by zero");
1006 *(double *)sval = fpval1 / fpval2;
1011 return error("divide by zero");
1012 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1014 // Compiler is picky here: Without casting these, it
1015 // discards the sign if dividing a negative # by a
1016 // positive one, creating a bad result. :-/
1017 // Definitely a side effect of using uint32_ts intead of
1019 *sval = (int32_t)sval[0] / (int32_t)sval[1];
1021 //printf("%i\n", *sval);
1023 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1030 if ((*sattr | sattr[1]) & FLOAT)
1031 return error("floating point numbers not allowed with operator '%'.");
1034 return error("mod (%) by zero");
1037 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1042 sattr--; // Pop attrib
1044 if ((*sattr | sattr[1]) & FLOAT)
1045 return error("floating point numbers not allowed with operator '<<'.");
1048 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1053 sattr--; // Pop attrib
1055 if ((*sattr | sattr[1]) & FLOAT)
1056 return error("floating point numbers not allowed with operator '>>'.");
1059 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1064 sattr--; // Pop attrib
1066 if ((*sattr | sattr[1]) & FLOAT)
1067 return error("floating point numbers not allowed with operator '&'.");
1070 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1075 sattr--; // Pop attrib
1077 if ((*sattr | sattr[1]) & FLOAT)
1078 return error("floating point numbers not allowed with operator '^'.");
1081 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1088 if ((*sattr | sattr[1]) & FLOAT)
1089 return error("floating point numbers not allowed with operator '|'.");
1092 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1096 // Bad operator in expression stream (this should never happen!)
1108 // Copy value + attrib into return variables
1117 // Count the # of tokens in the passed in expression
1118 // N.B.: 64-bit constants count as two tokens each
1120 uint16_t ExpressionLength(TOKEN * tk)
1124 for(length=0; tk[length]!=ENDEXPR; length++)
1126 // Add one to length for 2X tokens, two for 3X tokens
1127 if (tk[length] == SYMBOL)
1129 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1133 // Add 1 for ENDEXPR