/* expr.c */ #include "config.h" /* * This file is part of TeenyMUD II. * Copyright(C) 1995 by Jason Downs. All rights reserved. * * TeenyMUD II is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * TeenyMUD II is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file 'COPYING'); if not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * */ #include <sys/types.h> #ifdef HAVE_STRING_H #include <string.h> #else #include <strings.h> #endif /* HAVE_STRING_H */ #include <ctype.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif /* HAVE_STDLIB_H */ #include "conf.h" #include "teeny.h" #include "expr.h" #include "externs.h" /* * The TeenyMUD II math expression evaluator, version 2. */ static int isfloat _ANSI_ARGS_((char *)); static struct expr_val expr_sub _ANSI_ARGS_((char *, char **)); static int isfloat(str) register char *str; { while(*str && isspace(*str)) str++; if((*str == '.') && isdigit(str[1])) return(1); while(*str && isdigit(*str)) str++; if((*str == '.') && isdigit(str[1])) return(1); return(0); } /* expression evaluator */ static struct expr_val expr_sub(str, nptr) register char *str; char **nptr; { struct expr_val val; int error; switch(str[0]) { case '(': str++; if((*nptr = parse_to(str, '(', ')'))) { val = expr_parse(str, &error); if(error) *nptr = (char *)NULL; } break; case '-': str++; if(!*str) *nptr = (char *)NULL; else { if(*str == '(') { /* awe, fuck */ str++; if((*nptr = parse_to(str, '(', ')'))) { if((val = expr_parse(str, &error))) { switch(val.type) { case EXPRVAL_INT: (val.val).ival = -(val.val).ival; break; case EXPRVAL_FLOAT: (val.val).fval = -(val.val).fval; break; } if(error) *nptr = (char *)NULL; } } } else { if(isdouble(str)) { (val.val).fval = strtod(str, nptr); if(*nptr == str) *nptr = (char *)NULL; else { val.type = EXPRVAL_FLOAT; (val.val).fval = -(val.val).fval; } } else { (val.val).ival = (int)strtol(str, nptr, 10); if(*nptr == str) *nptr = (char *)NULL; else { val.type = EXPRVAL_INT; (val.val).ival = -(val.val).ival; } } } } break; case '~': str++; if(!*str) *nptr = (char *)NULL; else { if(*str == '(') { /* argh */ str++; if((*nptr = parse_to(str, '(', ')'))) { if((val = expr_parse(str, &error))) { switch(val.type) { case EXPRVAL_INT: (val.val).ival = ~(val.val).ival; break; case EXPRVAL_FLOAT: error++; break; } if(error) *nptr = (char *)NULL; } } } else { if(isdouble(str)) *nptr = (char *)NULL; else { (val.val).ival = (int)strtol(str, nptr, 10); if(*nptr == str) *nptr = (char *)NULL; else { val.type = EXPRVAL_INT; (val.val).ival = ~(val.val).ival; } } } } break; case '!': str++; if(!*str) *nptr = (char *)NULL; else { if(*str == '(') { /* die, scum */ str++; if((*nptr = parse_to(str, '(', ')'))) { if((val = expr_parse(str, &error))) { switch(val.type) { case EXPRVAL_INT: (val.val).ival = !(val.val).ival; break; case EXPRVAL_FLOAT: error++; break; } if(error) *nptr = (char *)NULL; } } } else { if(isdouble(str)) *nptr = (char *)NULL; else { (val.val).ival = (int)strtol(str, nptr, 10); if(*nptr == str) *nptr = (char *)NULL; else { val.type = EXPRVAL_INT; (val.val).ival = !(val.val).ival; } } } } break; default: if(isdouble(str)) { (val.val).fval = strtod(str, nptr); if(*nptr == str) *nptr = (char *)NULL; else val.type = EXPRVAL_FLOAT; } else if(isdigit(str[0])) { (val.val).ival = strtol(str, nptr, 10); if(*nptr == str) *nptr = (char *)NULL; else val.type = EXPRVAL_INT; } else { *nptr = (char *)NULL; } break; } return(val); } long expr_parse(str, error) char *str; int *error; { register long left = 0, right = 0; int first = 1; char *expr, *nptr; if (!str) { *error = 1; return(0); } else *error = 0; while(*str && !*error) { while(*str && isspace(*str)) str++; if(!*str) break; if(first) { left = expr_sub(str, &nptr); if(!nptr) { *error = 1; break; } for(str = nptr; *str && isspace(*str); str++); if(!*str) break; first = 0; } expr = str; while(*str && strchr("*/%+-<>=!&^|", *str)) str++; while(*str && isspace(*str)) str++; if(!*str || (!isdigit(*str) && !strchr("(-~!", *str))) { *error = 1; break; } right = expr_sub(str, &nptr); if(!nptr) { *error = 1; break; } str = nptr; /* evaluate */ switch(expr[0]) { case '*': /* multiply */ left *= right; break; case '/': /* divide */ left /= right; break; case '%': /* modulo */ left %= right; break; case '+': /* addition */ left += right; break; case '-': /* substraction */ left -= right; break; case '<': switch(expr[1]) { case '<': /* shift */ left = left << right; break; case '=': /* lesser than or equal */ left = (left <= right); break; default: /* lesser than */ left = (left < right); break; } break; case '>': switch(expr[1]) { case '>': /* shift */ left = left >> right; break; case '=': /* greater than or equal */ left = (left >= right); break; default: /* greater than */ left = (left > right); break; } break; case '=': if(expr[1] != '=') { *error = 1; break; } left = (left == right); break; case '!': if(expr[1] != '=') { *error = 1; break; } left = (left != right); break; case '^': left ^= right; break; case '&': switch(expr[1]) { case '&': left = (left && right); break; default: left &= right; break; } break; case '|': switch(expr[1]) { case '|': left = (left || right); break; default: left |= right; break; } break; default: *error = 1; } } return(left); }