mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-20 05:53:52 +01:00
884 lines
14 KiB
C
884 lines
14 KiB
C
/*
|
|
* math.c - mathematical expression evaluation
|
|
*
|
|
* This file is part of zsh, the Z shell.
|
|
*
|
|
* Copyright (c) 1992-1997 Paul Falstad
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and to distribute modified versions of this software for any
|
|
* purpose, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* In no event shall Paul Falstad or the Zsh Development Group be liable
|
|
* to any party for direct, indirect, special, incidental, or consequential
|
|
* damages arising out of the use of this software and its documentation,
|
|
* even if Paul Falstad and the Zsh Development Group have been advised of
|
|
* the possibility of such damage.
|
|
*
|
|
* Paul Falstad and the Zsh Development Group specifically disclaim any
|
|
* warranties, including, but not limited to, the implied warranties of
|
|
* merchantability and fitness for a particular purpose. The software
|
|
* provided hereunder is on an "as is" basis, and Paul Falstad and the
|
|
* Zsh Development Group have no obligation to provide maintenance,
|
|
* support, updates, enhancements, or modifications.
|
|
*
|
|
*/
|
|
|
|
#include "zsh.mdh"
|
|
#include "math.pro"
|
|
|
|
/* nonzero means we are not evaluating, just parsing */
|
|
|
|
/**/
|
|
int noeval;
|
|
|
|
/* last input base we used */
|
|
|
|
/**/
|
|
int lastbase;
|
|
|
|
static char *ptr;
|
|
|
|
static long yyval;
|
|
static LV yylval;
|
|
|
|
static int mlevel = 0;
|
|
|
|
/* != 0 means recognize unary plus, minus, etc. */
|
|
|
|
static int unary = 1;
|
|
|
|
/* LR = left-to-right associativity *
|
|
* RL = right-to-left associativity *
|
|
* BOO = short-circuiting boolean */
|
|
|
|
#define LR 0
|
|
#define RL 1
|
|
#define BOOL 2
|
|
|
|
#define M_INPAR 0
|
|
#define M_OUTPAR 1
|
|
#define NOT 2
|
|
#define COMP 3
|
|
#define POSTPLUS 4
|
|
#define POSTMINUS 5
|
|
#define UPLUS 6
|
|
#define UMINUS 7
|
|
#define AND 8
|
|
#define XOR 9
|
|
#define OR 10
|
|
#define MUL 11
|
|
#define DIV 12
|
|
#define MOD 13
|
|
#define PLUS 14
|
|
#define MINUS 15
|
|
#define SHLEFT 16
|
|
#define SHRIGHT 17
|
|
#define LES 18
|
|
#define LEQ 19
|
|
#define GRE 20
|
|
#define GEQ 21
|
|
#define DEQ 22
|
|
#define NEQ 23
|
|
#define DAND 24
|
|
#define DOR 25
|
|
#define DXOR 26
|
|
#define QUEST 27
|
|
#define COLON 28
|
|
#define EQ 29
|
|
#define PLUSEQ 30
|
|
#define MINUSEQ 31
|
|
#define MULEQ 32
|
|
#define DIVEQ 33
|
|
#define MODEQ 34
|
|
#define ANDEQ 35
|
|
#define XOREQ 36
|
|
#define OREQ 37
|
|
#define SHLEFTEQ 38
|
|
#define SHRIGHTEQ 39
|
|
#define DANDEQ 40
|
|
#define DOREQ 41
|
|
#define DXOREQ 42
|
|
#define COMMA 43
|
|
#define EOI 44
|
|
#define PREPLUS 45
|
|
#define PREMINUS 46
|
|
#define NUM 47
|
|
#define ID 48
|
|
#define POWER 49
|
|
#define CID 50
|
|
#define POWEREQ 51
|
|
#define TOKCOUNT 52
|
|
|
|
/* precedences */
|
|
|
|
static int prec[TOKCOUNT] =
|
|
{
|
|
1, 137, 2, 2, 2,
|
|
2, 2, 2, 4, 5,
|
|
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,
|
|
2, 2, 0, 0, 7,
|
|
0, 15
|
|
};
|
|
|
|
#define TOPPREC 16
|
|
#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
|
|
};
|
|
|
|
#define LVCOUNT 32
|
|
|
|
/* list of lvalues (variables) */
|
|
|
|
static int lvc;
|
|
static char **lvals;
|
|
|
|
|
|
/**/
|
|
static int
|
|
zzlex(void)
|
|
{
|
|
int cct = 0;
|
|
|
|
for (;; cct = 0)
|
|
switch (*ptr++) {
|
|
case '+':
|
|
if (*ptr == '+' && (unary || !ialnum(*ptr))) {
|
|
ptr++;
|
|
return (unary) ? PREPLUS : POSTPLUS;
|
|
}
|
|
if (*ptr == '=') {
|
|
unary = 1;
|
|
ptr++;
|
|
return PLUSEQ;
|
|
}
|
|
return (unary) ? UPLUS : PLUS;
|
|
case '-':
|
|
if (*ptr == '-' && (unary || !ialnum(*ptr))) {
|
|
ptr++;
|
|
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;
|
|
}
|
|
return NOT;
|
|
case '~':
|
|
return COMP;
|
|
case '&':
|
|
unary = 1;
|
|
if (*ptr == '&') {
|
|
if (*++ptr == '=') {
|
|
ptr++;
|
|
return DANDEQ;
|
|
}
|
|
return DAND;
|
|
} else if (*ptr == '=') {
|
|
ptr++;
|
|
return ANDEQ;
|
|
}
|
|
return AND;
|
|
case '|':
|
|
unary = 1;
|
|
if (*ptr == '|') {
|
|
if (*++ptr == '=') {
|
|
ptr++;
|
|
return DOREQ;
|
|
}
|
|
return DOR;
|
|
} else if (*ptr == '=') {
|
|
ptr++;
|
|
return OREQ;
|
|
}
|
|
return OR;
|
|
case '^':
|
|
unary = 1;
|
|
if (*ptr == '^') {
|
|
if (*++ptr == '=') {
|
|
ptr++;
|
|
return DXOREQ;
|
|
}
|
|
return DXOR;
|
|
} else if (*ptr == '=') {
|
|
ptr++;
|
|
return XOREQ;
|
|
}
|
|
return XOR;
|
|
case '*':
|
|
unary = 1;
|
|
if (*ptr == '*') {
|
|
if (*++ptr == '=') {
|
|
ptr++;
|
|
return POWEREQ;
|
|
}
|
|
return POWER;
|
|
}
|
|
if (*ptr == '=') {
|
|
ptr++;
|
|
return MULEQ;
|
|
}
|
|
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++;
|
|
return SHLEFTEQ;
|
|
}
|
|
return SHLEFT;
|
|
} else if (*ptr == '=') {
|
|
ptr++;
|
|
return LEQ;
|
|
}
|
|
return LES;
|
|
case '>':
|
|
unary = 1;
|
|
if (*ptr == '>') {
|
|
if (*++ptr == '=') {
|
|
ptr++;
|
|
return SHRIGHTEQ;
|
|
}
|
|
return SHRIGHT;
|
|
} else if (*ptr == '=') {
|
|
ptr++;
|
|
return GEQ;
|
|
}
|
|
return GRE;
|
|
case '=':
|
|
unary = 1;
|
|
if (*ptr == '=') {
|
|
ptr++;
|
|
return DEQ;
|
|
}
|
|
return EQ;
|
|
case '$':
|
|
unary = 0;
|
|
yyval = mypid;
|
|
return NUM;
|
|
case '?':
|
|
if (unary) {
|
|
yyval = lastval;
|
|
unary = 0;
|
|
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);
|
|
return NUM;
|
|
}
|
|
case ' ':
|
|
case '\t':
|
|
case '\n':
|
|
break;
|
|
case '0':
|
|
if (*ptr == 'x' || *ptr == 'X') {
|
|
unary = 0;
|
|
/* Should we set lastbase here? */
|
|
yyval = zstrtol(++ptr, &ptr, lastbase = 16);
|
|
return NUM;
|
|
}
|
|
/* Fall through! */
|
|
default:
|
|
if (idigit(*--ptr)) {
|
|
unary = 0;
|
|
yyval = zstrtol(ptr, &ptr, 10);
|
|
|
|
if (*ptr == '#') {
|
|
ptr++;
|
|
yyval = zstrtol(ptr, &ptr, lastbase = yyval);
|
|
}
|
|
return NUM;
|
|
}
|
|
if (*ptr == '#') {
|
|
if (*++ptr == '\\') {
|
|
ptr++;
|
|
yyval = *ptr == Meta ? *++ptr ^ 32 : *ptr;
|
|
ptr++;
|
|
unary = 0;
|
|
return NUM;
|
|
}
|
|
cct = 1;
|
|
}
|
|
if (iident(*ptr)) {
|
|
char *p, q;
|
|
|
|
p = ptr;
|
|
if (lvc == LVCOUNT) {
|
|
zerr("too many identifiers (complain to author)", NULL, 0);
|
|
return EOI;
|
|
}
|
|
unary = 0;
|
|
while (iident(*++ptr));
|
|
if (*ptr == '[') {
|
|
int l;
|
|
for (ptr++, l = 1; *ptr && l; ptr++) {
|
|
if (*ptr == '[')
|
|
l++;
|
|
if (*ptr == ']')
|
|
l--;
|
|
if (*ptr == '\\' && ptr[1])
|
|
ptr++;
|
|
}
|
|
}
|
|
q = *ptr;
|
|
*ptr = '\0';
|
|
lvals[yylval = lvc++] = ztrdup(p);
|
|
*ptr = q;
|
|
return cct ? CID : ID;
|
|
}
|
|
else if (cct) {
|
|
yyval = poundgetfn(NULL);
|
|
unary = 0;
|
|
return NUM;
|
|
}
|
|
return EOI;
|
|
}
|
|
}
|
|
|
|
/* the value stack */
|
|
|
|
#define STACKSZ 100
|
|
static int mtok; /* last token */
|
|
static int sp = -1; /* stack pointer */
|
|
|
|
struct mathvalue {
|
|
LV lval;
|
|
long val;
|
|
};
|
|
|
|
static struct mathvalue *stack;
|
|
|
|
/**/
|
|
static void
|
|
push(long val, LV lval)
|
|
{
|
|
if (sp == STACKSZ - 1)
|
|
zerr("stack overflow", NULL, 0);
|
|
else
|
|
sp++;
|
|
stack[sp].val = val;
|
|
stack[sp].lval = lval;
|
|
}
|
|
|
|
|
|
/**/
|
|
static long
|
|
getcvar(LV s)
|
|
{
|
|
char *t;
|
|
|
|
if (!(t = getsparam(lvals[s])))
|
|
return 0;
|
|
return STOUC(*t == Meta ? t[1] ^ 32 : *t);
|
|
}
|
|
|
|
|
|
/**/
|
|
static long
|
|
setvar(LV s, long v)
|
|
{
|
|
if (s == -1 || s >= lvc) {
|
|
zerr("lvalue required", NULL, 0);
|
|
return 0;
|
|
}
|
|
if (noeval)
|
|
return v;
|
|
setiparam(lvals[s], v);
|
|
return v;
|
|
}
|
|
|
|
|
|
/**/
|
|
static int
|
|
notzero(long a)
|
|
{
|
|
if (a == 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;
|
|
|
|
if (sp < 0) {
|
|
zerr("bad math expression: stack empty", NULL, 0);
|
|
return;
|
|
}
|
|
switch (what) {
|
|
case NOT:
|
|
stack[sp].val = !stack[sp].val;
|
|
nolval();
|
|
break;
|
|
case COMP:
|
|
stack[sp].val = ~stack[sp].val;
|
|
nolval();
|
|
break;
|
|
case POSTPLUS:
|
|
(void)setvar(stack[sp].lval, stack[sp].val + 1);
|
|
break;
|
|
case POSTMINUS:
|
|
(void)setvar(stack[sp].lval, stack[sp].val - 1);
|
|
break;
|
|
case UPLUS:
|
|
nolval();
|
|
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)));
|
|
break;
|
|
case QUEST:
|
|
pop3();
|
|
pushv((a) ? b : c);
|
|
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);
|
|
break;
|
|
case PREPLUS:
|
|
stack[sp].val = setvar(stack[sp].lval,
|
|
stack[sp].val + 1);
|
|
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);
|
|
break;
|
|
default:
|
|
zerr("out of integers", NULL, 0);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
/**/
|
|
static void
|
|
bop(int tk)
|
|
{
|
|
switch (tk) {
|
|
case DAND:
|
|
case DANDEQ:
|
|
if (!stack[sp].val)
|
|
noeval++;
|
|
break;
|
|
case DOR:
|
|
case DOREQ:
|
|
if (stack[sp].val)
|
|
noeval++;
|
|
break;
|
|
};
|
|
}
|
|
|
|
|
|
/**/
|
|
static long
|
|
mathevall(char *s, int prek, char **ep)
|
|
{
|
|
int t0;
|
|
int xlastbase, xnoeval, xunary, xlvc;
|
|
char *xptr;
|
|
long xyyval;
|
|
LV xyylval;
|
|
char **xlvals = 0;
|
|
int xsp;
|
|
struct mathvalue *xstack = 0;
|
|
long ret;
|
|
|
|
xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
|
|
xptr = NULL;
|
|
if (mlevel++) {
|
|
xlastbase = lastbase;
|
|
xnoeval = noeval;
|
|
xunary = unary;
|
|
xlvc = lvc;
|
|
xptr = ptr;
|
|
xyyval = yyval;
|
|
xyylval = yylval;
|
|
xlvals = lvals;
|
|
|
|
xsp = sp;
|
|
xstack = stack;
|
|
}
|
|
stack = (struct mathvalue *)zalloc(STACKSZ*sizeof(struct mathvalue));
|
|
lastbase = -1;
|
|
lvals = (char **)zcalloc(LVCOUNT*sizeof(char *));
|
|
lvc = 0;
|
|
ptr = s;
|
|
sp = -1;
|
|
unary = 1;
|
|
mathparse(prek);
|
|
*ep = ptr;
|
|
if (sp)
|
|
zerr("bad math expression: unbalanced stack", NULL, 0);
|
|
for (t0 = 0; t0 != lvc; t0++)
|
|
zsfree(lvals[t0]);
|
|
|
|
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;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**/
|
|
long
|
|
matheval(char *s)
|
|
{
|
|
char *junk;
|
|
long x;
|
|
int xmtok = mtok;
|
|
|
|
if (!*s)
|
|
return 0;
|
|
x = mathevall(s, TOPPREC, &junk);
|
|
mtok = xmtok;
|
|
if (*junk)
|
|
zerr("bad math expression: illegal character: %c", NULL, *junk);
|
|
return x;
|
|
}
|
|
|
|
|
|
/**/
|
|
long
|
|
mathevalarg(char *s, char **ss)
|
|
{
|
|
long x;
|
|
int xmtok = mtok;
|
|
|
|
x = mathevall(s, ARGPREC, ss);
|
|
if (mtok == COMMA)
|
|
(*ss)--;
|
|
mtok = xmtok;
|
|
return x;
|
|
}
|
|
|
|
|
|
/* operator-precedence parse the string and execute */
|
|
|
|
/**/
|
|
static void
|
|
mathparse(int pc)
|
|
{
|
|
int q, otok, onoeval;
|
|
|
|
if (errflag)
|
|
return;
|
|
mtok = zzlex();
|
|
while (prec[mtok] <= pc) {
|
|
if (errflag)
|
|
return;
|
|
switch (mtok) {
|
|
case NUM:
|
|
push(yyval, -1);
|
|
break;
|
|
case ID:
|
|
push(getiparam(lvals[yylval]), yylval);
|
|
break;
|
|
case CID:
|
|
push(getcvar(yylval), yylval);
|
|
break;
|
|
case M_INPAR:
|
|
mathparse(TOPPREC);
|
|
if (mtok != M_OUTPAR) {
|
|
if (!errflag)
|
|
zerr("')' expected", NULL, 0);
|
|
return;
|
|
}
|
|
break;
|
|
case QUEST:
|
|
q = stack[sp].val;
|
|
|
|
if (!q)
|
|
noeval++;
|
|
mathparse(prec[QUEST] - 1);
|
|
if (!q)
|
|
noeval--;
|
|
else
|
|
noeval++;
|
|
mathparse(prec[QUEST]);
|
|
if (q)
|
|
noeval--;
|
|
op(QUEST);
|
|
continue;
|
|
default:
|
|
otok = mtok;
|
|
onoeval = noeval;
|
|
if (type[otok] == BOOL)
|
|
bop(otok);
|
|
mathparse(prec[otok] - (type[otok] != RL));
|
|
noeval = onoeval;
|
|
op(otok);
|
|
continue;
|
|
}
|
|
mtok = zzlex();
|
|
}
|
|
}
|