about summary refs log tree commit diff
path: root/Src/math.c
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-09-17 15:12:01 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-09-17 15:12:01 +0000
commitd0f024f1527bdae5ad40e0b1076723e94e752459 (patch)
treea44a43ae855600e8fef521acabbbc26efc530829 /Src/math.c
parent77c1b9a3d42d1453182cf6882c548d096ac2ad83 (diff)
downloadzsh-d0f024f1527bdae5ad40e0b1076723e94e752459.tar.gz
zsh-d0f024f1527bdae5ad40e0b1076723e94e752459.tar.xz
zsh-d0f024f1527bdae5ad40e0b1076723e94e752459.zip
manual/7915
Diffstat (limited to 'Src/math.c')
-rw-r--r--Src/math.c590
1 files changed, 337 insertions, 253 deletions
diff --git a/Src/math.c b/Src/math.c
index 10821b284..f91a58ea8 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -30,6 +30,8 @@
 #include "zsh.mdh"
 #include "math.pro"
 
+#include <math.h>
+
 /* nonzero means we are not evaluating, just parsing */
  
 /**/
@@ -42,7 +44,7 @@ int lastbase;
  
 static char *ptr;
 
-static zlong yyval;
+static mnumber yyval;
 static LV yylval;
 
 static int mlevel = 0;
@@ -53,12 +55,27 @@ 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 MTYPE(x)  ((x) & 3)
+
+/*
+ * OP_A2 2 argument
+ * OP_A2IR 2 argument with return type integer
+ * OP_A2IO 2 arguments, must be integer, returning integer
+ * OP_E2 2 argument with assignment
+ * OP_E2IO 2 arguments with assignment, must be integer, return integer
+ */
+#define OP_A2   4
+#define OP_A2IR 8
+#define OP_A2IO 16
+#define OP_E2   32
+#define OP_E2IO 64
+
 #define M_INPAR 0
 #define M_OUTPAR 1
 #define NOT 2
@@ -135,17 +152,17 @@ static int prec[TOKCOUNT] =
 
 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, RL, RL, RL,
+/*  5 */    RL, 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, RL, 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,
+/* 45 */    RL, RL, LR, LR, RL|OP_A2,
+/* 50 */    LR, RL|OP_E2
 };
 
 #define LVCOUNT 32
