#include "irc.h"
#include <math.h>
#include "debug.h"
#if 0
static char *alias_special_char(char **, char *, const char *, char *, int *);
#endif
#define STACKSZ 100
#define TOKENCOUNT 256
#define MAGIC_TOKEN -14
typedef int TOKEN;
#ifdef FLOATING_POINT_MATH
typedef double NUMBER;
typedef long BooL;
# define STON atof
# define NTOS ftoa
#else
typedef unsigned long NUMBER;
typedef long BooL;
# define STON atol
# define NTOS ltoa
#endif
typedef struct
{
char *ptr;
int noeval;
int operand;
TOKEN token;
char * tokens[TOKENCOUNT + 1];
TOKEN stack[STACKSZ + 1];
int sp;
TOKEN mtok;
int errflag;
TOKEN last_token;
const char *args;
int *args_flag;
} expr_info;
__inline static TOKEN tokenize (expr_info *c, const char *t);
static char * after_expando_special (expr_info *c);
void setup_expr_info (expr_info *c)
{
int i;
c->ptr = NULL;
c->noeval = 0;
c->operand = 1;
c->token = 0;
for (i = 0; i <= TOKENCOUNT; i++)
c->tokens[i] = NULL;
for (i = 0; i <= STACKSZ; i++)
c->stack[i] = 0;
c->sp = -1;
c->mtok = 0;
c->errflag = 0;
c->last_token = 0;
tokenize(c, empty_string);
}
void destroy_expr_info (expr_info *c)
{
int i;
c->ptr = NULL;
c->noeval = -1;
c->operand = -1;
for (i = 0; i < c->token; i++)
new_free(&c->tokens[i]);
c->token = -1;
for (i = 0; i <= STACKSZ; i++)
c->stack[i] = -1;
c->sp = -1;
c->mtok = -1;
c->errflag = -1;
c->last_token = -1;
}
#define LR 0
#define RL 1
#define BOOL 2
enum LEX {
M_INPAR,
NOT, COMP, PREMINUS, PREPLUS,
UPLUS, UMINUS, STRLEN,
WORDC, DEREF,
POWER,
MUL, DIV, MOD,
PLUS, MINUS, STRCAT,
SHLEFT, SHRIGHT,
LES, LEQ, GRE, GEQ,
MATCH, NOMATCH,
DEQ, NEQ,
AND,
XOR,
OR,
DAND,
DXOR,
DOR,
QUEST, COLON,
EQ, PLUSEQ, MINUSEQ, MULEQ, DIVEQ,
MODEQ, ANDEQ, XOREQ, OREQ,
SHLEFTEQ, SHRIGHTEQ, DANDEQ, DOREQ,
DXOREQ, POWEREQ, STRCATEQ, STRPREEQ,
SWAP,
COMMA,
POSTMINUS, POSTPLUS,
ID,
M_OUTPAR,
EERROR,
EOI,
TOKCOUNT
};
static int prec[TOKCOUNT] =
{
1,
2, 2, 2, 2,
2, 2, 2,
2, 2,
3,
4, 4, 4,
5, 5, 5,
6, 6,
7, 7, 7, 7,
8, 8,
9, 9,
10,
11,
12,
13,
14,
15,
16, 16,
17, 17, 17, 17, 17,
17, 17, 17, 17,
17, 17, 17, 17,
17, 17, 17, 17,
17,
18,
2, 2,
0,
137,
156,
200
};
#define TOPPREC 21
static int assoc[TOKCOUNT] =
{
LR,
RL, RL, RL, RL,
RL, RL, RL,
RL, RL,
RL,
LR, LR, LR,
LR, LR, LR,
LR, LR,
LR, LR, LR, LR,
LR, LR,
LR, LR,
LR,
LR,
LR,
BOOL,
BOOL,
BOOL,
RL, RL,
RL, RL, RL, RL, RL,
RL, RL, RL, RL,
RL, RL, RL, RL,
RL, RL, RL, RL,
RL,
LR,
RL, RL,
LR,
LR,
LR,
LR
};
__inline static TOKEN tokenize (expr_info *c, const char *t)
{
if (c->token >= TOKENCOUNT)
{
error("Too many tokens for this expression");
return -1;
}
c->tokens[c->token] = m_strdup(t);
return c->token++;
}
__inline static const char * get_token (expr_info *c, TOKEN v)
{
if (v == MAGIC_TOKEN)
return c->args;
if (v < 0 || v >= c->token)
{
error("Token index [%d] is out of range", v);
return get_token(c, 0);
}
return c->tokens[v];
}
static char * getsval2 (expr_info *c, TOKEN s);
static char * getsval (expr_info *c, TOKEN s)
{
char * retval;
const char * t;
t = get_token(c, s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell(">>> Expanding token [%d]: [%s]", s, t);
retval = getsval2(c, s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("<<< Expanded token [%d]: [%s] to: [%s]", s, t, retval);
return retval;
}
static char * getsval2 (expr_info *c, TOKEN s)
{
const char *t;
if (c->noeval || s == 0)
return m_strdup(get_token(c, 0));
if (s == MAGIC_TOKEN)
{
*c->args_flag = 1;
return m_strdup(c->args);
}
t = get_token(c, s);
if (*t == '[')
{
t++;
if (*t == '$')
{
if (t[1] == '*' && !t[2])
return m_strdup(c->args);
else
{
char * end = NULL;
long j = strtol(t + 1, &end, 10);
if (end && !*end)
{
*c->args_flag = 1;
if (j < 0)
return extract2(c->args, SOS, -j);
else
return extract2(c->args, j, j);
}
else if (*end == '-' && !end[1])
{
*c->args_flag = 1;
return extract2(c->args, j, EOS);
}
else
return expand_alias(t, c->args,
c->args_flag, NULL);
}
}
else if (!strchr(t, '$') && !strchr(t, '\\'))
return m_strdup(t);
else
return expand_alias(t, c->args, c->args_flag, NULL);
}
else if (is_number(t))
return m_strdup(t);
else
{
char *after,
*ptr,
*w,
saver = 0;
int func = 0;
w = LOCAL_COPY(t);
after = after_expando(w, 0, &func);
if (after)
{
saver = *after;
*after = 0;
}
if (func)
ptr = call_function(w, c->args, c->args_flag);
else
ptr = get_variable_with_args(w, c->args, c->args_flag);
if (!ptr)
return m_strdup(empty_string);
if (after)
*after = saver;
return ptr;
}
return NULL ;
}
__inline static NUMBER getnval (expr_info *c, TOKEN s)
{
char *t;
NUMBER retval;
if (c->noeval)
return 0;
if (!(t = getsval(c, s)))
return 0;
retval = STON(t);
new_free(&t);
return retval;
}
#ifdef notused
__inline static BooL getbval (expr_info *c, TOKEN s)
{
char *t;
long retval;
if (c->noeval)
return 0;
if (!(t = getsval(c, s)))
return 0;
retval = check_val(t);
new_free(&t);
return retval;
}
#endif
__inline static TOKEN setvar (expr_info *c, TOKEN l, TOKEN r)
{
char *t = expand_alias(get_token(c, l), c->args, c->args_flag, NULL);
char *u = getsval(c, r);
char *s;
if (!c->noeval)
{
int old_window_display = window_display;
window_display = 0;
add_var_alias(t, u);
window_display = old_window_display;
}
s = alloca(strlen(u) + 3);
s[0] = '[';
strcpy(s+1, u);
new_free(&t);
new_free(&u);
return tokenize(c, s);
}
__inline static TOKEN setnvar (expr_info *c, TOKEN l, NUMBER v)
{
return setvar(c, l, tokenize(c, NTOS(v)));
}
__inline static TOKEN setsvar (expr_info *c, TOKEN l, char *v)
{
char *s;
s = alloca(strlen(v) + 3);
s[0] = '[';
strcpy(s+1, v);
return setvar(c, l, tokenize(c, s));
}
__inline static TOKEN pusht (expr_info *c, TOKEN t)
{
if (c->sp == STACKSZ - 1)
{
error("Expressions may not have more than 99 operands");
return -1;
}
else
c->sp++;
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Pushing token [%d] [%s]", t, get_token(c, t));
return ((c->stack[c->sp] = t));
}
__inline static TOKEN pushn (expr_info *c, NUMBER val)
{
return pusht(c, tokenize(c, NTOS(val)));
}
__inline static TOKEN pushs (expr_info *c, char *val)
{
char *blah;
blah = alloca(strlen(val) + 2);
sprintf(blah, "[%s", val);
return pusht(c, tokenize(c, blah));
}
__inline static TOKEN top (expr_info *c)
{
if (c->sp < 0)
{
error("No operands.");
return -1;
}
else
return c->stack[c->sp];
}
__inline static TOKEN pop (expr_info *c)
{
if (c->sp < 0)
{
error("Cannot pop operand: no more operands");
return 0;
}
else
return c->stack[c->sp--];
}
__inline static double popn (expr_info *c)
{
char * x = getsval(c, pop(c));
NUMBER i = atof(x);
new_free(&x);
return i;
}
__inline static char * pops (expr_info *c)
{
return getsval(c, pop(c));
}
__inline static BooL popb (expr_info *c)
{
char * x = getsval(c, pop(c));
BooL i = check_val(x);
new_free(&x);
return i;
}
__inline static void pop2 (expr_info *c, TOKEN *t1, TOKEN *t2)
{
*t2 = pop(c);
*t1 = pop(c);
}
__inline static void pop2n (expr_info *c, NUMBER *a, NUMBER *b)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*a = STON(x);
*b = STON(y);
new_free(&x);
new_free(&y);
}
__inline static void pop2s (expr_info *c, char **s, char **t)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*s = x;
*t = y;
}
__inline static void pop2b (expr_info *c, BooL *a, BooL *b)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*a = check_val(x);
*b = check_val(y);
new_free(&x);
new_free(&y);
}
__inline static void pop2n_a (expr_info *c, NUMBER *a, NUMBER *b, TOKEN *v)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*a = STON(x);
*b = STON(y);
*v = t1;
new_free(&x);
new_free(&y);
}
__inline static void pop2s_a (expr_info *c, char **s, char **t, TOKEN *v)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*s = x;
*t = y;
*v = t1;
}
#if notused
__inline static void pop2b_a (expr_info *c, BooL *a, BooL *b, TOKEN *v)
{
TOKEN t1, t2;
char *x, *y;
pop2(c, &t1, &t2);
x = getsval(c, t1);
y = getsval(c, t2);
*a = check_val(x);
*b = check_val(y);
*v = t1;
new_free(&x);
new_free(&y);
}
#endif
__inline static void pop3 (expr_info *c, NUMBER *a, TOKEN *v, TOKEN *w)
{
TOKEN t1, t2, t3;
char *x;
t3 = pop(c);
t2 = pop(c);
t1 = pop(c);
x = getsval(c, t1);
*a = STON(x);
*v = t2;
*w = t3;
new_free(&x);
}
void op (expr_info *cx, int what)
{
NUMBER a, b;
BooL c, d;
char *s, *t;
TOKEN v, w;
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Reducing last operation...");
if (cx->sp < 0) {
error("An operator is missing a required operand");
return;
}
if (cx->errflag)
return;
#define BINARY(x) \
{ \
pop2n(cx, &a, &b); \
pushn(cx, (x)); \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%ld %ld) -> %ld", #x, a, b, (long)x); \
break; \
}
#define BINARY_BOOLEAN(x) \
{ \
pop2b(cx, &c, &d); \
pushn(cx, (x)); \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%ld %ld) -> %ld", #x, c, d, (long)x); \
break; \
}
#define BINARY_NOZERO(x) \
{ \
pop2n(cx, &a, &b); \
if (b == 0) { \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%ld %ld) -> 0", #x, a, b); \
error("Division by zero"); \
pushn(cx, 0); \
} \
else \
{ \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%ld %ld) -> %ld", #x, a, b, (long)x); \
pushn(cx, (x)); \
} \
break; \
}
#define IMPLIED(x) \
{ \
pop2n_a(cx, &a, &b, &v); \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s = %s (%ld %ld) -> %ld", \
get_token(cx, v), #x, a, b, x); \
pushn(cx, setnvar(cx, v, (x))); \
break; \
}
#define IMPLIED_NOZERO(x) \
{ \
pop2n_a(cx, &a, &b, &v); \
if (b == 0) { \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s = %s (%ld %ld) -> 0", \
get_token(cx, v), #x, a, b); \
error("Division by zero"); \
pushn(cx, setnvar(cx, v, 0)); \
} \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s = %s (%ld %ld) -> %ld", \
get_token(cx, v), #x, a, b, x); \
pushn(cx, setnvar(cx, v, (x))); \
break; \
}
#define AUTO_UNARY(x, y) \
{ \
v = pop(cx); \
b = getnval(cx, v); \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%s %ld) -> %ld", \
#x, get_token(cx, v), b, (x)); \
setnvar(cx, v, (x)); \
pushn(cx, (y)); \
break; \
}
#define dpushn(x1,x2,y1) \
{ \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
{ \
debugyell("O: COMPARE"); \
debugyell("O: %s -> %d", #x2, (x2)); \
} \
pushn(x1,y1); \
}
#define COMPARE(x, y) \
{ \
pop2s(cx, &s, &t); \
if ((a = STON(s)) && (b = STON(t))) \
{ \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%ld %ld) -> %d", #x, a, b, (x)); \
if ((x)) dpushn(cx, x, 1) \
else dpushn(cx, x, 0) \
} \
else \
{ \
if (x_debug & DEBUG_NEW_MATH_DEBUG) \
debugyell("O: %s (%s %s) -> %d", #x, s, t, (y)); \
if ((y)) dpushn(cx, y, 1) \
else dpushn(cx, y, 0) \
} \
new_free(&s); \
new_free(&t); \
break; \
}
switch (what)
{
case NOT:
c = popb(cx);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: !%ld -> %d", c, !c);
pushn(cx, !c);
break;
case COMP:
a = popn(cx);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell(": ~%ld -> %ld", a, ~a);
pushn(cx, ~a);
break;
case UPLUS:
a = popn(cx);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: +%ld -> %ld", a, a);
pushn(cx, a);
break;
case UMINUS:
a = popn(cx);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: -%ld -> %ld", a, -a);
pushn(cx, -a);
break;
case STRLEN:
s = pops(cx);
a = strlen(s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: @(%s) -> %ld", s, a);
pushn(cx, a);
new_free(&s);
break;
case WORDC:
s = pops(cx);
a = word_count(s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: #(%s) -> %ld", s, a);
pushn(cx, a);
new_free(&s);
break;
case DEREF:
{
char *buffer = NULL,
*tmp;
if (top(cx) == MAGIC_TOKEN)
break;
s = pops(cx);
tmp = expand_alias(s, cx->args, cx->args_flag, NULL);
alias_special_char(&buffer, tmp, cx->args,
NULL, cx->args_flag);
if (buffer == NULL)
buffer = m_strdup(empty_string);
*cx->args_flag = 1;
pushs(cx, buffer);
new_free(&buffer);
new_free(&tmp);
break;
}
case PREPLUS: AUTO_UNARY(b + 1, b + 1)
case PREMINUS: AUTO_UNARY(b - 1, b - 1)
case POSTPLUS: AUTO_UNARY(b + 1, b)
case POSTMINUS: AUTO_UNARY(b - 1, b)
case AND: BINARY(a & b)
case XOR: BINARY(a ^ b)
case OR: BINARY(a | b)
case PLUS: BINARY(a + b)
case MINUS: BINARY(a - b)
case MUL: BINARY(a * b)
case POWER: BINARY(pow(a, b))
case SHLEFT: BINARY(a << b)
case SHRIGHT: BINARY(a >> b)
case DIV: BINARY_NOZERO(a / b)
case MOD: BINARY_NOZERO(a % b)
case DAND: BINARY_BOOLEAN((long)(c && d))
case DOR: BINARY_BOOLEAN((long)(c || d))
case DXOR: BINARY_BOOLEAN((long)((c && !d) || (!c && d)))
case STRCAT:
pop2s(cx, &s, &t);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: (%s) ## (%s) -> %s%s", s, t, s, t);
malloc_strcat(&s, t);
pushs(cx, s);
new_free(&s);
new_free(&t);
break;
case PLUSEQ: IMPLIED(a + b)
case MINUSEQ: IMPLIED(a - b)
case MULEQ: IMPLIED(a * b)
case POWEREQ: IMPLIED((long)pow(a, b))
case DIVEQ: IMPLIED_NOZERO(a / b)
case MODEQ: IMPLIED_NOZERO(a % b)
case ANDEQ: IMPLIED(a & b)
case XOREQ: IMPLIED(a ^ b)
case OREQ: IMPLIED(a | b)
case SHLEFTEQ: IMPLIED(a << b)
case SHRIGHTEQ: IMPLIED(a >> b)
case DANDEQ: IMPLIED((long)(c && d))
case DOREQ: IMPLIED((long)(c || d))
case DXOREQ: IMPLIED((long)((c && !d) || (!c && d)))
case STRCATEQ:
pop2s_a(cx, &s, &t, &v);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s = (%s ## %s) -> %s%s",
get_token(cx, v), s, t, s, t);
malloc_strcat(&s, t);
pusht(cx, setsvar(cx, v, s));
new_free(&s);
new_free(&t);
break;
case STRPREEQ:
pop2s_a(cx, &s, &t, &v);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s = (%s ## %s) -> %s%s",
get_token(cx, v), t, s, t, s);
malloc_strcat(&t, s);
pusht(cx, setsvar(cx, v, t));
new_free(&s);
new_free(&t);
break;
case EQ:
pop2(cx, &v, &w);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s = (%s)",
get_token(cx, v), get_token(cx, w));
pusht(cx, setvar(cx, v, w));
break;
case SWAP:
{
char *vval, *wval;
pop2(cx, &v, &w);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s <=> %s",
get_token(cx, v), get_token(cx, w));
vval = getsval(cx, v);
wval = getsval(cx, w);
setsvar(cx, w, vval);
pusht(cx, setsvar(cx, v, wval));
new_free(&vval);
new_free(&wval);
break;
}
case DEQ:
pop2s(cx, &s, &t);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s == %s -> %d", s, t,
!!my_stricmp(s, t));
if (my_stricmp(s, t) == 0) pushn(cx, 1);
else pushn(cx, 0);
new_free(&s);
new_free(&t);
break;
case NEQ:
pop2s(cx, &s, &t);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s != %s -> %d", s, t,
!my_stricmp(s, t));
if (my_stricmp(s, t) != 0) pushn(cx, 1);
else pushn(cx, 0);
new_free(&s);
new_free(&t);
break;
case MATCH:
pop2s(cx, &s, &t);
a = !!wild_match(t, s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s =~ %s -> %ld", s, t, a);
pushn(cx, a);
new_free(&s);
new_free(&t);
break;
case NOMATCH:
pop2s(cx, &s, &t);
a = !wild_match(t, s);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s !~ %s -> %ld", s, t, a);
pushn(cx, a);
new_free(&s);
new_free(&t);
break;
case LES: COMPARE(a < b, my_stricmp(s, t) < 0)
case LEQ: COMPARE(a <= b, my_stricmp(s, t) <= 0)
case GRE: COMPARE(a > b, my_stricmp(s, t) > 0)
case GEQ: COMPARE(a >= b, my_stricmp(s, t) >= 0)
case QUEST:
pop3(cx, &a, &v, &w);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %ld ? %s : %s -> %s", a,
get_token(cx, v), get_token(cx, w),
(a) ? get_token(cx, v) :
get_token(cx, w));
pusht(cx, (a) ? v : w);
break;
case COLON:
break;
case COMMA:
v = pop(cx);
w = pop(cx);
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("O: %s , %s -> %s",
get_token(cx, w),
get_token(cx, v),
get_token(cx, v));
pusht(cx, v);
break;
default:
error("Unknown operator or out of operators");
return;
}
}
static int dummy = 1;
int lexerr (expr_info *c, char *format, ...)
{
char buffer[BIG_BUFFER_SIZE + 1];
va_list a;
va_start(a, format);
vsnprintf(buffer, BIG_BUFFER_SIZE, format, a);
va_end(a);
error("%s", buffer);
c->errflag = 1;
return EOI;
}
__inline int check_implied_arg (expr_info *c)
{
if (c->operand == 2)
{
pusht(c, MAGIC_TOKEN);
c->operand = 0;
*c->args_flag = 1;
return 0;
}
return c->operand;
}
__inline TOKEN operator (expr_info *c, char *x, int y, TOKEN z)
{
check_implied_arg(c);
if (c->operand)
return lexerr(c, "A binary operator (%s) was found "
"where an operand was expected", x);
c->ptr += y;
c->operand = 1;
return z;
}
__inline TOKEN unary (expr_info *c, char *x, int y, TOKEN z)
{
if (!c->operand)
return lexerr(c, "An operator (%s) was found where "
"an operand was expected", x);
c->ptr += y;
c->operand = dummy;
return z;
}
static int zzlex (expr_info *c)
{
char *start = c->ptr;
#define OPERATOR(x, y, z) return operator(c, x, y, z);
#define UNARY(x, y, z) return unary(c, x, y, z);
dummy = 1;
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Parsing next token from: [%s]", c->ptr);
for (;;)
{
switch (*(c->ptr++))
{
case '(':
c->operand = 1;
return M_INPAR;
case ')':
if (check_implied_arg(c))
pusht(c, 0);
c->operand = 0;
return M_OUTPAR;
case '+':
{
check_implied_arg(c);
if (*c->ptr == '+' && (c->operand || !isalnum((unsigned char)*c->ptr)))
{
c->ptr++;
return c->operand ? PREPLUS : POSTPLUS;
}
else if (*c->ptr == '=')
OPERATOR("+=", 1, PLUSEQ)
else if (c->operand)
UNARY("+", 0, UPLUS)
else
OPERATOR("+", 0, PLUS)
}
case '-':
{
check_implied_arg(c);
if (*c->ptr == '-' && (c->operand || !isalnum((unsigned char)*c->ptr)))
{
c->ptr++;
return (c->operand) ? PREMINUS : POSTMINUS;
}
else if (*c->ptr == '=')
OPERATOR("-=", 1, MINUSEQ)
else if (c->operand)
UNARY("-", 0, UMINUS)
else
OPERATOR("-", 0, MINUS)
}
case '*':
{
if (*c->ptr == '*')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("**=", 1, POWEREQ)
else
OPERATOR("**", 0, POWER)
}
else if (*c->ptr == '=')
OPERATOR("*=", 1, MULEQ)
else if (c->operand)
{
dummy = 2;
UNARY("*", 0, DEREF)
}
else
OPERATOR("*", 0, MUL)
}
case '/':
{
if (*c->ptr == '=')
OPERATOR("/=", 1, DIVEQ)
else
OPERATOR("/", 0, DIV)
}
case '%':
{
if (*c->ptr == '=')
OPERATOR("%=", 1, MODEQ)
else
OPERATOR("%", 0, MOD)
}
case '!':
{
if (*c->ptr == '=')
OPERATOR("!=", 1, NEQ)
else if (*c->ptr == '~')
OPERATOR("!~", 1, NOMATCH)
else
UNARY("!", 0, NOT)
}
case '~':
UNARY("~", 0, COMP)
case '&':
{
if (*c->ptr == '&')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("&&=", 1, DANDEQ)
else
OPERATOR("&&", 0, DAND)
}
else if (*c->ptr == '=')
OPERATOR("&=", 1, ANDEQ)
else
OPERATOR("&", 0, AND)
}
case '|':
{
if (*c->ptr == '|')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("||=", 1, DOREQ)
else
OPERATOR("||", 0, DOR)
}
else if (*c->ptr == '=')
OPERATOR("|=", 1, OREQ)
else
OPERATOR("|", 0, OR)
}
case '^':
{
if (*c->ptr == '^')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("^^=", 1, DXOREQ)
else
OPERATOR("^^", 0, DXOR)
}
else if (*c->ptr == '=')
OPERATOR("^=", 1, XOREQ)
else
OPERATOR("^", 0, XOR)
}
case '#':
{
check_implied_arg(c);
if (*c->ptr == '#')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("##=", 1, STRCATEQ)
else
OPERATOR("##", 0, STRCAT)
}
else if (*c->ptr == '=')
OPERATOR("#=", 1, STRCATEQ)
else if (*c->ptr == '~')
OPERATOR("#~", 1, STRPREEQ)
else if (c->operand)
{
dummy = 2;
UNARY("#", 0, WORDC)
}
else
OPERATOR("#", 0, STRCAT)
}
case '@':
dummy = 2;
UNARY("@", 0, STRLEN)
case '<':
{
if (*c->ptr == '<')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR("<<=", 1, SHLEFTEQ)
else
OPERATOR("<<", 0, SHLEFT)
}
else if (*c->ptr == '=')
{
c->ptr++;
if (*c->ptr == '>')
OPERATOR("<=>", 1, SWAP)
else
OPERATOR("<=", 0, LEQ)
}
else
OPERATOR("<", 0, LES)
}
case '>':
{
if (*c->ptr == '>')
{
c->ptr++;
if (*c->ptr == '=')
OPERATOR(">>=", 1, SHRIGHTEQ)
else
OPERATOR(">>", 0, SHRIGHT)
}
else if (*c->ptr == '=')
OPERATOR(">=", 1, GEQ)
else
OPERATOR(">", 0, GRE)
}
case '=':
if (*c->ptr == '=')
OPERATOR("==", 1, DEQ)
else if (*c->ptr == '~')
OPERATOR("=~", 1, MATCH)
else
OPERATOR("=", 0, EQ)
case '?':
c->operand = 1;
return QUEST;
case ':':
if (c->operand)
goto handle_expando;
c->operand = 1;
return COLON;
case ',':
if (c->operand)
goto handle_expando;
c->operand = 1;
return COMMA;
case '\0':
check_implied_arg(c);
c->operand = 1;
c->ptr--;
return EOI;
case '[':
{
char *p = c->ptr - 1;
char oc = 0;
if (!c->operand)
return lexerr(c, "Misplaced [ token");
if ((c->ptr = MatchingBracket(p + 1, '[', ']')))
{
oc = *c->ptr;
*c->ptr = 0;
}
else
c->ptr = empty_string;
c->last_token = tokenize(c, p);
if (oc)
*c->ptr++ = oc;
c->operand = 0;
return ID;
}
case ' ':
case '\t':
case '\n':
start++;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
char *end;
char endc;
c->operand = 0;
c->ptr--;
strtod(c->ptr, &end);
endc = *end;
*end = 0;
c->last_token = tokenize(c, c->ptr);
*end = endc;
c->ptr = end;
return ID;
}
case '$':
continue;
default:
handle_expando:
{
char *end;
char endc;
c->operand = 0;
c->ptr--;
if ((end = after_expando_special(c)))
{
endc = *end;
*end = 0;
c->last_token = tokenize(c, start);
*end = endc;
c->ptr = end;
}
else
{
c->last_token = 0;
c->ptr = empty_string;
}
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("After token: [%s]", c->ptr);
return ID;
}
}
}
}
static void mathparse (expr_info *c, int pc)
{
int otok,
onoeval;
if (c->errflag)
return;
c->mtok = zzlex(c);
while (prec[c->mtok] <= pc)
{
if (c->errflag)
return;
switch (c->mtok)
{
case ID:
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Parsed identifier token [%s]", get_token(c, c->last_token));
if (c->noeval)
pusht(c, 0);
else
pusht(c, c->last_token);
break;
case M_INPAR:
{
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Parsed open paren");
mathparse(c, TOPPREC);
if (c->mtok != M_OUTPAR)
{
if (!c->errflag)
error("')' expected");
return;
}
break;
}
case QUEST:
{
long u = popb(c);
pushn(c, u);
if (!u)
c->noeval++;
mathparse(c, prec[QUEST] - 1);
if (!u)
c->noeval--;
else
c->noeval++;
mathparse(c, prec[QUEST]);
if (u)
c->noeval--;
op(c, QUEST);
continue;
}
default:
{
otok = c->mtok;
onoeval = c->noeval;
if (assoc[otok] == BOOL)
{
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Parsed short circuit operator");
switch (otok)
{
case DAND:
case DANDEQ:
{
long u = popb(c);
pushn(c, u);
if (!u)
c->noeval++;
break;
}
case DOR:
case DOREQ:
{
long u = popb(c);
pushn(c, u);
if (u)
c->noeval++;
break;
}
}
}
if (x_debug & DEBUG_NEW_MATH_DEBUG)
debugyell("Parsed operator of type [%d]", otok);
mathparse(c, prec[otok] - (assoc[otok] != RL));
c->noeval = onoeval;
op(c, otok);
continue;
}
}
c->mtok = zzlex(c);
}
}
static char * matheval (char *s, const char *args, int *args_flag)
{
expr_info context;
char * ret;
if (!s || !*s)
return m_strdup(empty_string);
setup_expr_info(&context);
context.ptr = s;
context.args = args;
context.args_flag = args_flag;
mathparse(&context, TOPPREC);
if (context.errflag)
{
ret = m_strdup(empty_string);
goto cleanup;
}
if (context.sp)
error("The expression has too many operands");
if (x_debug & DEBUG_NEW_MATH_DEBUG)
{
int i;
debugyell("Terms left: %d", context.sp);
for (i = 0; i <= context.sp; i++)
debugyell("Term [%d]: [%s]", i,
get_token(&context, context.stack[i]));
}
ret = getsval(&context, pop(&context));
cleanup:
destroy_expr_info(&context);
if (internal_debug & DEBUG_EXPANSIONS && !in_debug_yell)
debugyell("Returning [%s]", ret);
return ret;
}
static char * after_expando_special (expr_info *c)
{
char *start;
char *rest;
int call;
if (!(start = c->ptr))
return c->ptr;
for (;;)
{
rest = after_expando(start, 0, &call);
if (*rest != '$')
break;
start = rest + 1;
}
return rest;
}