2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // EXPR.C - Expression Analyzer
4 // Copyright (C) 199x Landon Dyer, 2011-2020 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");
173 *evalTokenBuffer.u32++ = CONST;
174 // @@copypasted from d_incbin, maybe factor this out somehow?
175 // Attempt to open the include file in the current directory, then (if that
176 // failed) try list of include files passed in the enviroment string or by
181 if ((fd = open(string[*tok], _OPEN_INC)) < 0)
183 for(i=0; nthpath("RMACPATH", i, buf1)!= 0; i++)
187 // Append path char if necessary
188 if ((fd > 0) && (buf1[fd - 1] != SLASHCHAR))
189 strcat(buf1, SLASHSTRING);
191 strcat(buf1, string[*tok]);
193 if ((fd = open(buf1, _OPEN_INC)) >= 0)
197 return error("cannot open: \"%s\"", string[tok[1]]);
201 *evalTokenBuffer.u64++ = (uint64_t)lseek(fd, 0L, SEEK_END);
204 // Advance tok because of consumed string token
208 *evalTokenBuffer.u32++ = CONST;
209 *evalTokenBuffer.u64++ = dos_time();
212 *evalTokenBuffer.u32++ = CONST;
213 *evalTokenBuffer.u64++ = dos_date();
215 case CR_MACDEF: // ^^macdef <macro-name>
216 if (*tok++ != SYMBOL)
217 return error(missym_error);
220 w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
221 *evalTokenBuffer.u32++ = CONST;
222 *evalTokenBuffer.u64++ = (uint64_t)w;
230 if (*tok++ != SYMBOL)
231 return error(missym_error);
234 int j = (*p == '.' ? curenv : 0);
235 SYM * sy = lookup(p, LABEL, j);
236 w = ((sy != NULL) && (sy->sattr & w ? 1 : 0));
237 *evalTokenBuffer.u32++ = CONST;
238 *evalTokenBuffer.u64++ = (uint64_t)w;
241 if (*tok != SYMBOL && *tok != STRING)
242 return error(str_error);
248 return error(comma_error);
250 if (*tok != SYMBOL && *tok != STRING)
251 return error(str_error);
253 char * p2 = string[tok[1]];
256 w = (WORD)(!strcmp(p, p2));
257 *evalTokenBuffer.u32++ = CONST;
258 *evalTokenBuffer.u64++ = (uint64_t)w;
270 // Terminals (CONSTs) and parenthesis grouping
280 *evalTokenBuffer.u32++ = CONST;
281 *evalTokenBuffer.u64++ = *ptk.u64++;
286 *evalTokenBuffer.u32++ = FCONST;
287 *evalTokenBuffer.u64++ = *ptk.u64++;
292 char * p = string[*tok++];
293 int j = (*p == '.' ? curenv : 0);
294 SYM * sy = lookup(p, LABEL, j);
297 sy = NewSymbol(p, LABEL, j);
299 // Check register bank usage
300 if (sy->sattre & EQUATEDREG)
302 if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
303 warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
305 if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
306 warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
309 *evalTokenBuffer.u32++ = SYMBOL;
310 *evalTokenBuffer.u32++ = symbolNum;
311 symbolPtr[symbolNum] = sy;
316 *evalTokenBuffer.u32++ = CONST;
317 *evalTokenBuffer.u64++ = str_value(string[*tok++]);
324 return error("missing closing parenthesis ')'");
332 return error("missing closing bracket ']'");
336 if (expr0() != OK) // Eat up first parameter (register or immediate)
339 if (*tok++ != ':') // Demand a ':' there
340 return error("missing colon ':'");
342 if (expr0() != OK) // Eat up second parameter (register or immediate)
346 return error("missing closing brace '}'");
350 *evalTokenBuffer.u32++ = ACONST; // Attributed const
351 *evalTokenBuffer.u32++ = sloc; // Current location
352 *evalTokenBuffer.u32++ = cursect | DEFINED; // Store attribs
355 *evalTokenBuffer.u32++ = ACONST; // Attributed const
357 // pcloc == location at start of line
358 *evalTokenBuffer.u32++ = (orgactive ? orgaddr : pcloc);
359 // '*' takes attributes of current section, not ABS!
360 *evalTokenBuffer.u32++ = cursect | DEFINED;
363 return error("bad expression");
371 // Recursive-descent expression analyzer (with some simple speed hacks)
373 int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
375 // Passed in values (once derefenced, that is) can all be zero. They are
376 // there so that the expression analyzer can fill them in as needed. The
377 // expression analyzer gets its input from the global token pointer "tok",
378 // and not from anything passed in by the user.
384 evalTokenBuffer.u32 = otk; // Set token pointer to 'exprbuf' (direct.c)
385 // Also set in various other places too (riscasm.c,
388 //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]]);
389 // Optimize for single constant or single symbol.
390 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
391 // followed by the value 101, it will trigger a bad evaluation here.
392 // This is probably a really bad assumption to be making here...!
393 // (assuming tok[1] == EOL is a single token that is)
394 // Seems that even other tokens (SUNARY type) can fuck this up too.
396 // if ((tok[1] == EOL)
397 if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
398 // || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
399 // && (tokenClass[tok[2]] < UNARY)))
400 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
401 && (tokenClass[tok[2]] < UNARY))
402 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
405 // 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:
407 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
408 || (((tok[0] == SYMBOL)
409 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
410 && (tokenClass[tok[2]] < UNARY))
411 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
413 // 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
416 if (*tok >= KW_R0 && *tok <= KW_R31)
418 *evalTokenBuffer.u32++ = CONST;
419 *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
420 *a_attr = ABS | DEFINED;
427 else if (*tok == CONST)
430 *evalTokenBuffer.u32++ = *ptk.u32++;
431 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
432 *a_attr = ABS | DEFINED;
438 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
440 // Not sure that removing float constant here is going to break anything and/or
441 // make things significantly slower, but having this here seems to cause the
442 // complexity of the check to get to this part of the parse to go through the
443 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
445 else if (*tok == FCONST)
447 *evalTokenBuffer.u32++ = *tok++;
448 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
449 *a_attr = ABS | DEFINED | FLOAT;
454 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
457 else if (*tok == '*')
459 *evalTokenBuffer.u32++ = CONST;
462 *evalTokenBuffer.u64++ = *a_value = orgaddr;
464 *evalTokenBuffer.u64++ = *a_value = pcloc;
466 // '*' takes attributes of current section, not ABS!
467 *a_attr = cursect | DEFINED;
474 else if (*tok == STRING || *tok == SYMBOL)
477 j = (*p == '.' ? curenv : 0);
478 symbol = lookup(p, LABEL, j);
480 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
482 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
486 symbol = NewSymbol(p, LABEL, j);
488 symbol->sattr |= REFERENCED;
490 // Check for undefined register equates, but only if it's not part
491 // of a #<SYMBOL> construct, as it could be that the label that's
492 // been undefined may later be used as an address label--which
493 // means it will be fixed up later, and thus, not an error.
494 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
496 error("undefined register equate '%s'", symbol->sname);
497 //if we return right away, it returns some spurious errors...
501 // Check register bank usage
502 if (symbol->sattre & EQUATEDREG)
504 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
505 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
507 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
508 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
511 *evalTokenBuffer.u32++ = SYMBOL;
513 *evalTokenBuffer++ = (TOKEN)symbol;
516 While this approach works, it's wasteful. It would be better to use something
517 that's already available, like the symbol "order defined" table (which needs to
518 be converted from a linked list into an array).
520 *evalTokenBuffer.u32++ = symbolNum;
521 symbolPtr[symbolNum] = symbol;
525 if (symbol->sattr & DEFINED)
526 *a_value = symbol->svalue;
531 All that extra crap that was put into the svalue when doing the equr stuff is
532 thrown away right here. What the hell is it for?
534 if (symbol->sattre & EQUATEDREG)
537 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
539 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
545 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
548 *evalTokenBuffer.u32++ = *tok++;
552 // Unknown type here... Alert the user!,
553 error("undefined RISC register in expression [token=$%X]", *tok);
554 // Prevent spurious error reporting...
559 *evalTokenBuffer.u32++ = ENDEXPR;
566 *evalTokenBuffer.u32++ = ENDEXPR;
567 return evexpr(otk, a_value, a_attr, a_esym);
572 // Evaluate expression.
573 // If the expression involves only ONE external symbol, the expression is
574 // UNDEFINED, but it's value includes everything but the symbol value, and
575 // 'a_esym' is set to the external symbol.
577 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
581 uint64_t * sval = evstk; // (Empty) initial stack
582 WORD * sattr = evattr;
583 SYM * esym = NULL; // No external symbol involved
588 while (*tk.u32 != ENDEXPR)
590 switch ((int)*tk.u32++)
593 //printf("evexpr(): SYMBOL\n");
594 sy = symbolPtr[*tk.u32++];
595 sy->sattr |= REFERENCED; // Set "referenced" bit
597 if (!(sy->sattr & DEFINED))
599 // Reference to undefined symbol
600 if (!(sy->sattr & GLOBAL))
607 if (esym != NULL) // Check for multiple externals
608 return error(seg_error);
613 if (sy->sattr & DEFINED)
614 *++sval = sy->svalue; // Push symbol's value
616 *++sval = 0; // 0 for undefined symbols
618 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
619 sym_seg = (WORD)(sy->sattr & TDB);
624 //printf("evexpr(): CONST = %lX\n", *sval);
625 *++sattr = ABS | DEFINED; // Push simple attribs
629 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
630 // Even though it's a double, we can treat it like a uint64_t since
631 // we're just moving the bits around.
633 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
637 //printf("evexpr(): ACONST = %i\n", *tk.u32);
638 *++sval = *tk.u32++; // Push value
639 *++sattr = (WORD)*tk.u32++; // Push attribs
642 // Binary "+" and "-" matrix:
645 // ----------------------------
646 // ABS | ABS | Sect | Other |
647 // Sect | Sect | [1] | Error |
648 // Other | Other | Error | [1] |
649 // ----------------------------
655 //printf("evexpr(): +\n");
657 --sattr; // Pop attrib
658 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
659 // Get FLOAT attribute, if any
660 attr = (sattr[0] | sattr[1]) & FLOAT;
662 // Since adding an int to a fp value promotes it to a fp value, we
663 // don't care whether it's first or second; we cast to to a double
669 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
671 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
672 *(double *)sval = fpval1 + fpval2;
676 *sval += sval[1]; // Compute value
678 //printf("%i\n", *sval);
681 *sattr = sattr[1] | attr;
682 else if (sattr[1] & TDB)
683 return error(seg_error);
688 //printf("evexpr(): -\n");
690 --sattr; // Pop attrib
691 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
692 // Get FLOAT attribute, if any
693 attr = (sattr[0] | sattr[1]) & FLOAT;
695 // Since subtracting an int to a fp value promotes it to a fp
696 // value, we don't care whether it's first or second; we cast to to
697 // a double regardless.
702 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
704 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
705 *(double *)sval = fpval1 - fpval2;
711 //printf("%i\n", *sval);
713 *sattr |= attr; // Inherit FLOAT attribute
714 attr = (WORD)(*sattr & TDB);
716 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
718 // If symbol1 is ABS, take attributes from symbol2
721 // Otherwise, they're both TDB and so attributes cancel out
722 else if (sattr[1] & TDB)
727 // Unary operators only work on ABS items
729 //printf("evexpr(): UNMINUS\n");
731 return error(seg_error);
735 double * dst = (double *)sval;
737 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
741 *sval = -(int64_t)*sval;
742 *sattr = ABS | DEFINED; // Expr becomes absolute
747 case UNLT: // Unary < (get the low byte of a word)
748 //printf("evexpr(): UNLT\n");
750 return error(seg_error);
753 return error(noflt_error);
755 *sval = (int64_t)((*sval) & 0x00FF);
756 *sattr = ABS | DEFINED; // Expr becomes absolute
759 case UNGT: // Unary > (get the high byte of a word)
760 //printf("evexpr(): UNGT\n");
762 return error(seg_error);
765 return error(noflt_error);
767 *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
768 *sattr = ABS | DEFINED; // Expr becomes absolute
772 //printf("evexpr(): !\n");
774 return error(seg_error);
777 return error("floating point numbers not allowed with operator '!'.");
780 *sattr = ABS | DEFINED; // Expr becomes absolute
784 //printf("evexpr(): ~\n");
786 return error(seg_error);
789 return error("floating point numbers not allowed with operator '~'.");
792 *sattr = ABS | DEFINED; // Expr becomes absolute
795 // Comparison operators must have two values that
796 // are in the same segment, but that's the only requirement.
798 //printf("evexpr(): LE\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(): GE\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;
888 //printf("evexpr(): <\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(): NE\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 //printf("evexpr(): =\n");
952 if ((*sattr & TDB) != (sattr[1] & TDB))
953 return error(seg_error);
955 // Get FLOAT attribute, if any
956 attr = (sattr[0] | sattr[1]) & FLOAT;
958 // Cast any ints in the comparison to double, if there's at least
959 // one double in the comparison.
964 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
966 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
967 *sval = (fpval1 == fpval2);
971 *sval = (*sval == sval[1]);
974 *sattr = ABS | DEFINED; // Expr forced to ABS
978 // All other binary operators must have two ABS items to work with.
979 // They all produce an ABS value.
980 // Shamus: Is this true? There's at least one counterexample of legit
981 // code where this assumption fails to produce correct code.
983 //printf("evexpr(): default\n");
985 switch ((int)tk.u32[-1])
990 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
991 // Get FLOAT attribute, if any
992 attr = (sattr[0] | sattr[1]) & FLOAT;
994 // Since multiplying an int to a fp value promotes it to a fp
995 // value, we don't care whether it's first or second; it will
996 // be cast to a double regardless.
998 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.
1004 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
1006 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
1007 *(double *)sval = fpval1 * fpval2;
1013 //printf("%i\n", *sval);
1015 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1021 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1022 // Get FLOAT attribute, if any
1023 attr = (sattr[0] | sattr[1]) & FLOAT;
1029 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
1031 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
1034 return error("divide by zero");
1036 *(double *)sval = fpval1 / fpval2;
1041 return error("divide by zero");
1042 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1044 // Compiler is picky here: Without casting these, it
1045 // discards the sign if dividing a negative # by a
1046 // positive one, creating a bad result. :-/
1047 // Definitely a side effect of using uint32_ts intead of
1049 *sval = (int32_t)sval[0] / (int32_t)sval[1];
1051 //printf("%i\n", *sval);
1053 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1060 if ((*sattr | sattr[1]) & FLOAT)
1061 return error("floating point numbers not allowed with operator '%'.");
1064 return error("mod (%) by zero");
1067 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1072 sattr--; // Pop attrib
1074 if ((*sattr | sattr[1]) & FLOAT)
1075 return error("floating point numbers not allowed with operator '<<'.");
1078 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1083 sattr--; // Pop attrib
1085 if ((*sattr | sattr[1]) & FLOAT)
1086 return error("floating point numbers not allowed with operator '>>'.");
1089 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1094 sattr--; // Pop attrib
1096 if ((*sattr | sattr[1]) & FLOAT)
1097 return error("floating point numbers not allowed with operator '&'.");
1100 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1105 sattr--; // Pop attrib
1107 if ((*sattr | sattr[1]) & FLOAT)
1108 return error("floating point numbers not allowed with operator '^'.");
1111 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1118 if ((*sattr | sattr[1]) & FLOAT)
1119 return error("floating point numbers not allowed with operator '|'.");
1122 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1126 // Bad operator in expression stream (this should never happen!)
1138 // Copy value + attrib into return variables
1147 // Count the # of tokens in the passed in expression
1148 // N.B.: 64-bit constants count as two tokens each
1150 uint16_t ExpressionLength(TOKEN * tk)
1154 for(length=0; tk[length]!=ENDEXPR; length++)
1156 // Add one to length for 2X tokens, two for 3X tokens
1157 if (tk[length] == SYMBOL)
1159 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1163 // Add 1 for ENDEXPR