diff options
author | Oliver Kiddle <opk@users.sourceforge.net> | 2000-04-30 17:58:35 +0000 |
---|---|---|
committer | Oliver Kiddle <opk@users.sourceforge.net> | 2000-04-30 17:58:35 +0000 |
commit | ddd8614e5149a5aabde1acef1609084003adbc80 (patch) | |
tree | caec96cf9ce80ba08adb3402b819c8d12faf164f /Src/math.c | |
parent | 3e43e5099282927fad9844f106b1cd8a361be03c (diff) | |
download | zsh-ddd8614e5149a5aabde1acef1609084003adbc80.tar.gz zsh-ddd8614e5149a5aabde1acef1609084003adbc80.tar.xz zsh-ddd8614e5149a5aabde1acef1609084003adbc80.zip |
AIX dependency fixes
Diffstat (limited to 'Src/math.c')
-rw-r--r-- | Src/math.c | 872 |
1 files changed, 533 insertions, 339 deletions
diff --git a/Src/math.c b/Src/math.c index 7a0a1f9bd..aee318cfc 100644 --- a/Src/math.c +++ b/Src/math.c @@ -30,11 +30,18 @@ #include "zsh.mdh" #include "math.pro" +#include <math.h> + /* nonzero means we are not evaluating, just parsing */ /**/ int noeval; +/* integer zero */ + +/**/ +mnumber zero_mnumber; + /* last input base we used */ /**/ @@ -42,8 +49,10 @@ int lastbase; static char *ptr; -static long yyval; -static LV yylval; +static mnumber yyval; +static char *yylval; + +#define MAX_MLEVEL 256 static int mlevel = 0; @@ -53,11 +62,39 @@ static int unary = 1; /* LR = left-to-right associativity * * RL = right-to-left associativity * - * BOO = short-circuiting boolean */ + * BOOL = short-circuiting boolean */ -#define LR 0 -#define RL 1 -#define BOOL 2 +#define LR 0x0000 +#define RL 0x0001 +#define BOOL 0x0002 + +#define MTYPE(x) ((x) & 3) + +/* + * OP_A2 2 arguments + * OP_A2IR 2 arguments, return integer + * OP_A2IO 2 arguments, must be integer, return integer + * OP_E2 2 arguments with assignment + * OP_E2IO 2 arguments with assignment, must be integer, return integer + * OP_OP None of the above, but occurs where we are expecting an operator + * rather than an operand. + * OP_OPF Followed by an operator, not an operand. + * + * OP_A2*, OP_E2*, OP_OP*: + * Occur when we need an operator; the next object must be an operand, + * unless OP_OPF is also supplied. + * + * Others: + * Occur when we need an operand; the next object must also be an operand, + * unless OP_OPF is also supplied. + */ +#define OP_A2 0x0004 +#define OP_A2IR 0x0008 +#define OP_A2IO 0x0010 +#define OP_E2 0x0020 +#define OP_E2IO 0x0040 +#define OP_OP 0x0080 +#define OP_OPF 0x0100 #define M_INPAR 0 #define M_OUTPAR 1 @@ -111,7 +148,8 @@ static int unary = 1; #define POWER 49 #define CID 50 #define POWEREQ 51 -#define TOKCOUNT 52 +#define FUNC 52 +#define TOKCOUNT 53 /* precedences */ @@ -122,45 +160,42 @@ static int prec[TOKCOUNT] = 6, 8, 8, 8, 9, 9, 3, 3, 10, 10, 10, 10, 11, 11, 12, - 13, 13, 14, 14, 15, - 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, - 15, 15, 15, 16, 200, + 13, 13, 14, 15, 16, + 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, + 16, 16, 16, 17, 200, 2, 2, 0, 0, 7, - 0, 15 + 0, 16, 0 }; -#define TOPPREC 16 +#define TOPPREC 17 #define ARGPREC (TOPPREC-1) static int type[TOKCOUNT] = { - LR, LR, RL, RL, RL, - RL, RL, RL, LR, LR, - LR, LR, LR, LR, LR, - LR, LR, LR, LR, LR, - LR, LR, LR, LR, BOOL, - BOOL, LR, RL, RL, RL, - RL, RL, RL, RL, RL, - RL, RL, RL, RL, RL, - BOOL, BOOL, RL, RL, RL, - RL, RL, LR, LR, RL, - LR, RL +/* 0 */ LR, LR|OP_OP|OP_OPF, RL, RL, RL|OP_OP|OP_OPF, +/* 5 */ RL|OP_OP|OP_OPF, RL, RL, LR|OP_A2IO, LR|OP_A2IO, +/* 10 */ LR|OP_A2IO, LR|OP_A2, LR|OP_A2, LR|OP_A2IO, LR|OP_A2, +/* 15 */ LR|OP_A2, LR|OP_A2IO, LR|OP_A2IO, LR|OP_A2IR, LR|OP_A2IR, +/* 20 */ LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, LR|OP_A2IR, BOOL|OP_A2IO, +/* 25 */ BOOL|OP_A2IO, LR|OP_A2IO, RL|OP_OP, RL|OP_OP, RL|OP_E2, +/* 30 */ RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2, RL|OP_E2IO, +/* 35 */ RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, RL|OP_E2IO, +/* 40 */ BOOL|OP_E2IO, BOOL|OP_E2IO, RL|OP_A2IO, RL|OP_A2, RL|OP_OP, +/* 45 */ RL, RL, LR|OP_OPF, LR|OP_OPF, RL|OP_A2, +/* 50 */ LR|OP_OPF, RL|OP_E2, LR|OP_OPF }; -#define LVCOUNT 32 - -/* list of lvalues (variables) */ - -static int lvc; -static char **lvals; - /**/ static int zzlex(void) { +#ifdef USE_LOCALE + char *prev_locale; +#endif int cct = 0; + yyval.type = MN_INTEGER; for (;; cct = 0) switch (*ptr++) { @@ -170,7 +205,6 @@ zzlex(void) return (unary) ? PREPLUS : POSTPLUS; } if (*ptr == '=') { - unary = 1; ptr++; return PLUSEQ; } @@ -181,19 +215,16 @@ zzlex(void) return (unary) ? PREMINUS : POSTMINUS; } if (*ptr == '=') { - unary = 1; ptr++; return MINUSEQ; } return (unary) ? UMINUS : MINUS; case '(': - unary = 1; return M_INPAR; case ')': return M_OUTPAR; case '!': if (*ptr == '=') { - unary = 1; ptr++; return NEQ; } @@ -201,7 +232,6 @@ zzlex(void) case '~': return COMP; case '&': - unary = 1; if (*ptr == '&') { if (*++ptr == '=') { ptr++; @@ -214,7 +244,6 @@ zzlex(void) } return AND; case '|': - unary = 1; if (*ptr == '|') { if (*++ptr == '=') { ptr++; @@ -227,7 +256,6 @@ zzlex(void) } return OR; case '^': - unary = 1; if (*ptr == '^') { if (*++ptr == '=') { ptr++; @@ -240,7 +268,6 @@ zzlex(void) } return XOR; case '*': - unary = 1; if (*ptr == '*') { if (*++ptr == '=') { ptr++; @@ -254,21 +281,18 @@ zzlex(void) } return MUL; case '/': - unary = 1; if (*ptr == '=') { ptr++; return DIVEQ; } return DIV; case '%': - unary = 1; if (*ptr == '=') { ptr++; return MODEQ; } return MOD; case '<': - unary = 1; if (*ptr == '<') { if (*++ptr == '=') { ptr++; @@ -281,7 +305,6 @@ zzlex(void) } return LES; case '>': - unary = 1; if (*ptr == '>') { if (*++ptr == '=') { ptr++; @@ -294,42 +317,34 @@ zzlex(void) } return GRE; case '=': - unary = 1; if (*ptr == '=') { ptr++; return DEQ; } return EQ; case '$': - unary = 0; - yyval = mypid; + yyval.u.l = mypid; return NUM; case '?': if (unary) { - yyval = lastval; - unary = 0; + yyval.u.l = lastval; return NUM; } - unary = 1; return QUEST; case ':': - unary = 1; return COLON; case ',': - unary = 1; return COMMA; case '\0': - unary = 1; ptr--; return EOI; case '[': - unary = 0; { int base = zstrtol(ptr, &ptr, 10); if (*ptr == ']') ptr++; - yyval = zstrtol(ptr, &ptr, lastbase = base); + yyval.u.l = zstrtol(ptr, &ptr, lastbase = base); return NUM; } case ' ': @@ -338,63 +353,78 @@ zzlex(void) break; case '0': if (*ptr == 'x' || *ptr == 'X') { - unary = 0; /* Should we set lastbase here? */ - yyval = zstrtol(++ptr, &ptr, lastbase = 16); + yyval.u.l = zstrtol(++ptr, &ptr, lastbase = 16); return NUM; } /* Fall through! */ default: - if (idigit(*--ptr)) { - unary = 0; - yyval = zstrtol(ptr, &ptr, 10); + if (idigit(*--ptr) || *ptr == '.') { + char *nptr; + for (nptr = ptr; idigit(*nptr); nptr++); - if (*ptr == '#') { - ptr++; - yyval = zstrtol(ptr, &ptr, lastbase = yyval); + if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') { + /* it's a float */ + yyval.type = MN_FLOAT; +#ifdef USE_LOCALE + prev_locale = setlocale(LC_NUMERIC, NULL); + setlocale(LC_NUMERIC, "POSIX"); +#endif + yyval.u.d = strtod(ptr, &nptr); +#ifdef USE_LOCALE + setlocale(LC_NUMERIC, prev_locale); +#endif + if (ptr == nptr || *nptr == '.') { + zerr("bad floating point constant", NULL, 0); + return EOI; + } + ptr = nptr; + } else { + /* it's an integer */ + yyval.u.l = zstrtol(ptr, &ptr, 10); + + if (*ptr == '#') { + ptr++; + yyval.u.l = zstrtol(ptr, &ptr, lastbase = yyval.u.l); + } } return NUM; } if (*ptr == '#') { - if (*++ptr == '\\') { - ptr++; - yyval = *ptr == Meta ? *++ptr ^ 32 : *ptr; + if (*++ptr == '\\' || *ptr == '#') { + int v; + ptr++; - unary = 0; + ptr = getkeystring(ptr, NULL, 6, &v); + yyval.u.l = v; return NUM; } cct = 1; } if (iident(*ptr)) { - char *p, q; + int func = 0; + char *p; p = ptr; - if (lvc == LVCOUNT) { - zerr("too many identifiers (complain to author)", NULL, 0); - return EOI; - } - unary = 0; while (iident(*++ptr)); - if (*ptr == '[') { + if (*ptr == '[' || (!cct && *ptr == '(')) { + char op = *ptr, cp = ((*ptr == '[') ? ']' : ')'); int l; + func = (op == '('); for (ptr++, l = 1; *ptr && l; ptr++) { - if (*ptr == '[') + if (*ptr == op) l++; - if (*ptr == ']') + if (*ptr == cp) l--; if (*ptr == '\\' && ptr[1]) ptr++; } } - q = *ptr; - *ptr = '\0'; - lvals[yylval = lvc++] = ztrdup(p); - *ptr = q; - return cct ? CID : ID; + yylval = dupstrpfx(p, ptr - p); + return (func ? FUNC : (cct ? CID : ID)); } else if (cct) { - yyval = poundgetfn(NULL); - unary = 0; + yyval.u.l = poundgetfn(NULL); return NUM; } return EOI; @@ -408,15 +438,15 @@ static int mtok; /* last token */ static int sp = -1; /* stack pointer */ struct mathvalue { - LV lval; - long val; + char *lval; + mnumber val; }; static struct mathvalue *stack; /**/ static void -push(long val, LV lval) +push(mnumber val, char *lval) { if (sp == STACKSZ - 1) zerr("stack overflow", NULL, 0); @@ -428,275 +458,374 @@ push(long val, LV lval) /**/ -static long -getcvar(LV s) +static mnumber +getcvar(char *s) { char *t; + mnumber mn; + mn.type = MN_INTEGER; - if (!(t = getsparam(lvals[s]))) - return 0; - return STOUC(*t == Meta ? t[1] ^ 32 : *t); + if (!(t = getsparam(s))) + mn.u.l = 0; + else + mn.u.l = STOUC(*t == Meta ? t[1] ^ 32 : *t); + return mn; } /**/ -static long -setvar(LV s, long v) +static mnumber +setvar(char *s, mnumber v) { - if (s == -1 || s >= lvc) { + if (!s) { zerr("lvalue required", NULL, 0); - return 0; + v.type = MN_INTEGER; + v.u.l = 0; + return v; } if (noeval) return v; - setiparam(lvals[s], v); + setnparam(s, v); return v; } /**/ +static mnumber +callmathfunc(char *o) +{ + MathFunc f; + char *a, *n; + static mnumber dummy; + + n = a = dupstring(o); + + while (*a != '(') + a++; + *a++ = '\0'; + a[strlen(a) - 1] = '\0'; + + if ((f = getmathfunc(n, 1))) { + if (f->flags & MFF_STR) + return f->sfunc(n, a, f->funcid); + else { + int argc = 0; + mnumber *argv = NULL, *q; + LinkList l = newlinklist(); + LinkNode node; + + while (iblank(*a)) + a++; + while (*a) { + if (*a) { + argc++; + q = (mnumber *) zhalloc(sizeof(mnumber)); + *q = mathevall(a, ARGPREC, &a); + addlinknode(l, q); + if (errflag || mtok != COMMA) + break; + } + } + if (*a && !errflag) + zerr("bad math expression: illegal character: %c", + NULL, *a); + if (!errflag) { + if (argc >= f->minargs && (f->maxargs < 0 || + argc <= f->maxargs)) { + if (argc) { + q = argv = (mnumber *)zhalloc(argc * sizeof(mnumber)); + for (node = firstnode(l); node; incnode(node)) + *q++ = *(mnumber *)getdata(node); + } + return f->nfunc(n, argc, argv, f->funcid); + } else + zerr("wrong number of arguments: %s", o, 0); + } + } + } else + zerr("unknown function: %s", n, 0); + + dummy.type = MN_INTEGER; + dummy.u.l = 0; + + return dummy; +} + +/**/ static int -notzero(long a) +notzero(mnumber a) { - if (a == 0) { + if ((a.type & MN_INTEGER) ? a.u.l == 0 : a.u.d == 0.0) { zerr("division by zero", NULL, 0); return 0; } return 1; } -/* macro to pop two values off the value stack */ -#define pop2() { \ - if (sp < 1) { \ - zerr("bad math expression: unbalanced stack", NULL, 0); \ - return; \ - } \ - b = stack[sp--].val; \ - a = stack[sp--].val; \ - } - /* macro to pop three values off the value stack */ -#define pop3() { \ - if (sp < 2) { \ - zerr("bad math expression: unbalanced stack", NULL, 0); \ - return; \ - } \ - c = stack[sp--].val; \ - b = stack[sp--].val; \ - a = stack[sp--].val; \ - } - -#define nolval() {stack[sp].lval= -1;} -#define pushv(X) { push(X,-1); } -#define pop2lv() { pop2() lv = stack[sp+1].lval; } -#define set(X) { push(setvar(lv,X),lv); } - /**/ void op(int what) { - long a, b, c; - LV lv; + mnumber a, b, c, *spval; + char *lv; + int tp = type[what]; + if (errflag) + return; if (sp < 0) { zerr("bad math expression: stack empty", NULL, 0); return; } + + if (tp & (OP_A2|OP_A2IR|OP_A2IO|OP_E2|OP_E2IO)) { + /* Make sure anyone seeing this message reports it. */ + DPUTS(sp < 1, "BUG: math: not enough wallabies in outback."); + b = stack[sp--].val; + a = stack[sp--].val; + + if (tp & (OP_A2IO|OP_E2IO)) { + /* coerce to integers */ + if (a.type & MN_FLOAT) { + a.type = MN_INTEGER; + a.u.l = (zlong)a.u.d; + } + if (b.type & MN_FLOAT) { + b.type = MN_INTEGER; + b.u.l = (zlong)b.u.d; + } + } else if (a.type != b.type && what != COMMA) { + /* + * Different types, so coerce to float. + * It may happen during an assigment that the LHS + * variable is actually an integer, but there's still + * no harm in doing the arithmetic in floating point; + * the assignment will do the correct conversion. + * This way, if the parameter is actually a scalar, but + * used to contain an integer, we can write a float into it. + */ + if (a.type & MN_INTEGER) { + a.type = MN_FLOAT; + a.u.d = (double)a.u.l; + } + if (b.type & MN_INTEGER) { + b.type = MN_FLOAT; + b.u.d = (double)b.u.l; + } + } + + if (noeval) { + c.type = MN_INTEGER; + c.u.l = 0; + } else { + /* + * type for operation: usually same as operands, but e.g. + * (a == b) returns int. + */ + c.type = (tp & OP_A2IR) ? MN_INTEGER : a.type; + + switch(what) { + case AND: + case ANDEQ: + c.u.l = a.u.l & b.u.l; + break; + case XOR: + case XOREQ: + c.u.l = a.u.l ^ b.u.l; + break; + case OR: + case OREQ: + c.u.l = a.u.l | b.u.l; + break; + case MUL: + case MULEQ: + if (c.type == MN_FLOAT) + c.u.d = a.u.d * b.u.d; + else + c.u.l = a.u.l * b.u.l; + break; + case DIV: + case DIVEQ: + if (!notzero(b)) + return; + if (c.type == MN_FLOAT) + c.u.d = a.u.d / b.u.d; + else + c.u.l = a.u.l / b.u.l; + break; + case MOD: + case MODEQ: + if (!notzero(b)) + return; + c.u.l = a.u.l % b.u.l; + break; + case PLUS: + case PLUSEQ: + if (c.type == MN_FLOAT) + c.u.d = a.u.d + b.u.d; + else + c.u.l = a.u.l + b.u.l; + break; + case MINUS: + case MINUSEQ: + if (c.type == MN_FLOAT) + c.u.d = a.u.d - b.u.d; + else + c.u.l = a.u.l - b.u.l; + break; + case SHLEFT: + case SHLEFTEQ: + c.u.l = a.u.l << b.u.l; + break; + case SHRIGHT: + case SHRIGHTEQ: + c.u.l = a.u.l >> b.u.l; + break; + case LES: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d < b.u.d) : (a.u.l < b.u.l)); + break; + case LEQ: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d <= b.u.d) : (a.u.l <= b.u.l)); + break; + case GRE: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d > b.u.d) : (a.u.l > b.u.l)); + break; + case GEQ: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d >= b.u.d) : (a.u.l >= b.u.l)); + break; + case DEQ: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d == b.u.d) : (a.u.l == b.u.l)); + break; + case NEQ: + c.u.l = (zlong) + (a.type == MN_FLOAT ? (a.u.d != b.u.d) : (a.u.l != b.u.l)); + break; + case DAND: + case DANDEQ: + c.u.l = (zlong)(a.u.l && b.u.l); + break; + case DOR: + case DOREQ: + c.u.l = (zlong)(a.u.l || b.u.l); + break; + case DXOR: + case DXOREQ: + c.u.l = (zlong)((a.u.l && !b.u.l) || (!a.u.l && b.u.l)); + break; + case COMMA: + c = b; + break; + case POWER: + case POWEREQ: + if (c.type == MN_INTEGER && b.u.l < 0) { + /* produces a real result, so cast to real. */ + a.type = b.type = c.type = MN_FLOAT; + a.u.d = (double) a.u.l; + b.u.d = (double) b.u.l; + } + if (c.type == MN_INTEGER) { + for (c.u.l = 1; b.u.l--; c.u.l *= a.u.l); + } else { + if (b.u.d <= 0 && !notzero(a)) + return; + if (a.u.d < 0) { + /* Error if (-num ** b) and b is not an integer */ + double tst = (double)(zlong)b.u.d; + if (tst != b.u.d) { + zerr("imaginary power", NULL, 0); + return; + } + } + c.u.d = pow(a.u.d, b.u.d); + } + break; + case EQ: + c = b; + break; + } + } + if (tp & (OP_E2|OP_E2IO)) { + lv = stack[sp+1].lval; + push(setvar(lv,c), lv); + } else + push(c,NULL); + return; + } + + spval = &stack[sp].val; switch (what) { case NOT: - stack[sp].val = !stack[sp].val; - nolval(); + if (spval->type & MN_FLOAT) { + spval->u.l = !spval->u.d; + spval->type = MN_INTEGER; + } else + spval->u.l = !spval->u.l; + stack[sp].lval = NULL; break; case COMP: - stack[sp].val = ~stack[sp].val; - nolval(); + if (spval->type & MN_FLOAT) { + spval->u.l = ~((zlong)spval->u.d); + spval->type = MN_INTEGER; + } else + spval->u.l = ~spval->u.l; + stack[sp].lval = NULL; break; case POSTPLUS: - (void)setvar(stack[sp].lval, stack[sp].val + 1); + a = *spval; + if (spval->type & MN_FLOAT) + a.u.d++; + else + a.u.l++; + (void)setvar(stack[sp].lval, a); break; case POSTMINUS: - (void)setvar(stack[sp].lval, stack[sp].val - 1); + a = *spval; + if (spval->type & MN_FLOAT) + a.u.d--; + else + a.u.l--; + (void)setvar(stack[sp].lval, a); break; case UPLUS: - nolval(); + stack[sp].lval = NULL; break; case UMINUS: - stack[sp].val = -stack[sp].val; - nolval(); - break; - case AND: - pop2(); - pushv(a & b); - break; - case XOR: - pop2(); - pushv(a ^ b); - break; - case OR: - pop2(); - pushv(a | b); - break; - case MUL: - pop2(); - pushv(a * b); - break; - case DIV: - pop2(); - if (notzero(b)) - pushv(a / b); - break; - case MOD: - pop2(); - if (notzero(b)) - pushv(a % b); - break; - case PLUS: - pop2(); - pushv(a + b); - break; - case MINUS: - pop2(); - pushv(a - b); - break; - case SHLEFT: - pop2(); - pushv(a << b); - break; - case SHRIGHT: - pop2(); - pushv(a >> b); - break; - case LES: - pop2(); - pushv((long)(a < b)); - break; - case LEQ: - pop2(); - pushv((long)(a <= b)); - break; - case GRE: - pop2(); - pushv((long)(a > b)); - break; - case GEQ: - pop2(); - pushv((long)(a >= b)); - break; - case DEQ: - pop2(); - pushv((long)(a == b)); - break; - case NEQ: - pop2(); - pushv((long)(a != b)); - break; - case DAND: - pop2(); - pushv((long)(a && b)); - break; - case DOR: - pop2(); - pushv((long)(a || b)); - break; - case DXOR: - pop2(); - pushv((long)((a && !b) || (!a && b))); + if (spval->type & MN_FLOAT) + spval->u.d = -spval->u.d; + else + spval->u.l = -spval->u.l; + stack[sp].lval = NULL; break; case QUEST: - pop3(); - pushv((a) ? b : c); + DPUTS(sp < 2, "BUG: math: three shall be the number of the counting."); + c = stack[sp--].val; + b = stack[sp--].val; + a = stack[sp--].val; + /* b and c can stay different types in this case. */ + push(((a.type & MN_FLOAT) ? a.u.d : a.u.l) ? b : c, NULL); break; case COLON: - break; - case EQ: - pop2(); - lv = stack[sp + 1].lval; - set(b); - break; - case PLUSEQ: - pop2lv(); - set(a + b); - break; - case MINUSEQ: - pop2lv(); - set(a - b); - break; - case MULEQ: - pop2lv(); - set(a * b); - break; - case DIVEQ: - pop2lv(); - if (notzero(b)) - set(a / b); - break; - case MODEQ: - pop2lv(); - if (notzero(b)) - set(a % b); - break; - case ANDEQ: - pop2lv(); - set(a & b); - break; - case XOREQ: - pop2lv(); - set(a ^ b); - break; - case OREQ: - pop2lv(); - set(a | b); - break; - case SHLEFTEQ: - pop2lv(); - set(a << b); - break; - case SHRIGHTEQ: - pop2lv(); - set(a >> b); - break; - case DANDEQ: - pop2lv(); - set((long)(a && b)); - break; - case DOREQ: - pop2lv(); - set((long)(a || b)); - break; - case DXOREQ: - pop2lv(); - set((long)((a && !b) || (!a && b))); - break; - case COMMA: - pop2(); - pushv(b); + zerr("':' without '?'", NULL, 0); break; case PREPLUS: - stack[sp].val = setvar(stack[sp].lval, - stack[sp].val + 1); + if (spval->type & MN_FLOAT) + spval->u.d++; + else + spval->u.l++; + setvar(stack[sp].lval, *spval); break; case PREMINUS: - stack[sp].val = setvar(stack[sp].lval, - stack[sp].val - 1); - break; - case POWER: - pop2(); - if (b < 0) { - zerr("can't handle negative exponents", NULL, 0); - return; - } - for (c = 1; b--; c *= a); - pushv(c); - break; - case POWEREQ: - pop2lv(); - if (b < 0) { - zerr("can't handle negative exponents", NULL, 0); - return; - } - for (c = 1; b--; c *= a); - set(c); + if (spval->type & MN_FLOAT) + spval->u.d--; + else + spval->u.l--; + setvar(stack[sp].lval, *spval); break; default: zerr("out of integers", NULL, 0); @@ -709,15 +838,18 @@ op(int what) static void bop(int tk) { + mnumber *spval = &stack[sp].val; + int tst = (spval->type & MN_FLOAT) ? (zlong)spval->u.d : spval->u.l; + switch (tk) { case DAND: case DANDEQ: - if (!stack[sp].val) + if (!tst) noeval++; break; case DOR: case DOREQ: - if (stack[sp].val) + if (tst) noeval++; break; }; @@ -725,61 +857,63 @@ bop(int tk) /**/ -static long +static mnumber mathevall(char *s, int prek, char **ep) { - int t0; - int xlastbase, xnoeval, xunary, xlvc; + int xlastbase, xnoeval, xunary; char *xptr; - long xyyval; - LV xyylval; - char **xlvals = 0; + mnumber xyyval; + char *xyylval; int xsp; - struct mathvalue *xstack = 0; - long ret; + struct mathvalue *xstack = 0, nstack[STACKSZ]; + mnumber ret; + + if (mlevel >= MAX_MLEVEL) { + xyyval.type = MN_INTEGER; + xyyval.u.l = 0; - xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0; - xptr = NULL; + zerr("math recursion limit exceeded", NULL, 0); + + return xyyval; + } if (mlevel++) { xlastbase = lastbase; xnoeval = noeval; xunary = unary; - xlvc = lvc; xptr = ptr; xyyval = yyval; xyylval = yylval; - xlvals = lvals; xsp = sp; xstack = stack; + } else { + xlastbase = xnoeval = xunary = xsp = 0; + xyyval.type = MN_INTEGER; + xyyval.u.l = 0; + xyylval = NULL; + xptr = NULL; } - stack = (struct mathvalue *)zalloc(STACKSZ*sizeof(struct mathvalue)); + stack = nstack; lastbase = -1; - lvals = (char **)zcalloc(LVCOUNT*sizeof(char *)); - lvc = 0; ptr = s; sp = -1; unary = 1; + stack[0].val.type = MN_INTEGER; + stack[0].val.u.l = 0; mathparse(prek); *ep = ptr; - if (sp) - zerr("bad math expression: unbalanced stack", NULL, 0); - for (t0 = 0; t0 != lvc; t0++) - zsfree(lvals[t0]); + DPUTS(!errflag && sp, + "BUG: math: wallabies roaming too freely in outback"); ret = stack[0].val; - zfree(lvals, LVCOUNT*sizeof(char *)); - zfree(stack, STACKSZ*sizeof(struct mathvalue)); if (--mlevel) { lastbase = xlastbase; noeval = xnoeval; unary = xunary; - lvc = xlvc; ptr = xptr; yyval = xyyval; yylval = xyylval; - lvals = xlvals; sp = xsp; stack = xstack; @@ -789,15 +923,18 @@ mathevall(char *s, int prek, char **ep) /**/ -long +mod_export mnumber matheval(char *s) { char *junk; - long x; + mnumber x; int xmtok = mtok; - if (!*s) - return 0; + if (!*s) { + x.type = MN_INTEGER; + x.u.l = 0; + return x; + } x = mathevall(s, TOPPREC, &junk); mtok = xmtok; if (*junk) @@ -805,21 +942,64 @@ matheval(char *s) return x; } +/**/ +mod_export zlong +mathevali(char *s) +{ + mnumber x = matheval(s); + return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l; +} + /**/ -long +zlong mathevalarg(char *s, char **ss) { - long x; + mnumber x; int xmtok = mtok; x = mathevall(s, ARGPREC, ss); if (mtok == COMMA) (*ss)--; mtok = xmtok; - return x; + return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l; } +/* + * Make sure we have an operator or an operand, whatever is expected. + * For this purpose, unary operators constitute part of an operand. + */ + +/**/ +static void +checkunary(int mtokc, char *mptr) +{ + int errmsg = 0; + int tp = type[mtokc]; + if (tp & (OP_A2|OP_A2IR|OP_A2IO|OP_E2|OP_E2IO|OP_OP)) { + if (unary) + errmsg = 1; + } else { + if (!unary) + errmsg = 2; + } + if (errmsg) { + char errbuf[80]; + int len, over = 0; + while (inblank(*mptr)) + mptr++; + len = ztrlen(mptr); + if (len > 10) { + len = 10; + over = 1; + } + sprintf(errbuf, "bad math expression: %s expected at `%%l%s'", + errmsg == 2 ? "operator" : "operand", + over ? "..." : ""); + zerr(errbuf, mptr, len); + } + unary = !(tp & OP_OPF); +} /* operator-precedence parse the string and execute */ @@ -827,23 +1007,29 @@ mathevalarg(char *s, char **ss) static void mathparse(int pc) { - int q, otok, onoeval; + zlong q; + int otok, onoeval; + char *optr = ptr; if (errflag) return; mtok = zzlex(); + checkunary(mtok, optr); while (prec[mtok] <= pc) { if (errflag) return; switch (mtok) { case NUM: - push(yyval, -1); + push(yyval, NULL); break; case ID: - push(getiparam(lvals[yylval]), yylval); + push((noeval ? zero_mnumber : getnparam(yylval)), yylval); break; case CID: - push(getcvar(yylval), yylval); + push((noeval ? zero_mnumber : getcvar(yylval)), yylval); + break; + case FUNC: + push((noeval ? zero_mnumber : callmathfunc(yylval)), yylval); break; case M_INPAR: mathparse(TOPPREC); @@ -854,14 +1040,20 @@ mathparse(int pc) } break; case QUEST: - q = stack[sp].val; + q = (stack[sp].val.type == MN_FLOAT) ? (zlong)stack[sp].val.u.d : + stack[sp].val.u.l; if (!q) noeval++; - mathparse(prec[QUEST] - 1); + mathparse(prec[COLON] - 1); if (!q) noeval--; - else + if (mtok != COLON) { + if (!errflag) + zerr("':' expected", NULL, 0); + return; + } + if (q) noeval++; mathparse(prec[QUEST]); if (q) @@ -871,13 +1063,15 @@ mathparse(int pc) default: otok = mtok; onoeval = noeval; - if (type[otok] == BOOL) + if (MTYPE(type[otok]) == BOOL) bop(otok); - mathparse(prec[otok] - (type[otok] != RL)); + mathparse(prec[otok] - (MTYPE(type[otok]) != RL)); noeval = onoeval; op(otok); continue; } + optr = ptr; mtok = zzlex(); + checkunary(mtok, optr); } } |