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, 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 PTR 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)
106 while (tokenClass[*tok] >= MULT)
113 *evalTokenBuffer.u32++ = t;
121 // Unary operators (detect unary '-')
122 // ggn: If expression starts with a plus then also eat it up. For some reason
123 // the parser gets confused when this happens and emits a "bad
134 int class = tokenClass[*tok];
136 if (*tok == '-' || *tok == '+' || class == UNARY)
146 // With leading + we don't have to deposit anything to the buffer
147 // because there's no unary '+' nor we have to do anything about it
149 *evalTokenBuffer.u32++ = t;
151 else if (class == SUNARY)
156 *evalTokenBuffer.u32++ = CONST;
157 *evalTokenBuffer.u64++ = (uint64_t)sect[ABS].sloc;
160 *evalTokenBuffer.u32++ = CONST;
161 *evalTokenBuffer.u64++ = dos_time();
164 *evalTokenBuffer.u32++ = CONST;
165 *evalTokenBuffer.u64++ = dos_date();
167 case CR_MACDEF: // ^^macdef <macro-name>
168 if (*tok++ != SYMBOL)
169 return error(missym_error);
172 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
173 *evalTokenBuffer.u32++ = CONST;
174 *evalTokenBuffer.u64++ = (uint64_t)w;
182 if (*tok++ != SYMBOL)
183 return error(missym_error);
186 j = (*p == '.' ? curenv : 0);
187 w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
188 *evalTokenBuffer.u32++ = CONST;
189 *evalTokenBuffer.u64++ = (uint64_t)w;
192 if (*tok != SYMBOL && *tok != STRING)
193 return error(str_error);
199 return error(comma_error);
201 if (*tok != SYMBOL && *tok != STRING)
202 return error(str_error);
207 w = (WORD)(!strcmp(p, p2));
208 *evalTokenBuffer.u32++ = CONST;
209 *evalTokenBuffer.u64++ = (uint64_t)w;
221 // Terminals (CONSTs) and parenthesis grouping
234 *evalTokenBuffer.u32++ = CONST;
235 *evalTokenBuffer.u64++ = *ptk.u64++;
240 *evalTokenBuffer.u32++ = FCONST;
241 *evalTokenBuffer.u64++ = *ptk.u64++;
246 j = (*p == '.' ? curenv : 0);
247 sy = lookup(p, LABEL, j);
250 sy = NewSymbol(p, LABEL, j);
252 // Check register bank usage
253 if (sy->sattre & EQUATEDREG)
255 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
256 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
258 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
259 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
262 *evalTokenBuffer.u32++ = SYMBOL;
263 *evalTokenBuffer.u32++ = symbolNum;
264 symbolPtr[symbolNum] = sy;
268 *evalTokenBuffer.u32++ = CONST;
269 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
276 return error("missing closing parenthesis ')'");
284 return error("missing closing bracket ']'");
288 if (expr0() != OK) // Eat up first parameter (register or immediate)
291 if (*tok++ != ':') // Demand a ':' there
292 return error("missing colon ':'");
294 if (expr0() != OK) // Eat up second parameter (register or immediate)
298 return error("missing closing brace '}'");
302 *evalTokenBuffer.u32++ = ACONST; // Attributed const
303 *evalTokenBuffer.u32++ = sloc; // Current location
304 *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs
307 *evalTokenBuffer.u32++ = ACONST; // Attributed const
309 // pcloc == location at start of line
310 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
311 // '*' takes attributes of current section, not ABS!
312 *evalTokenBuffer.u32++ = cursect | DEFINED;
315 return error("bad expression");
323 // Recursive-descent expression analyzer (with some simple speed hacks)
325 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
327 // Passed in values (once derefenced, that is) can all be zero. They are
328 // there so that the expression analyzer can fill them in as needed. The
329 // expression analyzer gets its input from the global token pointer "tok",
330 // and not from anything passed in by the user.
336 evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c)
337 // Also set in various other places too (riscasm.c,
340 //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]]);
341 // Optimize for single constant or single symbol.
342 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
343 // followed by the value 101, it will trigger a bad evaluation here.
344 // This is probably a really bad assumption to be making here...!
345 // (assuming tok[1] == EOL is a single token that is)
346 // Seems that even other tokens (SUNARY type) can fuck this up too.
348 // if ((tok[1] == EOL)
349 if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
350 // || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
351 // && (tokenClass[tok[2]] < UNARY)))
352 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
353 && (tokenClass[tok[2]] < UNARY))
354 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
357 // 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:
359 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
360 || (((tok[0] == SYMBOL)
361 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
362 && (tokenClass[tok[2]] < UNARY))
363 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
365 // 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
368 if (*tok >= KW_R0 && *tok <= KW_R31)
370 *evalTokenBuffer.u32++ = CONST;
371 *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
372 *a_attr = ABS | DEFINED;
379 else if (*tok == CONST)
382 *evalTokenBuffer.u32++ = *ptk.u32++;
383 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
384 *a_attr = ABS | DEFINED;
390 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
392 // Not sure that removing float constant here is going to break anything and/or
393 // make things significantly slower, but having this here seems to cause the
394 // complexity of the check to get to this part of the parse to go through the
395 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
397 else if (*tok == FCONST)
399 *evalTokenBuffer.u32++ = *tok++;
400 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
401 *a_attr = ABS | DEFINED | FLOAT;
406 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
409 else if (*tok == '*')
411 *evalTokenBuffer.u32++ = CONST;
414 *evalTokenBuffer.u64++ = *a_value = orgaddr;
416 *evalTokenBuffer.u64++ = *a_value = pcloc;
418 // '*' takes attributes of current section, not ABS!
419 *a_attr = cursect | DEFINED;
426 else if (*tok == STRING || *tok == SYMBOL)
429 j = (*p == '.' ? curenv : 0);
430 symbol = lookup(p, LABEL, j);
432 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
434 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
438 symbol = NewSymbol(p, LABEL, j);
440 symbol->sattr |= REFERENCED;
442 // Check for undefined register equates, but only if it's not part
443 // of a #<SYMBOL> construct, as it could be that the label that's
444 // been undefined may later be used as an address label--which
445 // means it will be fixed up later, and thus, not an error.
446 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
448 error("undefined register equate '%s'", symbol->sname);
449 //if we return right away, it returns some spurious errors...
453 // Check register bank usage
454 if (symbol->sattre & EQUATEDREG)
456 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
457 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
459 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
460 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
463 *evalTokenBuffer.u32++ = SYMBOL;
465 *evalTokenBuffer++ = (TOKEN)symbol;
468 While this approach works, it's wasteful. It would be better to use something
469 that's already available, like the symbol "order defined" table (which needs to
470 be converted from a linked list into an array).
472 *evalTokenBuffer.u32++ = symbolNum;
473 symbolPtr[symbolNum] = symbol;
477 if (symbol->sattr & DEFINED)
478 *a_value = symbol->svalue;
483 All that extra crap that was put into the svalue when doing the equr stuff is
484 thrown away right here. What the hell is it for?
486 if (symbol->sattre & EQUATEDREG)
489 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
491 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
499 // Unknown type here... Alert the user!,
500 error("undefined RISC register in expression");
501 // Prevent spurious error reporting...
506 *evalTokenBuffer.u32++ = ENDEXPR;
513 *evalTokenBuffer.u32++ = ENDEXPR;
514 return evexpr(otk, a_value, a_attr, a_esym);
519 // Evaluate expression.
520 // If the expression involves only ONE external symbol, the expression is
521 // UNDEFINED, but it's value includes everything but the symbol value, and
522 // 'a_esym' is set to the external symbol.
524 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
528 uint64_t * sval = evstk; // (Empty) initial stack
529 WORD * sattr = evattr;
530 SYM * esym = NULL; // No external symbol involved
535 while (*tk.u32 != ENDEXPR)
537 switch ((int)*tk.u32++)
540 //printf("evexpr(): SYMBOL\n");
541 sy = symbolPtr[*tk.u32++];
542 sy->sattr |= REFERENCED; // Set "referenced" bit
544 if (!(sy->sattr & DEFINED))
546 // Reference to undefined symbol
547 if (!(sy->sattr & GLOBAL))
554 if (esym != NULL) // Check for multiple externals
555 return error(seg_error);
560 if (sy->sattr & DEFINED)
561 *++sval = sy->svalue; // Push symbol's value
563 *++sval = 0; // 0 for undefined symbols
565 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
566 sym_seg = (WORD)(sy->sattr & TDB);
571 //printf("evexpr(): CONST = %lX\n", *sval);
572 *++sattr = ABS | DEFINED; // Push simple attribs
576 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
577 // Even though it's a double, we can treat it like a uint64_t since
578 // we're just moving the bits around.
580 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
584 //printf("evexpr(): ACONST = %i\n", *tk.u32);
585 *++sval = *tk.u32++; // Push value
586 *++sattr = (WORD)*tk.u32++; // Push attribs
589 // Binary "+" and "-" matrix:
592 // ----------------------------
593 // ABS | ABS | Sect | Other |
594 // Sect | Sect | [1] | Error |
595 // Other | Other | Error | [1] |
596 // ----------------------------
602 //printf("evexpr(): +\n");
604 --sattr; // Pop attrib
605 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
606 // Get FLOAT attribute, if any
607 attr = (sattr[0] | sattr[1]) & FLOAT;
609 // Since adding an int to a fp value promotes it to a fp value, we
610 // don't care whether it's first or second; we cast to to a double
616 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
618 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
619 *(double *)sval = fpval1 + fpval2;
623 *sval += sval[1]; // Compute value
625 //printf("%i\n", *sval);
628 *sattr = sattr[1] | attr;
629 else if (sattr[1] & TDB)
630 return error(seg_error);
635 //printf("evexpr(): -\n");
637 --sattr; // Pop attrib
638 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
639 // Get FLOAT attribute, if any
640 attr = (sattr[0] | sattr[1]) & FLOAT;
642 // Since subtracting an int to a fp value promotes it to a fp
643 // value, we don't care whether it's first or second; we cast to to
644 // a double regardless.
649 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
651 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
652 *(double *)sval = fpval1 - fpval2;
658 //printf("%i\n", *sval);
660 *sattr |= attr; // Inherit FLOAT attribute
661 attr = (WORD)(*sattr & TDB);
663 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
665 // If symbol1 is ABS, take attributes from symbol2
668 // Otherwise, they're both TDB and so attributes cancel out
669 else if (sattr[1] & TDB)
674 // Unary operators only work on ABS items
676 //printf("evexpr(): UNMINUS\n");
678 return error(seg_error);
682 double * dst = (double *)sval;
684 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
688 *sval = -(int64_t)*sval;
689 *sattr = ABS | DEFINED; // Expr becomes absolute
695 //printf("evexpr(): !\n");
697 return error(seg_error);
700 return error("floating point numbers not allowed with operator '!'.");
703 *sattr = ABS | DEFINED; // Expr becomes absolute
707 //printf("evexpr(): ~\n");
709 return error(seg_error);
712 return error("floating point numbers not allowed with operator '~'.");
715 *sattr = ABS | DEFINED; // Expr becomes absolute
718 // Comparison operators must have two values that
719 // are in the same segment, but that's the only requirement.
721 //printf("evexpr(): LE\n");
725 if ((*sattr & TDB) != (sattr[1] & TDB))
726 return error(seg_error);
728 // Get FLOAT attribute, if any
729 attr = (sattr[0] | sattr[1]) & FLOAT;
731 // Cast any ints in the comparison to double, if there's at least
732 // one double in the comparison.
737 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
739 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
740 *sval = (fpval1 <= fpval2);
744 *sval = (*sval <= sval[1]);
747 *sattr = ABS | DEFINED;
751 //printf("evexpr(): GE\n");
755 if ((*sattr & TDB) != (sattr[1] & TDB))
756 return error(seg_error);
758 // Get FLOAT attribute, if any
759 attr = (sattr[0] | sattr[1]) & FLOAT;
761 // Cast any ints in the comparison to double, if there's at least
762 // one double in the comparison.
767 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
769 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
770 *sval = (fpval1 >= fpval2);
774 *sval = (*sval >= sval[1]);
777 *sattr = ABS | DEFINED;
781 //printf("evexpr(): >\n");
785 if ((*sattr & TDB) != (sattr[1] & TDB))
786 return error(seg_error);
788 // Get FLOAT attribute, if any
789 attr = (sattr[0] | sattr[1]) & FLOAT;
791 // Cast any ints in the comparison to double, if there's at least
792 // one double in the comparison.
797 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
799 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
800 *sval = (fpval1 > fpval2);
804 *sval = (*sval > sval[1]);
807 *sattr = ABS | DEFINED;
811 //printf("evexpr(): <\n");
815 if ((*sattr & TDB) != (sattr[1] & TDB))
816 return error(seg_error);
818 // Get FLOAT attribute, if any
819 attr = (sattr[0] | sattr[1]) & FLOAT;
821 // Cast any ints in the comparison to double, if there's at least
822 // one double in the comparison.
827 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
829 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
830 *sval = (fpval1 < fpval2);
834 *sval = (*sval < sval[1]);
837 *sattr = ABS | DEFINED; // Expr forced to ABS
841 //printf("evexpr(): NE\n");
845 if ((*sattr & TDB) != (sattr[1] & TDB))
846 return error(seg_error);
848 // Get FLOAT attribute, if any
849 attr = (sattr[0] | sattr[1]) & FLOAT;
851 // Cast any ints in the comparison to double, if there's at least
852 // one double in the comparison.
857 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
859 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
860 *sval = (fpval1 != fpval2);
864 *sval = (*sval != sval[1]);
867 *sattr = ABS | DEFINED; // Expr forced to ABS
871 //printf("evexpr(): =\n");
875 if ((*sattr & TDB) != (sattr[1] & TDB))
876 return error(seg_error);
878 // Get FLOAT attribute, if any
879 attr = (sattr[0] | sattr[1]) & FLOAT;
881 // Cast any ints in the comparison to double, if there's at least
882 // one double in the comparison.
887 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
889 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
890 *sval = (fpval1 == fpval2);
894 *sval = (*sval == sval[1]);
897 *sattr = ABS | DEFINED; // Expr forced to ABS
901 // All other binary operators must have two ABS items to work with.
902 // They all produce an ABS value.
903 // Shamus: Is this true? There's at least one counterexample of legit
904 // code where this assumption fails to produce correct code.
906 //printf("evexpr(): default\n");
908 switch ((int)tk.u32[-1])
913 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
914 // Get FLOAT attribute, if any
915 attr = (sattr[0] | sattr[1]) & FLOAT;
917 // Since multiplying an int to a fp value promotes it to a fp
918 // value, we don't care whether it's first or second; it will
919 // be cast to a double regardless.
921 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.
927 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
929 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
930 *(double *)sval = fpval1 * fpval2;
936 //printf("%i\n", *sval);
938 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
944 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
945 // Get FLOAT attribute, if any
946 attr = (sattr[0] | sattr[1]) & FLOAT;
952 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
954 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
957 return error("divide by zero");
959 *(double *)sval = fpval1 / fpval2;
964 return error("divide by zero");
965 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
967 // Compiler is picky here: Without casting these, it
968 // discards the sign if dividing a negative # by a
969 // positive one, creating a bad result. :-/
970 // Definitely a side effect of using uint32_ts intead of
972 *sval = (int32_t)sval[0] / (int32_t)sval[1];
974 //printf("%i\n", *sval);
976 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
983 if ((*sattr | sattr[1]) & FLOAT)
984 return error("floating point numbers not allowed with operator '%'.");
987 return error("mod (%) by zero");
990 //no *sattr = ABS | DEFINED; // Expr becomes absolute
995 sattr--; // Pop attrib
997 if ((*sattr | sattr[1]) & FLOAT)
998 return error("floating point numbers not allowed with operator '<<'.");
1001 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1006 sattr--; // Pop attrib
1008 if ((*sattr | sattr[1]) & FLOAT)
1009 return error("floating point numbers not allowed with operator '>>'.");
1012 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1017 sattr--; // Pop attrib
1019 if ((*sattr | sattr[1]) & FLOAT)
1020 return error("floating point numbers not allowed with operator '&'.");
1023 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1028 sattr--; // Pop attrib
1030 if ((*sattr | sattr[1]) & FLOAT)
1031 return error("floating point numbers not allowed with operator '^'.");
1034 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1041 if ((*sattr | sattr[1]) & FLOAT)
1042 return error("floating point numbers not allowed with operator '|'.");
1045 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1049 // Bad operator in expression stream (this should never happen!)
1061 // Copy value + attrib into return variables
1070 // Count the # of tokens in the passed in expression
1071 // N.B.: 64-bit constants count as two tokens each
1073 uint16_t ExpressionLength(TOKEN * tk)
1077 for(length=0; tk[length]!=ENDEXPR; length++)
1079 // Add one to length for 2X tokens, two for 3X tokens
1080 if (tk[length] == SYMBOL)
1082 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1086 // Add 1 for ENDEXPR