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 //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]]);
388 // Optimize for single constant or single symbol.
389 // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
390 // followed by the value 101, it will trigger a bad evaluation here.
391 // This is probably a really bad assumption to be making here...!
392 // (assuming tok[1] == EOL is a single token that is)
393 // Seems that even other tokens (SUNARY type) can fuck this up too.
395 // if ((tok[1] == EOL)
396 if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
397 // || (((*tok == CONST || *tok == FCONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
398 // && (tokenClass[tok[2]] < UNARY)))
399 || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
400 && (tokenClass[tok[2]] < UNARY))
401 || ((tok[0] == CONST || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
404 // 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:
406 && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
407 || (((tok[0] == SYMBOL)
408 || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
409 && (tokenClass[tok[2]] < UNARY))
410 || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
412 // 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
415 if (*tok >= KW_R0 && *tok <= KW_R31)
417 *evalTokenBuffer.u32++ = CONST;
418 *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
419 *a_attr = ABS | DEFINED | RISCREG;
426 else if (*tok == CONST)
429 *evalTokenBuffer.u32++ = *ptk.u32++;
430 *evalTokenBuffer.u64++ = *a_value = *ptk.u64++;
431 *a_attr = ABS | DEFINED;
437 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
439 // Not sure that removing float constant here is going to break anything and/or
440 // make things significantly slower, but having this here seems to cause the
441 // complexity of the check to get to this part of the parse to go through the
442 // roof, and dammit, I just don't feel like fighting that fight ATM. :-P
444 else if (*tok == FCONST)
446 *evalTokenBuffer.u32++ = *tok++;
447 *evalTokenBuffer.u64++ = *a_value = *tok.u64++;
448 *a_attr = ABS | DEFINED | FLOAT;
453 //printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
456 else if (*tok == '*')
458 *evalTokenBuffer.u32++ = CONST;
461 *evalTokenBuffer.u64++ = *a_value = orgaddr;
463 *evalTokenBuffer.u64++ = *a_value = pcloc;
465 // '*' takes attributes of current section, not ABS!
466 *a_attr = cursect | DEFINED;
473 else if (*tok == STRING || *tok == SYMBOL)
476 j = (*p == '.' ? curenv : 0);
477 symbol = lookup(p, LABEL, j);
479 printf("eval: Looking up symbol (%s) [=%08X]\n", p, symbol);
481 printf(" attr=%04X, attre=%08X, val=%i, name=%s\n", symbol->sattr, symbol->sattre, symbol->svalue, symbol->sname);
485 symbol = NewSymbol(p, LABEL, j);
487 symbol->sattr |= REFERENCED;
489 // Check for undefined register equates, but only if it's not part
490 // of a #<SYMBOL> construct, as it could be that the label that's
491 // been undefined may later be used as an address label--which
492 // means it will be fixed up later, and thus, not an error.
493 if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
495 error("undefined register equate '%s'", symbol->sname);
496 //if we return right away, it returns some spurious errors...
500 // Check register bank usage
501 if (symbol->sattre & EQUATEDREG)
503 if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
504 warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
506 if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
507 warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
510 *evalTokenBuffer.u32++ = SYMBOL;
512 *evalTokenBuffer++ = (TOKEN)symbol;
515 While this approach works, it's wasteful. It would be better to use something
516 that's already available, like the symbol "order defined" table (which needs to
517 be converted from a linked list into an array).
519 *evalTokenBuffer.u32++ = symbolNum;
520 symbolPtr[symbolNum] = symbol;
524 *a_value = (symbol->sattr & DEFINED ? symbol->svalue : 0);
525 *a_attr = (WORD)(symbol->sattr & ~GLOBAL);
528 All that extra crap that was put into the svalue when doing the equr stuff is
529 thrown away right here. What the hell is it for?
531 if (symbol->sattre & EQUATEDREG)
534 *a_attr |= RISCREG; // Mark it as a register, 'cause it is
538 if ((symbol->sattr & (GLOBAL | DEFINED)) == GLOBAL
544 // Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
547 *evalTokenBuffer.u32++ = *tok++;
551 // Unknown type here... Alert the user!,
552 error("undefined RISC register in expression [token=$%X]", *tok);
553 // Prevent spurious error reporting...
558 *evalTokenBuffer.u32++ = ENDEXPR;
565 *evalTokenBuffer.u32++ = ENDEXPR;
566 return evexpr(otk, a_value, a_attr, a_esym);
571 // Evaluate expression.
572 // If the expression involves only ONE external symbol, the expression is
573 // UNDEFINED, but it's value includes everything but the symbol value, and
574 // 'a_esym' is set to the external symbol.
576 int evexpr(TOKEN * _tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
580 uint64_t * sval = evstk; // (Empty) initial stack
581 WORD * sattr = evattr;
582 SYM * esym = NULL; // No external symbol involved
587 while (*tk.u32 != ENDEXPR)
589 switch ((int)*tk.u32++)
592 //printf("evexpr(): SYMBOL\n");
593 sy = symbolPtr[*tk.u32++];
594 sy->sattr |= REFERENCED; // Set "referenced" bit
596 if (!(sy->sattr & DEFINED))
598 // Reference to undefined symbol
599 if (!(sy->sattr & GLOBAL))
606 if (esym != NULL) // Check for multiple externals
607 return error(seg_error);
612 if (sy->sattr & DEFINED)
613 *++sval = sy->svalue; // Push symbol's value
615 *++sval = 0; // 0 for undefined symbols
617 *++sattr = (WORD)(sy->sattr & ~GLOBAL); // Push attribs
618 sym_seg = (WORD)(sy->sattr & TDB);
623 //printf("evexpr(): CONST = %lX\n", *sval);
624 *++sattr = ABS | DEFINED; // Push simple attribs
628 //printf("evexpr(): FCONST = %lf\n", *tk.dp);
629 // Even though it's a double, we can treat it like a uint64_t since
630 // we're just moving the bits around.
632 *++sattr = ABS | DEFINED | FLOAT; // Push simple attribs
636 //printf("evexpr(): ACONST = %i\n", *tk.u32);
637 *++sval = *tk.u32++; // Push value
638 *++sattr = (WORD)*tk.u32++; // Push attribs
641 // Binary "+" and "-" matrix:
644 // ----------------------------
645 // ABS | ABS | Sect | Other |
646 // Sect | Sect | [1] | Error |
647 // Other | Other | Error | [1] |
648 // ----------------------------
654 //printf("evexpr(): +\n");
656 --sattr; // Pop attrib
657 //printf("--> N+N: %i + %i = ", *sval, sval[1]);
658 // Get FLOAT attribute, if any
659 attr = (sattr[0] | sattr[1]) & FLOAT;
661 // Since adding an int to a fp value promotes it to a fp value, we
662 // don't care whether it's first or second; we cast to to a double
668 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
670 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
671 *(double *)sval = fpval1 + fpval2;
675 *sval += sval[1]; // Compute value
677 //printf("%i\n", *sval);
680 *sattr = sattr[1] | attr;
681 else if (sattr[1] & TDB)
682 return error(seg_error);
687 //printf("evexpr(): -\n");
689 --sattr; // Pop attrib
690 //printf("--> N-N: %i - %i = ", *sval, sval[1]);
691 // Get FLOAT attribute, if any
692 attr = (sattr[0] | sattr[1]) & FLOAT;
694 // Since subtracting an int to a fp value promotes it to a fp
695 // value, we don't care whether it's first or second; we cast to to
696 // a double regardless.
701 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
703 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
704 *(double *)sval = fpval1 - fpval2;
710 //printf("%i\n", *sval);
712 *sattr |= attr; // Inherit FLOAT attribute
713 attr = (WORD)(*sattr & TDB);
715 printf("EVEXPR (-): sym1 = %X, sym2 = %X\n", attr, sattr[1]);
717 // If symbol1 is ABS, take attributes from symbol2
720 // Otherwise, they're both TDB and so attributes cancel out
721 else if (sattr[1] & TDB)
726 // Unary operators only work on ABS items
728 //printf("evexpr(): UNMINUS\n");
730 return error(seg_error);
734 double * dst = (double *)sval;
736 *sattr = ABS | DEFINED | FLOAT; // Expr becomes absolute
740 *sval = -(int64_t)*sval;
741 *sattr = ABS | DEFINED; // Expr becomes absolute
746 case UNLT: // Unary < (get the low byte of a word)
747 //printf("evexpr(): UNLT\n");
749 return error(seg_error);
752 return error(noflt_error);
754 *sval = (int64_t)((*sval) & 0x00FF);
755 *sattr = ABS | DEFINED; // Expr becomes absolute
758 case UNGT: // Unary > (get the high byte of a word)
759 //printf("evexpr(): UNGT\n");
761 return error(seg_error);
764 return error(noflt_error);
766 *sval = (int64_t)(((*sval) >> 8) & 0x00FF);
767 *sattr = ABS | DEFINED; // Expr becomes absolute
771 //printf("evexpr(): !\n");
773 return error(seg_error);
776 return error("floating point numbers not allowed with operator '!'.");
779 *sattr = ABS | DEFINED; // Expr becomes absolute
783 //printf("evexpr(): ~\n");
785 return error(seg_error);
788 return error("floating point numbers not allowed with operator '~'.");
791 *sattr = ABS | DEFINED; // Expr becomes absolute
794 // Comparison operators must have two values that
795 // are in the same segment, but that's the only requirement.
797 //printf("evexpr(): LE\n");
801 if ((*sattr & TDB) != (sattr[1] & TDB))
802 return error(seg_error);
804 // Get FLOAT attribute, if any
805 attr = (sattr[0] | sattr[1]) & FLOAT;
807 // Cast any ints in the comparison to double, if there's at least
808 // one double in the comparison.
813 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
815 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
816 *sval = (fpval1 <= fpval2);
820 *sval = (*sval <= sval[1]);
823 *sattr = ABS | DEFINED;
827 //printf("evexpr(): GE\n");
831 if ((*sattr & TDB) != (sattr[1] & TDB))
832 return error(seg_error);
834 // Get FLOAT attribute, if any
835 attr = (sattr[0] | sattr[1]) & FLOAT;
837 // Cast any ints in the comparison to double, if there's at least
838 // one double in the comparison.
843 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
845 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
846 *sval = (fpval1 >= fpval2);
850 *sval = (*sval >= sval[1]);
853 *sattr = ABS | DEFINED;
857 //printf("evexpr(): >\n");
861 if ((*sattr & TDB) != (sattr[1] & TDB))
862 return error(seg_error);
864 // Get FLOAT attribute, if any
865 attr = (sattr[0] | sattr[1]) & FLOAT;
867 // Cast any ints in the comparison to double, if there's at least
868 // one double in the comparison.
873 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
875 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
876 *sval = (fpval1 > fpval2);
880 *sval = (*sval > sval[1]);
883 *sattr = ABS | DEFINED;
887 //printf("evexpr(): <\n");
891 if ((*sattr & TDB) != (sattr[1] & TDB))
892 return error(seg_error);
894 // Get FLOAT attribute, if any
895 attr = (sattr[0] | sattr[1]) & FLOAT;
897 // Cast any ints in the comparison to double, if there's at least
898 // one double in the comparison.
903 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
905 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
906 *sval = (fpval1 < fpval2);
910 *sval = (*sval < sval[1]);
913 *sattr = ABS | DEFINED; // Expr forced to ABS
917 //printf("evexpr(): NE\n");
921 if ((*sattr & TDB) != (sattr[1] & TDB))
922 return error(seg_error);
924 // Get FLOAT attribute, if any
925 attr = (sattr[0] | sattr[1]) & FLOAT;
927 // Cast any ints in the comparison to double, if there's at least
928 // one double in the comparison.
933 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
935 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
936 *sval = (fpval1 != fpval2);
940 *sval = (*sval != sval[1]);
943 *sattr = ABS | DEFINED; // Expr forced to ABS
947 //printf("evexpr(): =\n");
951 if ((*sattr & TDB) != (sattr[1] & TDB))
952 return error(seg_error);
954 // Get FLOAT attribute, if any
955 attr = (sattr[0] | sattr[1]) & FLOAT;
957 // Cast any ints in the comparison to double, if there's at least
958 // one double in the comparison.
963 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
965 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
966 *sval = (fpval1 == fpval2);
970 *sval = (*sval == sval[1]);
973 *sattr = ABS | DEFINED; // Expr forced to ABS
977 // All other binary operators must have two ABS items to work with.
978 // They all produce an ABS value.
979 // Shamus: Is this true? There's at least one counterexample of legit
980 // code where this assumption fails to produce correct code.
982 //printf("evexpr(): default\n");
984 switch ((int)tk.u32[-1])
989 //printf("--> NxN: %i x %i = ", *sval, sval[1]);
990 // Get FLOAT attribute, if any
991 attr = (sattr[0] | sattr[1]) & FLOAT;
993 // Since multiplying an int to a fp value promotes it to a fp
994 // value, we don't care whether it's first or second; it will
995 // be cast to a double regardless.
997 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.
1003 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
1005 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
1006 *(double *)sval = fpval1 * fpval2;
1012 //printf("%i\n", *sval);
1014 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1020 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1021 // Get FLOAT attribute, if any
1022 attr = (sattr[0] | sattr[1]) & FLOAT;
1028 double fpval1 = (sattr[0] & FLOAT ? *p.dp : (double)*p.i64);
1030 double fpval2 = (sattr[1] & FLOAT ? *p.dp : (double)*p.i64);
1033 return error("divide by zero");
1035 *(double *)sval = fpval1 / fpval2;
1040 return error("divide by zero");
1041 //printf("--> N/N: %i / %i = ", sval[0], sval[1]);
1043 // Compiler is picky here: Without casting these, it
1044 // discards the sign if dividing a negative # by a
1045 // positive one, creating a bad result. :-/
1046 // Definitely a side effect of using uint32_ts intead of
1048 *sval = (int32_t)sval[0] / (int32_t)sval[1];
1050 //printf("%i\n", *sval);
1052 //no *sattr = ABS | DEFINED | attr; // Expr becomes absolute
1059 if ((*sattr | sattr[1]) & FLOAT)
1060 return error("floating point numbers not allowed with operator '%'.");
1063 return error("mod (%) by zero");
1066 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1071 sattr--; // Pop attrib
1073 if ((*sattr | sattr[1]) & FLOAT)
1074 return error("floating point numbers not allowed with operator '<<'.");
1077 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1082 sattr--; // Pop attrib
1084 if ((*sattr | sattr[1]) & FLOAT)
1085 return error("floating point numbers not allowed with operator '>>'.");
1088 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1093 sattr--; // Pop attrib
1095 if ((*sattr | sattr[1]) & FLOAT)
1096 return error("floating point numbers not allowed with operator '&'.");
1099 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1104 sattr--; // Pop attrib
1106 if ((*sattr | sattr[1]) & FLOAT)
1107 return error("floating point numbers not allowed with operator '^'.");
1110 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1117 if ((*sattr | sattr[1]) & FLOAT)
1118 return error("floating point numbers not allowed with operator '|'.");
1121 //no *sattr = ABS | DEFINED; // Expr becomes absolute
1125 // Bad operator in expression stream (this should never happen!)
1137 // Copy value + attrib into return variables
1146 // Count the # of tokens in the passed in expression
1147 // N.B.: 64-bit constants count as two tokens each
1149 uint16_t ExpressionLength(TOKEN * tk)
1153 for(length=0; tk[length]!=ENDEXPR; length++)
1155 // Add one to length for 2X tokens, two for 3X tokens
1156 if (tk[length] == SYMBOL)
1158 else if ((tk[length] == CONST) || (tk[length] == FCONST))
1162 // Add 1 for ENDEXPR