diff options
Diffstat (limited to 'evaluator.c')
-rw-r--r-- | evaluator.c | 291 |
1 files changed, 249 insertions, 42 deletions
diff --git a/evaluator.c b/evaluator.c index f297491..f5f8b06 100644 --- a/evaluator.c +++ b/evaluator.c @@ -1,9 +1,9 @@ -/* $Id: evaluator.c 754 2007-01-21 06:19:40Z michael $ - * $URL: https://ssl.bulix.org/svn/lcd4linux/branches/0.10.1/evaluator.c $ +/* $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 <reinelt@eunet.at> + * Copyright (C) 1999, 2000 Michael Reinelt <michael@reinelt.co.at> * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> * * This file is part of LCD4Linux. @@ -108,12 +108,18 @@ typedef enum { O_COL, /* colon in a?b:c */ O_OR, /* logical OR */ O_AND, /* logical AND */ - O_EQ, /* equal */ - O_NE, /* not equal */ - O_LT, /* less than */ - O_LE, /* less or equal */ - O_GT, /* greater than */ - O_GE, /* greater or equal */ + 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 '-' */ @@ -157,17 +163,17 @@ typedef struct _NODE { -/* operators */ +/* non-alphanumeric operators */ /* IMPORTANT! list must be sorted by length! */ -static PATTERN Pattern[] = { +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_LT}, /* less than */ - {">", 1, O_GT}, /* greater than */ + {"<", 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 */ @@ -179,10 +185,21 @@ static PATTERN Pattern[] = { {"(", 1, O_BRO}, /* open brace */ {",", 1, O_COM}, /* comma (argument seperator) */ {")", 1, O_BRC}, /* closing brace */ - {"==", 2, O_EQ}, /* equal */ - {"!=", 2, O_NE}, /* not equal */ - {"<=", 2, O_LE}, /* less or equal */ - {">=", 2, O_GE} /* greater or equal */ + {"==", 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 */ }; @@ -199,6 +216,30 @@ 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; @@ -511,6 +552,7 @@ static void Parse(void) /* names */ if (is_alpha(*ExprPtr)) { + int i; char *start = ExprPtr; while (is_alnum(*ExprPtr)) ExprPtr++; @@ -521,6 +563,16 @@ static void Parse(void) } 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 */ @@ -539,24 +591,91 @@ static void Parse(void) /* strings */ else if (*ExprPtr == '\'') { - char *start = ++ExprPtr; - while (*ExprPtr != '\0' && *ExprPtr != '\'') - ExprPtr++; - Word = strndup(start, ExprPtr - start); + 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 == '\'') + if (*ExprPtr == '\'') { ExprPtr++; + } else { + error("Evaluator: unterminated string in <%s>", Expression); + } } - /* operators */ + /* non-alpha operators */ else { int i; - for (i = sizeof(Pattern) / sizeof(Pattern[0]) - 1; i >= 0; i--) { - int len = Pattern[i].len; - if (strncmp(ExprPtr, Pattern[i].pattern, Pattern[i].len) == 0) { + 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 = Pattern[i].op; + Operator = Pattern1[i].op; ExprPtr += len; break; } @@ -808,7 +927,8 @@ static NODE *Level07(void) Root = Level08(); - while (Token == T_OPERATOR && (Operator == O_GT || Operator == O_GE || Operator == O_LT || Operator == O_LE)) { + 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()); @@ -825,7 +945,7 @@ static NODE *Level06(void) Root = Level07(); - while (Token == T_OPERATOR && (Operator == O_EQ || Operator == O_NE)) { + while (Token == T_OPERATOR && (Operator == O_NEQ || Operator == O_NNE || Operator == O_SEQ || Operator == O_SNE)) { Root = NewNode(Root); Parse(); LinkNode(Root, Level07()); @@ -948,10 +1068,6 @@ static int EvalTree(NODE * Root) char *s1, *s2; RESULT *param[10]; - for (i = 0; i < Root->Children; i++) { - EvalTree(Root->Child[i]); - } - switch (Root->Token) { case T_NUMBER: @@ -967,9 +1083,12 @@ static int EvalTree(NODE * Root) DelResult(Root->Result); /* prepare parameter list */ argc = Root->Children; - if (argc > 10) + 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) { @@ -986,6 +1105,9 @@ static int EvalTree(NODE * Root) 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; @@ -993,6 +1115,7 @@ static int EvalTree(NODE * Root) 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; @@ -1000,7 +1123,9 @@ static int EvalTree(NODE * Root) 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; @@ -1008,61 +1133,134 @@ static int EvalTree(NODE * Root) case O_OR: /* logical OR */ type = R_NUMBER; - number = ((R2N(Root->Child[0]->Result) != 0.0) || (R2N(Root->Child[1]->Result) != 0.0)); + 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; - number = ((R2N(Root->Child[0]->Result) != 0.0) && (R2N(Root->Child[1]->Result) != 0.0)); + 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_EQ: /* numeric equal */ + 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_NE: /* numeric not equal */ + 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_LT: /* numeric less than */ + 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_LE: /* numeric less equal */ + 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_GT: /* numeric greater than */ + 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_GE: /* numeric greater equal */ + 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); @@ -1073,11 +1271,15 @@ static int EvalTree(NODE * Root) 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"); @@ -1089,6 +1291,8 @@ static int EvalTree(NODE * Root) 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"); @@ -1100,11 +1304,14 @@ static int EvalTree(NODE * Root) 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; |