/* * Copyright (C) 2003 Tim Martin * * This program 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. * * This program 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include "map.h" #include "function.h" struct func_s { enum { VARIABLE = 0, NUMBER, IF, OP_MULTIPLY, OP_DIVIDE, OP_ADD, OP_SUBTRACT, OP_MOD, LPAREN, RPAREN, } type; char *variablename; int value; struct func_s *arg1; struct func_s *arg2; }; static func_t * parse_op(char *str) { char *end = NULL; func_t *ret = calloc(1, sizeof(func_t)); if (!ret) return NULL; if (!str) { printf("Op is NULL\n"); return NULL; } switch(str[0]) { case '(': ret->type = LPAREN; return ret; case ')': ret->type = RPAREN; return ret; case '$': ret->type = VARIABLE; ret->variablename = strdup(str+1); return ret; case '*': ret->type = OP_MULTIPLY; return ret; case '/': ret->type = OP_DIVIDE; return ret; case '+': ret->type = OP_ADD; return ret; case '-': if (isdigit(str[1])) { goto number; } ret->type = OP_SUBTRACT; return ret; case '%': ret->type = OP_MOD; return ret; case 'i': case 'I': if (strcasecmp(str,"IF") == 0) { ret->type = IF; return ret; } else { return NULL; } default: number: ret->type = NUMBER; ret->value = strtol(str, &end, 10); if ((ret->value == LONG_MIN) || (ret->value == LONG_MAX) || (*end)) { printf(_("Error parsing [%s]\n"), str); return NULL; } return ret; } } extern func_t * function_parse(char **argv, int argc, int *parsed) { int i; func_t *cur = NULL; for (i = 0; i < argc; i++) { func_t *new = parse_op(argv[i]); if (!new) { printf(_("Parse error parsing %s\n"), argv[i]); return NULL; } if (new->type == RPAREN) { if (parsed) *parsed = i+1; return cur; } if (new->type == LPAREN) { int did = 0; new = function_parse(argv+i+1, argc - i - 1, &did); i += did; } if (!cur) { cur = new; } else if (cur->type == IF) { cur->arg1 = new; cur->arg2 = parse_op(argv[i+1]); if (cur->arg2->type == LPAREN) { int did = 0; cur->arg2 = function_parse(argv+i+2, argc - i - 2, &did); i += did; } i++; } else { switch(new->type) { case OP_MULTIPLY: case OP_DIVIDE: case OP_ADD: case OP_SUBTRACT: case OP_MOD: new->arg1 = cur; new->arg2 = parse_op(argv[i+1]); if (new->arg2->type == LPAREN) { int did = 0; new->arg2 = function_parse(argv+i+2, argc - i - 2, &did); i += did; } i++; cur = new; break; default: printf(_("Can't have those 2 args next to eachother: %d and %d\n"), cur->type, new->type); return NULL; break; } } } return cur; } /* * Make into a args structure * * XXX doesn't honor maxargs */ static int make_args(char *str, char **argv, int maxargs, int *argc) { int numargs = 0; while (str) { char *end; while ((*str) && (isspace((int)*str))) str++; if (*str == '\0') break; end = str; while ((*end) && (!isspace((int)*end))) end++; if (*end) { *end = '\0'; end++; } argv[numargs++] = str; str = end; } *argc = numargs; argv[numargs] = NULL; return 0; } extern func_t * function_parse_string(char *str) { char *argv[100]; int argc; make_args(str, argv, 10, &argc); return function_parse(argv, argc, NULL); } extern int function_evaluate(func_t *func, func_getvariable_cb *getvar_cb, void *getvar_rock) { int mod; if (!func) return 0; switch(func->type) { case IF: if (function_evaluate(func->arg1, getvar_cb, getvar_rock)) { return function_evaluate(func->arg2, getvar_cb, getvar_rock); } else { return 0; } case VARIABLE: if (strcasecmp(func->variablename,"random") == 0) { return rand(); } else { int val; if (getvar_cb) { val = getvar_cb(func->variablename, getvar_rock); } else { val = 0; } return val; } break; case NUMBER: return func->value; case OP_MULTIPLY: return function_evaluate( func->arg1, getvar_cb, getvar_rock) * function_evaluate( func->arg2, getvar_cb, getvar_rock); case OP_DIVIDE: return function_evaluate( func->arg1, getvar_cb, getvar_rock) / function_evaluate( func->arg2, getvar_cb, getvar_rock); case OP_ADD: return function_evaluate( func->arg1, getvar_cb, getvar_rock) + function_evaluate( func->arg2, getvar_cb, getvar_rock); case OP_SUBTRACT: return function_evaluate( func->arg1, getvar_cb, getvar_rock) - function_evaluate( func->arg2, getvar_cb, getvar_rock); case OP_MOD: mod = function_evaluate( func->arg2, getvar_cb, getvar_rock); if (mod == 0) { return 0; } else { return function_evaluate( func->arg1, getvar_cb, getvar_rock) % mod; } default: printf(_("Type not understood: %d\n"), func->type); return 0; } }