From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- evaluator.c | 1430 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1430 insertions(+) create mode 100644 evaluator.c (limited to 'evaluator.c') diff --git a/evaluator.c b/evaluator.c new file mode 100644 index 0000000..f5f8b06 --- /dev/null +++ b/evaluator.c @@ -0,0 +1,1430 @@ +/* $Id: evaluator.c 1038 2009-08-21 03:33:16Z michael $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/evaluator.c $ + * + * expression evaluation + * + * Copyright (C) 1999, 2000 Michael Reinelt + * Copyright (C) 2004 The LCD4Linux Team + * + * This file is part of LCD4Linux. + * + * LCD4Linux 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, or (at your option) + * any later version. + * + * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + * exported functions: + * + * int SetVariable (char *name, RESULT *value) + * adds a generic variable to the evaluator + * + * int SetVariableNumeric (char *name, double value) + * adds a numerical variable to the evaluator + * + * int SetVariableString (char *name, char *value) + * adds a numerical variable to the evaluator + * + * int AddFunction (char *name, int argc, void (*func)()) + * adds a function to the evaluator + * + * void DeleteVariables (void); + * frees all allocated variables + * + * void DeleteFunctions (void); + * frees all allocated functions + * + * void DelResult (RESULT *result) + * sets a result to none + * frees a probably allocated memory + * + * RESULT* SetResult (RESULT **result, int type, void *value) + * initializes a result + * + * double R2N (RESULT *result) + * converts a result into a number + * + * char* R2S (RESULT *result) + * converts a result into a string + * + * + * int Compile (char* expression, void **tree) + * compiles a expression into a tree + * + * int Eval (void *tree, RESULT *result) + * evaluates an expression + * + * void DelTree (void *tree) + * frees a compiled tree + */ + + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "evaluator.h" + +#ifdef WITH_DMALLOC +#include +#endif + +/* string buffer chunk size */ +#define CHUNK_SIZE 16 + +typedef enum { + T_UNDEF, + T_NAME, + T_NUMBER, + T_STRING, + T_OPERATOR, + T_VARIABLE, + T_FUNCTION +} TOKEN; + +typedef enum { + O_UNDEF, /* undefined */ + O_LST, /* expression lists */ + O_SET, /* variable assignements */ + O_CND, /* conditional a?b:c */ + O_COL, /* colon in a?b:c */ + O_OR, /* logical OR */ + O_AND, /* logical AND */ + O_NEQ, /* numeric equal */ + O_NNE, /* numeric not equal */ + O_NLT, /* numeric less than */ + O_NLE, /* numeric less or equal */ + O_NGT, /* numeric greater than */ + O_NGE, /* numeric greater or equal */ + O_SEQ, /* string equal */ + O_SNE, /* string not equal */ + O_SLT, /* string less than */ + O_SLE, /* string less or equal */ + O_SGT, /* string greater than */ + O_SGE, /* string greater or equal */ + O_ADD, /* addition */ + O_SUB, /* subtraction */ + O_SGN, /* sign '-' */ + O_CAT, /* string concatenation */ + O_MUL, /* multiplication */ + O_DIV, /* division */ + O_MOD, /* modulo */ + O_POW, /* power */ + O_NOT, /* logical NOT */ + O_BRO, /* open brace */ + O_COM, /* comma (argument seperator) */ + O_BRC /* closing brace */ +} OPERATOR; + +typedef struct { + char *pattern; + int len; + OPERATOR op; +} PATTERN; + +typedef struct { + char *name; + RESULT *value; +} VARIABLE; + +typedef struct { + char *name; + int argc; + void (*func) (); +} FUNCTION; + +typedef struct _NODE { + TOKEN Token; + OPERATOR Operator; + RESULT *Result; + VARIABLE *Variable; + FUNCTION *Function; + int Children; + struct _NODE **Child; +} NODE; + + + +/* non-alphanumeric operators */ +/* IMPORTANT! list must be sorted by length! */ +static PATTERN Pattern1[] = { + {";", 1, O_LST}, /* expression lists */ + {"=", 1, O_SET}, /* variable assignements */ + {"?", 1, O_CND}, /* conditional a?b:c */ + {":", 1, O_COL}, /* colon a?b:c */ + {"|", 1, O_OR}, /* logical OR */ + {"&", 1, O_AND}, /* logical AND */ + {"<", 1, O_NLT}, /* numeric less than */ + {">", 1, O_NGT}, /* numeric greater than */ + {"+", 1, O_ADD}, /* addition */ + {"-", 1, O_SUB}, /* subtraction or sign */ + {".", 1, O_CAT}, /* string concatenation */ + {"*", 1, O_MUL}, /* multiplication */ + {"/", 1, O_DIV}, /* division */ + {"%", 1, O_MOD}, /* modulo */ + {"^", 1, O_POW}, /* power */ + {"!", 1, O_NOT}, /* logical NOT */ + {"(", 1, O_BRO}, /* open brace */ + {",", 1, O_COM}, /* comma (argument seperator) */ + {")", 1, O_BRC}, /* closing brace */ + {"==", 2, O_NEQ}, /* numeric equal */ + {"!=", 2, O_NNE}, /* numeric not equal */ + {"<=", 2, O_NLE}, /* numeric less or equal */ + {">=", 2, O_NGE} /* numeric greater or equal */ +}; + +/* alphanumeric operators */ +/* IMPORTANT! list must be sorted by length! */ +static PATTERN Pattern2[] = { + {"eq", 2, O_SEQ}, /* string equal */ + {"ne", 2, O_SNE}, /* string not equal */ + {"lt", 2, O_SLT}, /* string less than */ + {"le", 2, O_SLE}, /* string less or equal */ + {"gt", 2, O_SGT}, /* string greater than */ + {"ge", 2, O_SGE} /* string greater or equal */ +}; + + +static char *Expression = NULL; +static char *ExprPtr = NULL; +static char *Word = NULL; +static TOKEN Token = T_UNDEF; +static OPERATOR Operator = O_UNDEF; + +static VARIABLE Variable[255]; +static unsigned int nVariable = 0; + +static FUNCTION *Function = NULL; +static unsigned int nFunction = 0; + + +/* strndup() may be not available on several platforms */ +#ifndef HAVE_STRNDUP +char *strndup(const char *source, size_t len) +{ + char *tmp = NULL; + + if (source == NULL) + return NULL; + + if (len >= strlen(source)) + return strdup(source); + + tmp = malloc(len + 1); + if (tmp == 0) + return NULL; + + strncpy(tmp, source, len); + tmp[len] = '\0'; + + return (tmp); +} +#endif + + +void DelResult(RESULT * result) +{ + result->type = 0; + result->size = 0; + result->number = 0.0; + if (result->string) { + free(result->string); + result->string = NULL; + } +} + + +static void FreeResult(RESULT * result) +{ + if (result != NULL) { + DelResult(result); + free(result); + } +} + + +static RESULT *NewResult(void) +{ + RESULT *result = malloc(sizeof(RESULT)); + if (result == NULL) { + error("Evaluator: cannot allocate result: out of memory!"); + return NULL; + } + result->type = 0; + result->size = 0; + result->number = 0.0; + result->string = NULL; + + return result; +} + + +RESULT *SetResult(RESULT ** result, const int type, const void *value) +{ + if (*result == NULL) { + if ((*result = NewResult()) == NULL) + return NULL; + } else if (type == R_NUMBER) { + DelResult(*result); + } + + if (type == R_NUMBER) { + (*result)->type = R_NUMBER; + (*result)->size = 0; + (*result)->number = *(double *) value; + (*result)->string = NULL; + } + + else if (type == R_STRING) { + int len = strlen((char *) value); + (*result)->type = R_STRING; + (*result)->number = 0.0; + if ((*result)->string == NULL || len >= (*result)->size) { + /* buffer is either empty or too small */ + if ((*result)->string) + free((*result)->string); + /* allocate memory in multiples of CHUNK_SIZE */ + (*result)->size = CHUNK_SIZE * ((len + 1) / CHUNK_SIZE + 1); + (*result)->string = malloc((*result)->size); + } + strcpy((*result)->string, value); + } else { + error("Evaluator: internal error: invalid result type %d", type); + return NULL; + } + + return *result; +} + + +RESULT *CopyResult(RESULT ** result, RESULT * value) +{ + if (*result == NULL) { + if ((*result = NewResult()) == NULL) + return NULL; + } + + (*result)->type = value->type; + (*result)->number = value->number; + + if (value->string == NULL) { + (*result)->size = 0; + if ((*result)->string) + free((*result)->string); + (*result)->string = NULL; + } else { + /* is buffer large enough? */ + if ((*result)->string == NULL || value->size > (*result)->size) { + if ((*result)->string) + free((*result)->string); + (*result)->size = value->size; + (*result)->string = malloc((*result)->size); + } + strcpy((*result)->string, value->string); + } + return *result; +} + + +double R2N(RESULT * result) +{ + if (result == NULL) { + error("Evaluator: internal error: NULL result"); + return 0.0; + } + + if (result->type == 0) { + return 0.0; + } + + if (result->type & R_NUMBER) { + return result->number; + } + + if (result->type & R_STRING) { + result->type |= R_NUMBER; + result->number = atof(result->string); + return result->number; + } + + error("Evaluator: internal error: invalid result type %d", result->type); + return 0.0; +} + + +char *R2S(RESULT * result) +{ + if (result == NULL) { + error("Evaluator: internal error: NULL result"); + return NULL; + } + + if (result->type == 0) { + return NULL; + } + + if (result->type & R_STRING) { + return result->string; + } + + if (result->type & R_NUMBER) { + result->type |= R_STRING; + if (result->string) + free(result->string); + result->size = CHUNK_SIZE; + result->string = malloc(result->size); + snprintf(result->string, result->size, "%g", result->number); + return result->string; + } + + error("Evaluator: internal error: invalid result type %d", result->type); + return NULL; + +} + + +static VARIABLE *FindVariable(const char *name) +{ + unsigned int i; + + for (i = 0; i < nVariable; i++) { + if (strcmp(name, Variable[i].name) == 0) { + return &Variable[i]; + } + } + return NULL; +} + + +int SetVariable(const char *name, RESULT * value) +{ + VARIABLE *V; + + V = FindVariable(name); + if (V != NULL) { + CopyResult(&V->value, value); + return 1; + } + + if (nVariable >= sizeof(Variable) / sizeof(Variable[0])) { + error("Evaluator: cannot set variable <%s>: out of slots", name); + return -1; + } + + nVariable++; + Variable[nVariable - 1].name = strdup(name); + Variable[nVariable - 1].value = NULL; + CopyResult(&Variable[nVariable - 1].value, value); + + return 0; +} + + +int SetVariableNumeric(const char *name, const double value) +{ + RESULT result = { 0, 0, 0, NULL }; + RESULT *rp = &result; + + SetResult(&rp, R_NUMBER, &value); + + return SetVariable(name, rp); +} + + +int SetVariableString(const char *name, const char *value) +{ + RESULT result = { 0, 0, 0, NULL }; + RESULT *rp = &result; + + SetResult(&rp, R_STRING, value); + + return SetVariable(name, rp); +} + + +void DeleteVariables(void) +{ + unsigned int i; + + for (i = 0; i < nVariable; i++) { + free(Variable[i].name); + FreeResult(Variable[i].value); + } + nVariable = 0; +} + + +/* bsearch compare function for functions */ +static int LookupFunction(const void *a, const void *b) +{ + char *n = (char *) a; + FUNCTION *f = (FUNCTION *) b; + + return strcmp(n, f->name); +} + + +/* qsort compare function for functions */ +static int SortFunction(const void *a, const void *b) +{ + FUNCTION *fa = (FUNCTION *) a; + FUNCTION *fb = (FUNCTION *) b; + + return strcmp(fa->name, fb->name); +} + + +static FUNCTION *FindFunction(const char *name) +{ + return bsearch(name, Function, nFunction, sizeof(FUNCTION), LookupFunction); +} + + +int AddFunction(const char *name, const int argc, void (*func) ()) +{ + nFunction++; + Function = realloc(Function, nFunction * sizeof(FUNCTION)); + Function[nFunction - 1].name = strdup(name); + Function[nFunction - 1].argc = argc; + Function[nFunction - 1].func = func; + + qsort(Function, nFunction, sizeof(FUNCTION), SortFunction); + + return 0; +} + + +void DeleteFunctions(void) +{ + unsigned int i; + + for (i = 0; i < nFunction; i++) { + free(Function[i].name); + } + free(Function); + Function = NULL; + nFunction = 0; +} + + +#define is_space(c) ((c) == ' ' || (c) == '\t') +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define is_alpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z') || ((c) == '_')) +#define is_alnum(c) (is_alpha(c) || is_digit(c)) + +static void Parse(void) +{ + Token = T_UNDEF; + Operator = O_UNDEF; + + if (Word) { + free(Word); + Word = NULL; + } + + /* NULL expression? */ + if (ExprPtr == NULL) { + Word = strdup(""); + return; + } + + /* skip leading whitespace */ + while (is_space(*ExprPtr)) + ExprPtr++; + + /* names */ + if (is_alpha(*ExprPtr)) { + int i; + char *start = ExprPtr; + while (is_alnum(*ExprPtr)) + ExprPtr++; + if (*ExprPtr == ':' && *(ExprPtr + 1) == ':' && is_alpha(*(ExprPtr + 2))) { + ExprPtr += 3; + while (is_alnum(*ExprPtr)) + ExprPtr++; + } + Word = strndup(start, ExprPtr - start); + Token = T_NAME; + + /* check for alphanumeric operators */ + for (i = sizeof(Pattern2) / sizeof(Pattern2[0]) - 1; i >= 0; i--) { + if (strcmp(Word, Pattern2[i].pattern) == 0) { + Token = T_OPERATOR; + Operator = Pattern2[i].op; + break; + } + } + + } + + /* numbers */ + else if (is_digit(*ExprPtr) || (*ExprPtr == '.' && is_digit(*(ExprPtr + 1)))) { + char *start = ExprPtr; + while (is_digit(*ExprPtr)) + ExprPtr++; + if (*ExprPtr == '.') { + ExprPtr++; + while (is_digit(*ExprPtr)) + ExprPtr++; + } + Word = strndup(start, ExprPtr - start); + Token = T_NUMBER; + } + + /* strings */ + else if (*ExprPtr == '\'') { + size_t length = 0; + size_t size = CHUNK_SIZE; + Word = malloc(size); + ExprPtr++; + while (*ExprPtr != '\0' && *ExprPtr != '\'') { + if (*ExprPtr == '\\') { + switch (*(ExprPtr + 1)) { + case '\\': + case '\'': + Word[length++] = *(ExprPtr + 1); + ExprPtr += 2; + break; + case 'a': + Word[length++] = '\a'; + ExprPtr += 2; + break; + case 'b': + Word[length++] = '\b'; + ExprPtr += 2; + break; + case 't': + Word[length++] = '\t'; + ExprPtr += 2; + break; + case 'n': + Word[length++] = '\n'; + ExprPtr += 2; + break; + case 'v': + Word[length++] = '\v'; + ExprPtr += 2; + break; + case 'f': + Word[length++] = '\f'; + ExprPtr += 2; + break; + case 'r': + Word[length++] = '\r'; + ExprPtr += 2; + break; + case '0': + case '1': + case '2': + case '3': + if (*(ExprPtr + 2) >= '0' && *(ExprPtr + 2) <= '7' && + *(ExprPtr + 3) >= '0' && *(ExprPtr + 3) <= '7') { + Word[length++] = + (*(ExprPtr + 1) - '0') * 64 + (*(ExprPtr + 2) - '0') * 8 + (*(ExprPtr + 3) - '0'); + ExprPtr += 4; + } else { + error("Evaluator: illegal octal sequence '\\%c%c%c' in <%s>", + *(ExprPtr + 1), *(ExprPtr + 2), *(ExprPtr + 3), Expression); + Word[length++] = *ExprPtr++; + } + break; + default: + error("Evaluator: unknown escape sequence '\\%c' in <%s>", *(ExprPtr + 1), Expression); + Word[length++] = *ExprPtr++; + } + } else { + Word[length++] = *ExprPtr++; + } + if (length >= size) { + size += CHUNK_SIZE; + Word = realloc(Word, size); + } + } + Word[length] = '\0'; + Token = T_STRING; + if (*ExprPtr == '\'') { + ExprPtr++; + } else { + error("Evaluator: unterminated string in <%s>", Expression); + } + } + + /* non-alpha operators */ + else { + int i; + for (i = sizeof(Pattern1) / sizeof(Pattern1[0]) - 1; i >= 0; i--) { + int len = Pattern1[i].len; + if (strncmp(ExprPtr, Pattern1[i].pattern, Pattern1[i].len) == 0) { + Word = strndup(ExprPtr, len); + Token = T_OPERATOR; + Operator = Pattern1[i].op; + ExprPtr += len; + break; + } + } + } + + /* syntax check */ + if (Token == T_UNDEF && *ExprPtr != '\0') { + error("Evaluator: parse error in <%s>: garbage <%s>", Expression, ExprPtr); + } + + /* skip trailing whitespace */ + while (is_space(*ExprPtr)) + ExprPtr++; + + /* empty token */ + if (Word == NULL) + Word = strdup(""); +} + + +static NODE *NewNode(NODE * Child) +{ + NODE *N; + + N = malloc(sizeof(NODE)); + if (N == NULL) + return NULL; + + memset(N, 0, sizeof(NODE)); + N->Token = Token; + N->Operator = Operator; + + if (Child != NULL) { + N->Children = 1; + N->Child = malloc(sizeof(NODE *)); + N->Child[0] = Child; + } + + return N; + +} + + +static NODE *JunkNode(void) +{ + NODE *Junk; + + Junk = NewNode(NULL); + Junk->Token = T_STRING; + SetResult(&Junk->Result, R_STRING, ""); + + return Junk; +} + + +static void LinkNode(NODE * Root, NODE * Child) +{ + + if (Child == NULL) + return; + + Root->Children++; + Root->Child = realloc(Root->Child, Root->Children * sizeof(NODE *)); + if (Root->Child == NULL) + return; + Root->Child[Root->Children - 1] = Child; +} + + +/* forward declaration */ +static NODE *Level01(void); + + +/* literal numbers, variables, functions */ +static NODE *Level12(void) +{ + NODE *Root = NULL; + + if (Token == T_OPERATOR && Operator == O_BRO) { + Parse(); + Root = Level01(); + if (Token != T_OPERATOR || Operator != O_BRC) { + error("Evaluator: unbalanced parentheses in <%s>", Expression); + LinkNode(Root, JunkNode()); + } + } + + else if (Token == T_NUMBER) { + double value = atof(Word); + Root = NewNode(NULL); + SetResult(&Root->Result, R_NUMBER, &value); + } + + else if (Token == T_STRING) { + Root = NewNode(NULL); + SetResult(&Root->Result, R_STRING, Word); + } + + else if (Token == T_NAME) { + + /* look-ahead for opening brace */ + if (*ExprPtr == '(') { + int argc = 0; + Root = NewNode(NULL); + Root->Token = T_FUNCTION; + Root->Result = NewResult(); + Root->Function = FindFunction(Word); + if (Root->Function == NULL) { + error("Evaluator: unknown function '%s' in <%s>", Word, Expression); + Root->Token = T_STRING; + SetResult(&Root->Result, R_STRING, ""); + } + + /* opening brace */ + Parse(); + do { + Parse(); /* read argument */ + if (Token == T_OPERATOR && Operator == O_BRC) { + break; + } else if (Token == T_OPERATOR && Operator == O_COM) { + error("Evaluator: empty argument in <%s>", Expression); + LinkNode(Root, JunkNode()); + } else { + LinkNode(Root, Level01()); + } + argc++; + } while (Token == T_OPERATOR && Operator == O_COM); + + /* check for closing brace */ + if (Token != T_OPERATOR || Operator != O_BRC) { + error("Evaluator: missing closing brace in <%s>", Expression); + } + + /* check number of arguments */ + if (Root->Function != NULL && Root->Function->argc >= 0 && Root->Function->argc != argc) { + error("Evaluator: wrong number of arguments in <%s>", Expression); + while (argc < Root->Function->argc) { + LinkNode(Root, JunkNode()); + argc++; + } + } + + } else { + Root = NewNode(NULL); + Root->Token = T_VARIABLE; + Root->Result = NewResult(); + Root->Variable = FindVariable(Word); + if (Root->Variable == NULL) { + SetVariableString(Word, ""); + Root->Variable = FindVariable(Word); + } + } + } + + else { + error("Evaluator: syntax error in <%s>: <%s>", Expression, Word); + Root = NewNode(NULL); + Root->Token = T_STRING; + SetResult(&Root->Result, R_STRING, ""); + } + + Parse(); + return Root; + +} + + +/* unary + or - signs or logical 'not' */ +static NODE *Level11(void) +{ + NODE *Root; + TOKEN sign = T_UNDEF; + + if (Token == T_OPERATOR && (Operator == O_ADD || Operator == O_SUB || Operator == O_NOT)) { + sign = Operator; + if (sign == O_SUB) + sign = O_SGN; + Parse(); + } + + Root = Level12(); + + if (sign == O_SGN || sign == O_NOT) { + Root = NewNode(Root); + Root->Token = T_OPERATOR; + Root->Operator = sign; + } + + return Root; +} + + +/* x^y */ +static NODE *Level10(void) +{ + NODE *Root; + + Root = Level11(); + + while (Token == T_OPERATOR && Operator == O_POW) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level11()); + } + + return Root; +} + + +/* multiplication, division, modulo */ +static NODE *Level09(void) +{ + NODE *Root; + + Root = Level10(); + + while (Token == T_OPERATOR && (Operator == O_MUL || Operator == O_DIV || Operator == O_MOD)) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level10()); + } + + return Root; +} + + +/* addition, subtraction, string concatenation */ +static NODE *Level08(void) +{ + NODE *Root; + + Root = Level09(); + + while (Token == T_OPERATOR && (Operator == O_ADD || Operator == O_SUB || Operator == O_CAT)) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level09()); + } + + return Root; +} + + +/* relational operators */ +static NODE *Level07(void) +{ + NODE *Root; + + Root = Level08(); + + while (Token == T_OPERATOR && (Operator == O_NGT || Operator == O_NGE || Operator == O_NLT || Operator == O_NLE || + Operator == O_SGT || Operator == O_SGE || Operator == O_SLT || Operator == O_SLE)) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level08()); + } + + return Root; +} + + +/* equal, not equal */ +static NODE *Level06(void) +{ + NODE *Root; + + Root = Level07(); + + while (Token == T_OPERATOR && (Operator == O_NEQ || Operator == O_NNE || Operator == O_SEQ || Operator == O_SNE)) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level07()); + } + + return Root; +} + +/* logical 'and' */ +static NODE *Level05(void) +{ + NODE *Root; + + Root = Level06(); + + while (Token == T_OPERATOR && Operator == O_AND) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level06()); + } + + return Root; +} + + +/* logical 'or' */ +static NODE *Level04(void) +{ + NODE *Root; + + Root = Level05(); + + while (Token == T_OPERATOR && Operator == O_OR) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level05()); + } + + return Root; +} + + +/* conditional expression a?b:c */ +static NODE *Level03(void) +{ + NODE *Root; + + Root = Level04(); + + if (Token == T_OPERATOR && Operator == O_CND) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level04()); + if (Token == T_OPERATOR && Operator == O_COL) { + Parse(); + LinkNode(Root, Level04()); + } else { + error("Evaluator: syntax error in <%s>: expecting ':' got '%s'", Expression, Word); + LinkNode(Root, JunkNode()); + } + } + + return Root; +} + + +/* variable assignments */ +static NODE *Level02(void) +{ + NODE *Root; + + /* we have to do a look-ahead if it's really an assignment */ + if ((Token == T_NAME) && (*ExprPtr == '=') && (*(ExprPtr + 1) != '=')) { + char *name = strdup(Word); + VARIABLE *V = FindVariable(name); + if (V == NULL) { + SetVariableString(name, ""); + V = FindVariable(name); + } + Parse(); + Root = NewNode(NULL); + Root->Variable = V; + Parse(); + LinkNode(Root, Level03()); + free(name); + } else { + Root = Level03(); + } + + return Root; +} + + +/* expression lists */ +static NODE *Level01(void) +{ + NODE *Root; + + Root = Level02(); + + while (Token == T_OPERATOR && Operator == O_LST) { + Root = NewNode(Root); + Parse(); + LinkNode(Root, Level02()); + } + + return Root; +} + + +static int EvalTree(NODE * Root) +{ + int i; + int argc; + int type = -1; + double number = 0.0; + double dummy; + int freeme = 0; + char *string = NULL; + char *s1, *s2; + RESULT *param[10]; + + switch (Root->Token) { + + case T_NUMBER: + case T_STRING: + /* Root->Result already contains the value */ + return 0; + + case T_VARIABLE: + CopyResult(&Root->Result, Root->Variable->value); + return 0; + + case T_FUNCTION: + DelResult(Root->Result); + /* prepare parameter list */ + argc = Root->Children; + if (argc > 10) { + error("evaluator: more than 10 children (operands) not supported!"); + argc = 10; + } + for (i = 0; i < argc; i++) { + EvalTree(Root->Child[i]); + param[i] = Root->Child[i]->Result; + } + if (Root->Function->argc < 0) { + /* Function with variable argument list: */ + /* pass number of arguments as first parameter */ + Root->Function->func(Root->Result, argc, ¶m); + } else { + Root->Function->func(Root->Result, param[0], param[1], param[2], param[3], param[4], param[5], param[6], + param[7], param[8], param[9]); + } + return 0; + + case T_OPERATOR: + switch (Root->Operator) { + + case O_LST: /* expression list: result is last expression */ + for (i = 0; i < Root->Children; i++) { + EvalTree(Root->Child[i]); + } + i = Root->Children - 1; + type = Root->Child[i]->Result->type; + number = Root->Child[i]->Result->number; + string = Root->Child[i]->Result->string; + break; + + case O_SET: /* variable assignment */ + EvalTree(Root->Child[0]); + CopyResult(&Root->Variable->value, Root->Child[0]->Result); + type = Root->Child[0]->Result->type; + number = Root->Child[0]->Result->number; + string = Root->Child[0]->Result->string; + break; + + case O_CND: /* conditional expression */ + EvalTree(Root->Child[0]); + i = 1 + (R2N(Root->Child[0]->Result) == 0.0); + EvalTree(Root->Child[i]); + type = Root->Child[i]->Result->type; + number = Root->Child[i]->Result->number; + string = Root->Child[i]->Result->string; + break; + + case O_OR: /* logical OR */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + if (R2N(Root->Child[0]->Result) == 0.0) { + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[1]->Result) != 0.0); + } else { + number = 1.0; + } + break; + + case O_AND: /* logical AND */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + if (R2N(Root->Child[0]->Result) != 0.0) { + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[1]->Result) != 0.0); + } else { + number = 0.0; + } + break; + + case O_NEQ: /* numeric equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) == R2N(Root->Child[1]->Result)); + break; + + case O_NNE: /* numeric not equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) != R2N(Root->Child[1]->Result)); + break; + + case O_NLT: /* numeric less than */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) < R2N(Root->Child[1]->Result)); + break; + + case O_NLE: /* numeric less equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) <= R2N(Root->Child[1]->Result)); + break; + + case O_NGT: /* numeric greater than */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) > R2N(Root->Child[1]->Result)); + break; + + case O_NGE: /* numeric greater equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (R2N(Root->Child[0]->Result) >= R2N(Root->Child[1]->Result)); + break; + + case O_SEQ: /* string equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) == 0); + break; + + case O_SNE: /* string not equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) != 0); + break; + + case O_SLT: /* string less than */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) < 0); + break; + + case O_SLE: /* string less equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) <= 0); + break; + + case O_SGT: /* string greater than */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) > 0); + break; + + case O_SGE: /* string greater equal */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = (strcmp(R2S(Root->Child[0]->Result), R2S(Root->Child[1]->Result)) >= 0); + break; + + case O_ADD: /* addition */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = R2N(Root->Child[0]->Result) + R2N(Root->Child[1]->Result); + break; + + case O_SUB: /* subtraction */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = R2N(Root->Child[0]->Result) - R2N(Root->Child[1]->Result); + break; + + case O_SGN: /* sign */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + number = -R2N(Root->Child[0]->Result); + break; + + case O_CAT: /* string concatenation */ + type = R_STRING; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + s1 = R2S(Root->Child[0]->Result); + s2 = R2S(Root->Child[1]->Result); + string = malloc(strlen(s1) + strlen(s2) + 1); + strcpy(string, s1); + strcat(string, s2); + freeme = 1; + break; + + case O_MUL: /* multiplication */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = R2N(Root->Child[0]->Result) * R2N(Root->Child[1]->Result); + break; + + case O_DIV: /* division */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + dummy = R2N(Root->Child[1]->Result); + if (dummy == 0) { + error("Evaluator: warning: division by zero"); + number = 0.0; + } else { + number = R2N(Root->Child[0]->Result) / R2N(Root->Child[1]->Result); + } + break; + + case O_MOD: /* modulo */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + dummy = R2N(Root->Child[1]->Result); + if (dummy == 0) { + error("Evaluator: warning: division by zero"); + number = 0.0; + } else { + number = fmod(R2N(Root->Child[0]->Result), R2N(Root->Child[1]->Result)); + } + break; + + case O_POW: /* x^y */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + EvalTree(Root->Child[1]); + number = pow(R2N(Root->Child[0]->Result), R2N(Root->Child[1]->Result)); + break; + + case O_NOT: /* logical NOT */ + type = R_NUMBER; + EvalTree(Root->Child[0]); + number = (R2N(Root->Child[0]->Result) == 0.0); + break; + + default: + error("Evaluator: internal error: unhandled operator <%d>", Root->Operator); + SetResult(&Root->Result, R_STRING, ""); + return -1; + } + + if (type == R_NUMBER) { + SetResult(&Root->Result, R_NUMBER, &number); + return 0; + } + if (type == R_STRING) { + SetResult(&Root->Result, R_STRING, string); + if (freeme) + free(string); + return 0; + } + error("Evaluator: internal error: unhandled type <%d>", type); + SetResult(&Root->Result, R_STRING, ""); + return -1; + + default: + error("Evaluator: internal error: unhandled token <%d>", Root->Token); + SetResult(&Root->Result, R_STRING, ""); + return -1; + + } + + return 0; +} + + +int Compile(const char *expression, void **tree) +{ + NODE *Root; + + *tree = NULL; + + Expression = (char *) expression; + ExprPtr = Expression; + + Parse(); + if (*Word == '\0') { + /* error ("Evaluator: empty expression <%s>", Expression); */ + free(Word); + Word = NULL; + return -1; + } + + Root = Level01(); + + if (*Word != '\0') { + error("Evaluator: syntax error in <%s>: garbage <%s>", Expression, Word); + free(Word); + Word = NULL; + return -1; + } + + free(Word); + Word = NULL; + + *(NODE **) tree = Root; + + return 0; +} + + +int Eval(void *tree, RESULT * result) +{ + int ret; + NODE *Tree = (NODE *) tree; + + DelResult(result); + + if (Tree == NULL) { + SetResult(&result, R_STRING, ""); + return 0; + } + + ret = EvalTree(Tree); + + result->type = Tree->Result->type; + result->size = Tree->Result->size; + result->number = Tree->Result->number; + if (result->size > 0) { + result->string = malloc(result->size); + if (Tree->Result->string != NULL) { + strcpy(result->string, Tree->Result->string); + } else + result->string[0] = '\0'; + } else { + result->string = NULL; + } + + return ret; +} + + +void DelTree(void *tree) +{ + int i; + NODE *Tree = (NODE *) tree; + + if (Tree == NULL) + return; + + for (i = 0; i < Tree->Children; i++) { + DelTree(Tree->Child[i]); + } + + if (Tree->Result) + FreeResult(Tree->Result); + free(Tree); +} -- cgit v1.2.3