streval.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* D. G. Korn
* AT&T Labs
*
* arithmetic expression evaluator
*
* this version compiles the expression onto a stack
* and has a separate executor
*/
#include "streval.h"
#include <ctype.h>
#include <error.h>
#include <stak.h>
#include "defs.h" /* for sh.decomma */
#ifndef ERROR_dictionary
# define ERROR_dictionary(s) (s)
#endif
#ifndef SH_DICT
# define SH_DICT "libshell"
#endif
#define MAXLEVEL 9
#define SMALL_STACK 12
/*
* The following are used with tokenbits() macro
*/
#define roundptr(ep,cp,type) (((unsigned char*)(ep))+round(cp-((unsigned char*)(ep)),pow2size(sizeof(type))))
static int level;
struct vars /* vars stacked per invocation */
{
const char *expr; /* current expression */
const char *nextchr; /* next char in current expression */
const char *errchr; /* next char after error */
const char *errstr; /* error string */
int offset; /* offset for pushchr macro */
int staksize; /* current stack size needed */
int stakmaxsize; /* maximum stack size needed */
unsigned char paren; /* parenthesis level */
char infun; /* incremented by comma inside function */
int emode;
};
typedef int (*Math_1i_f)(Sfdouble_t);
#if ('a'==97) /* ASCII encodings */
# define getop(c) (((c) >= sizeof(strval_states))? \
strval_states[(c)])
#else
(c=='\''?A_LIT: \
#endif
/*
* set error message string and return(0)
*/
{
level = 0;
return(0);
}
{
level = 0;
}
#if _ast_no_um2fm
{
Sflong_t s = u;
Sfdouble_t f;
if (s >= 0)
return s;
s = u / 2;
f = s;
f *= 2;
if (u & 1)
f++;
return f;
}
#else
#define U2F(x) x
#endif
{
register int c,type=0;
register char *tp;
const char *ptr = "";
char *lastval=0;
int lastsub;
{
return(0);
}
sp = small_stack;
else
while(c = *cp++)
{
if(c&T_NOFLOAT)
{
}
switch(c&T_OP)
{
c &= T_OP;
cp += sizeof(short);
else
continue;
case A_NOTNOT:
type=0;
break;
case A_PLUSPLUS:
break;
case A_MINUSMINUS:
break;
case A_INCR:
break;
case A_DECR:
break;
case A_SWAP:
break;
case A_POP:
sp--;
continue;
case A_ASSIGNOP1:
case A_PUSHV:
cp += sizeof(Sfdouble_t*);
c = *(short*)cp;
cp += sizeof(short);
lastval = 0;
{
}
type = 1;
else
{
Sfdouble_t d=num;
{
type = 2;
d -= LDBL_LLONG_MAX;
}
if((Sflong_t)d!=d)
type = 1;
}
c = 0;
break;
case A_ENUM:
continue;
case A_ASSIGNOP:
case A_STORE:
cp += sizeof(Sfdouble_t*);
c = *(short*)cp;
if(c<0)
c = 0;
cp += sizeof(short);
if(lastval)
{
Sfdouble_t r;
if(r!=num)
{
}
}
lastval = 0;
c=0;
break;
case A_PUSHF:
continue;
case A_PUSHN:
cp += sizeof(Sfdouble_t);
break;
case A_NOT:
type=0;
break;
case A_UMINUS:
break;
case A_TILDE:
break;
case A_PLUS:
break;
case A_MINUS:
break;
case A_TIMES:
break;
case A_POW:
break;
case A_MOD:
else
break;
case A_DIV:
{
type = 1;
}
else
break;
case A_LSHIFT:
else
break;
case A_RSHIFT:
else
break;
case A_XOR:
else
break;
case A_OR:
else
break;
case A_AND:
else
break;
case A_EQ:
type=0;
break;
case A_NEQ:
type=0;
break;
case A_LE:
type=0;
break;
case A_GE:
type=0;
break;
case A_GT:
type=0;
break;
case A_LT:
type=0;
break;
case A_CALL1F:
if(c&T_BINARY)
{
c &= ~T_BINARY;
arg[1] = 0;
break;
}
break;
case A_CALL1I:
break;
case A_CALL2F:
if(c&T_BINARY)
{
c &= ~T_BINARY;
arg[2] = 0;
break;
}
if(c&T_NOFLOAT)
else
break;
case A_CALL2I:
break;
case A_CALL3F:
if(c&T_BINARY)
{
c &= ~T_BINARY;
arg[3] = 0;
break;
}
break;
}
if(c)
lastval = 0;
if(c&T_BINARY)
{
}
}
if(level>0)
level--;
num = 0;
return(num);
}
/*
* This returns operator tokens or A_REG or A_NUM
*/
{
register int c,op;
while(1)
{
{
case 0:
continue;
case A_EOF:
break;
case A_COMMA:
{
goto keep;
}
break;
case A_DOT:
else
/*FALL THRU*/
keep:
break;
case A_QUEST:
{
}
break;
{
op -= 2;
break;
}
/* FALL THRU */
c = '=';
/* FALL THRU */
case A_ASSIGN:
case A_TIMES:
{
op--;
}
}
return(op);
}
}
/*
* evaluate a subexpression with precedence
*/
{
register int c, op;
const char *pos;
Sfdouble_t d;
switch(op)
{
case A_PLUS:
goto again;
case A_EOF:
if(precedence>2)
return(1);
case A_MINUS:
goto common;
case A_NOT:
goto common;
case A_MINUSMINUS:
c = A_LVALUE;
goto common;
case A_PLUSPLUS:
c = A_LVALUE;
/* FALL THRU */
case A_TILDE:
return(0);
break;
default:
wasop = 1;
}
while(1)
{
{
if(!wasop)
goto number;
}
/* check for assignment operation */
{
if(precedence==3)
precedence = 2;
c = 3;
}
else
{
c++;
c *= 2;
}
/* from here on c is the new precedence level */
{
invalid = 0;
}
else if(precedence==A_LVALUE)
if(precedence >= c)
goto done;
c--;
{
wasop = 0;
return(0);
}
switch(op)
{
case A_RPAR:
if(invalid)
goto done;
case A_COMMA:
wasop = 0;
else
{
}
{
return(0);
}
break;
case A_LPAR:
{
int userfun=0;
if(nargs<0)
if(fun)
{
stakputc(1);
}
else
if(!invalid)
return(0);
if(fun)
{
nargs &= 7;
}
wasop = 0;
break;
}
case A_PLUSPLUS:
case A_MINUSMINUS:
wasop=0;
case A_ASSIGN:
{
}
else
break;
case A_QUEST:
{
return(0);
return(0);
wasop = 0;
break;
}
case A_COLON:
break;
case A_QCOLON:
case A_ANDAND:
case A_OROR:
{
int offset;
else
return(0);
wasop=0;
break;
}
/* FALL THRU */
break;
default:
wasop = 0;
{
}
{
/* character constants */
{
d = '\\';
}
else
/* posix allows the trailing ' to be optional */
}
else
{
}
{
}
/* check for function call */
continue;
break;
}
invalid = 0;
{
}
}
done:
return(1);
}
Arith_t *arith_compile(Shell_t *shp,const char *string,char **last,Sfdouble_t(*fun)(const char**,struct lval*,int,Sfdouble_t),int emode)
{
int offset;
{
{
stakseek(0);
return(0);
}
}
stakputc(0);
if(last)
return(ep);
}
/*
* evaluate an integer arithmetic expression in s
*
* (Sfdouble_t)(*convert)(char** end, struct lval* string, int type, Sfdouble_t value)
* is a user supplied conversion routine that is called when unknown
* chars are encountered.
* *end points to the part to be converted and must be adjusted by convert to
* point to the next non-converted character; if typ is MESSAGE then string
* points to an error message string
*
* NOTE: (*convert)() may call strval()
*/
Sfdouble_t strval(Shell_t *shp,const char *s,char **end,Sfdouble_t(*conv)(const char**,struct lval*,int,Sfdouble_t),int emode)
{
Sfdouble_t d;
char *sp=0;
int offset;
d = arith_exec(ep);
return(d);
}
#define _mem_name_exception 1
#define exception _exception
#endif
#if _BLD_shell && defined(__EXPORT__)
#define extern __EXPORT__
#endif
#ifndef DOMAIN
#endif
#ifndef OVERFLOW
#endif
#ifndef SING
#endif
{
const char *message;
{
#ifdef DOMAIN
case DOMAIN:
break;
#endif
#ifdef OVERFLOW
case OVERFLOW:
break;
#endif
#ifdef SING
case SING:
break;
#endif
default:
return(1);
}
level=0;
return(0);
}
#undef extern
#endif /* _mem_name_exception */