* math.c - mathematical expression evaluation
* This file is part of zsh, the Z shell.
* This software is Copyright 1992 by Paul Falstad
* Permission is hereby granted to copy, reproduce, redistribute or otherwise
* use this software as long as: there is no monetary profit gained
* specifically from the use or reproduction of this software, it is not
* sold, rented, traded or otherwise marketed, and this copyright notice is
* included prominently in any copy made.
* The author make no claims as to the fitness or correctness of this software
* for any use whatsoever, and it is provided as is. Any use of this software
* is at the user's own risk.
/* nonzero means we are not evaluating, just parsing */
/* != 0 means recognize unary plus, minus, etc. */
void mathparse
DCLPROTO((int));
/* LR = left-to-right associativity
RL = right-to-left associativity
BOO = short-circuiting boolean */
static int prec
[TOKCOUNT
] = {
static int type
[TOKCOUNT
] = {
/* list of lvalues (variables) */
static char *lvals
[LVCOUNT
];
if (*ptr
== '+' && (unary
|| !ialnum(*ptr
)))
return (unary
) ? PREPLUS
: POSTPLUS
;
if (*ptr
== '=') { unary
= 1; ptr
++; return PLUSEQ
; }
return (unary
) ? UPLUS
: PLUS
;
if (*ptr
== '-' && (unary
|| !ialnum(*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
; }
if (*ptr
== '&') { if (*++ptr
== '=')
{ ptr
++; return DANDEQ
; } return DAND
; }
else if (*ptr
== '=') { ptr
++; return ANDEQ
; } return AND
;
if (*ptr
== '|') { if (*++ptr
== '=')
{ ptr
++; return DOREQ
; } return DOR
; }
else if (*ptr
== '=') { ptr
++; return OREQ
; } return OR
;
if (*ptr
== '^') { if (*++ptr
== '=')
{ ptr
++; return DXOREQ
; } return DXOR
; }
else if (*ptr
== '=') { ptr
++; return XOREQ
; } return XOR
;
if (*ptr
== '=') { ptr
++; return MULEQ
; } return MUL
;
if (*ptr
== '=') { ptr
++; return DIVEQ
; } return DIV
;
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
; }
case '?': unary
= 1; return QUEST
;
case ':': unary
= 1; return COLON
;
case ',': unary
= 1; return COMMA
;
case '\0': unary
= 1; ptr
--; return EOI
;
{ int base
= zstrtol(ptr
,&ptr
,10);
yyval
= zstrtol(ptr
,&ptr
,lastbase
= base
);
{ unary
= 0; yyval
= zstrtol(ptr
,&ptr
,10); return NUM
; }
if (iident(*ptr
) || *ptr
== '$')
zerr("too many identifiers (complain to author)",NULL
,0);
lvals
[yylval
= lvc
++] = ztrdup(p
);
int mtok
; /* last token */
int sp
= -1; /* stack pointer */
zerr("stack overflow",NULL
,0);
if (!(t
= getiparam(lvals
[s
])))
zerr("lvalue required",NULL
,0);
zerr("division by zero",NULL
,0);
#define pop2() { b = stack[sp--].val; a = stack[sp--].val; }
#define pop3() {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); }
zerr("bad math expression: stack empty",NULL
,0);
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(a
<b
); break;
case LEQ
: pop2(); pushv(a
<=b
); break;
case GRE
: pop2(); pushv(a
>b
); break;
case GEQ
: pop2(); pushv(a
>=b
); break;
case DEQ
: pop2(); pushv(a
==b
); break;
case NEQ
: pop2(); pushv(a
!=b
); break;
case DAND
: pop2(); pushv(a
&&b
); break;
case DOR
: pop2(); pushv(a
||b
); break;
case DXOR
: pop2(); pushv(a
&&!b
||!a
&&b
); break;
case QUEST
: pop3(); pushv((a
)?b
:c
); break;
case EQ
: pop2lv(); 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(a
&&b
); break;
case DOREQ
: pop2lv(); set(a
||b
); break;
case DXOREQ
: pop2lv(); set(a
&&!b
||!a
&&b
); break;
case COMMA
: pop2(); pushv(b
); break;
case PREPLUS
: stack
[sp
].val
= setvar(stack
[sp
].lval
,
case PREMINUS
: stack
[sp
].val
= setvar(stack
[sp
].lval
,
default: zerr("out of integers",NULL
,0); exit(1);
case DAND
: case DANDEQ
: if (!stack
[sp
].val
) noeval
++; break;
case DOR
: case DOREQ
: if (stack
[sp
].val
) noeval
++; break;
long mathevall(s
,prek
,ep
) /**/
char *s
;int prek
;char **ep
;
for (t0
= 0; t0
!= LVCOUNT
; t0
++)
zerr("bad math expression: unbalanced stack",NULL
,0);
for (t0
= 0; t0
!= lvc
; t0
++)
x
= mathevall(s
,TOPPREC
,&junk
);
zerr("bad math expression: illegal character: %c",NULL
,*junk
);
long mathevalarg(s
,ss
) /**/
x
= mathevall(s
,ARGPREC
,ss
);
/* operator-precedence parse the string and execute */
push(getvar(yylval
),yylval
);
else if (mtok
== M_INPAR
)
mathparse(prec
[QUEST
]-1);
if (!q
) noeval
--; else noeval
++;
int otok
= mtok
,onoeval
= noeval
;
mathparse(prec
[otok
]-(type
[otok
] != RL
));