@@ -162,6 +179,7 @@ zzlex(void)
 {
     int cct = 0;
 
+    yyval.type = MN_INTEGER;
     for (;; cct = 0)
 	switch (*ptr++) {
 	case '+':
@@ -302,11 +320,11 @@ zzlex(void)
 	    return EQ;
 	case '$':
 	    unary = 0;
-	    yyval = mypid;
+	    yyval.u.l = mypid;
 	    return NUM;
 	case '?':
 	    if (unary) {
-		yyval = lastval;
+		yyval.u.l = lastval;
 		unary = 0;
 		return NUM;
 	    }
@@ -329,7 +347,7 @@ zzlex(void)
 
 		if (*ptr == ']')
 		    ptr++;
-		yyval = zstrtol(ptr, &ptr, lastbase = base);
+		yyval.u.l = zstrtol(ptr, &ptr, lastbase = base);
 		return NUM;
 	    }
 	case ' ':
@@ -340,18 +358,33 @@ zzlex(void)
 	    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)) {
+	    if (idigit(*--ptr) || *ptr == '.') {
+		char *nptr;
 		unary = 0;
-		yyval = zstrtol(ptr, &ptr, 10);
-
-		if (*ptr == '#') {
-		    ptr++;
-		    yyval = zstrtol(ptr, &ptr, lastbase = yyval);
+		for (nptr = ptr; idigit(*nptr); nptr++);
+
+		if (*nptr == '.' || *nptr == 'e' || *nptr == 'E') {
+		    /* it's a float */
+		    yyval.type = MN_FLOAT;
+		    yyval.u.d = strtod(ptr, &nptr);
+		    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;
 	    }
@@ -361,7 +394,7 @@ zzlex(void)
 
 		    ptr++;
 		    ptr = getkeystring(ptr, NULL, 6, &v);
-		    yyval = v;
+		    yyval.u.l = v;
 		    unary = 0;
 		    return NUM;
 		}
@@ -395,7 +428,7 @@ zzlex(void)
 		return cct ? CID : ID;
 	    }
 	    else if (cct) {
-		yyval = poundgetfn(NULL);
+		yyval.u.l = poundgetfn(NULL);
 		unary = 0;
 		return NUM;
 	    }
@@ -411,14 +444,14 @@ static int sp = -1;			/* stack pointer */
 
 struct mathvalue {
     LV lval;
-    zlong val;
+    mnumber val;
 };
 
 static struct mathvalue *stack;
 
 /**/
 static void
-push(zlong val, LV lval)
+push(mnumber val, LV lval)
 {
     if (sp == STACKSZ - 1)
 	zerr("stack overflow", NULL, 0);
@@ -430,275 +463,308 @@ push(zlong val, LV lval)
 
 
 /**/
-static zlong
+static mnumber
 getcvar(LV s)
 {
     char *t;
+    mnumber mn;
+    mn.type = MN_INTEGER;
 
     if (!(t = getsparam(lvals[s])))
-	return 0;
-    return STOUC(*t == Meta ? t[1] ^ 32 : *t);
+	mn.u.l = 0;
+    else
+        mn.u.l = STOUC(*t == Meta ? t[1] ^ 32 : *t);
+    return mn;
 }
 
 
 /**/
-static zlong
-setvar(LV s, zlong v)
+static mnumber
+setvar(LV s, mnumber v)
 {
     if (s == -1 || s >= lvc) {
 	zerr("lvalue required", NULL, 0);
-	return 0;
+	v.type = MN_INTEGER;
+	v.u.l = 0;
     }
     if (noeval)
 	return v;
-    setiparam(lvals[s], v);
+    setnparam(lvals[s], v);
     return v;
 }
 
 
 /**/
 static int
-notzero(zlong 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)
 {
-    zlong a, b, c;
+    mnumber a, b, c, *spval;
     LV lv;
+    int tp = type[what];
 
     if (sp < 0) {
 	zerr("bad math expression: stack empty", NULL, 0);
 	return;
     }
+
+    if (tp & (OP_A2|OP_A2IR|OP_A2IO|OP_E2|OP_E2IO)) {
+	if (sp < 1) {
+ 	    zerr("bad math expression: unbalanced stack", NULL, 0); \
+	    return;
+	}
+	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;
+	    }
+	}
+	/*
+	 * 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,-1);
+	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 = -1;
 	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 = -1;
 	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 = -1;
 	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((zlong)(a < b));
-	break;
-    case LEQ:
-	pop2();
-	pushv((zlong)(a <= b));
-	break;
-    case GRE:
-	pop2();
-	pushv((zlong)(a > b));
-	break;
-    case GEQ:
-	pop2();
-	pushv((zlong)(a >= b));
-	break;
-    case DEQ:
-	pop2();
-	pushv((zlong)(a == b));
-	break;
-    case NEQ:
-	pop2();
-	pushv((zlong)(a != b));
-	break;
-    case DAND:
-	pop2();
-	pushv((zlong)(a && b));
-	break;
-    case DOR:
-	pop2();
-	pushv((zlong)(a || b));
-	break;
-    case DXOR:
-	pop2();
-	pushv((zlong)((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 = -1;
 	break;
     case QUEST:
-	pop3();
-	pushv((a) ? b : c);
+	if (sp < 2) {
+ 	    zerr("bad math expression: unbalanced stack", NULL, 0);
+	    return;
+	}
+	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, -1);
 	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((zlong)(a && b));
-	break;
-    case DOREQ:
-	pop2lv();
-	set((zlong)(a || b));
-	break;
-    case DXOREQ:
-	pop2lv();
-	set((zlong)((a && !b) || (!a && b)));
-	break;
-    case COMMA:
-	pop2();
-	pushv(b);
-	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);
@@ -711,15 +777,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;
     };
@@ -727,21 +796,19 @@ bop(int tk)
 
 
 /**/
-static zlong
+static mnumber
 mathevall(char *s, int prek, char **ep)
 {
     int t0;
     int xlastbase, xnoeval, xunary, xlvc;
     char *xptr;
-    zlong xyyval;
+    mnumber xyyval;
     LV xyylval;
     char **xlvals = 0, *nlvals[LVCOUNT];
     int xsp;
     struct mathvalue *xstack = 0, nstack[STACKSZ];
-    zlong ret;
+    mnumber ret;
 
-    xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
-    xptr = NULL;
     if (mlevel++) {
 	xlastbase = lastbase;
 	xnoeval = noeval;
@@ -754,6 +821,11 @@ mathevall(char *s, int prek, char **ep)
 
 	xsp = sp;
 	xstack = stack;
+    } else {
+	xlastbase = xnoeval = xunary = xlvc = xyylval = xsp = 0;
+	xyyval.type = MN_INTEGER;
+	xyyval.u.l = 0;
+	xptr = NULL;
     }
     stack = nstack;
     lastbase = -1;
@@ -790,15 +862,18 @@ mathevall(char *s, int prek, char **ep)
 
 
 /**/
-zlong
+mnumber
 matheval(char *s)
 {
     char *junk;
-    zlong 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)
@@ -806,19 +881,27 @@ matheval(char *s)
     return x;
 }
 
+/**/
+zlong
+mathevali(char *s)
+{
+    mnumber x = matheval(s);
+    return (x.type & MN_FLOAT) ? (zlong)x.u.d : x.u.l;
+}
+
 
 /**/
 zlong
 mathevalarg(char *s, char **ss)
 {
-    zlong 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;
 }
 
 
@@ -842,7 +925,7 @@ mathparse(int pc)
 	    push(yyval, -1);
 	    break;
 	case ID:
-	    push(getiparam(lvals[yylval]), yylval);
+	    push(getnparam(lvals[yylval]), yylval);
 	    break;
 	case CID:
 	    push(getcvar(yylval), yylval);
@@ -856,7 +939,8 @@ 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++;
@@ -873,9 +957,9 @@ 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;