aboutsummaryrefslogtreecommitdiffstats
path: root/evaluator.c
diff options
context:
space:
mode:
Diffstat (limited to 'evaluator.c')
-rw-r--r--evaluator.c291
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;