|
@@ -79,6 +79,10 @@ struct expr *expr_copy(const struct expr *org)
|
|
|
e->left.expr = expr_copy(org->left.expr);
|
|
|
break;
|
|
|
case E_EQUAL:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
e->left.sym = org->left.sym;
|
|
|
e->right.sym = org->right.sym;
|
|
@@ -111,6 +115,10 @@ void expr_free(struct expr *e)
|
|
|
expr_free(e->left.expr);
|
|
|
return;
|
|
|
case E_EQUAL:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
break;
|
|
|
case E_OR:
|
|
@@ -197,6 +205,10 @@ static int expr_eq(struct expr *e1, struct expr *e2)
|
|
|
return 0;
|
|
|
switch (e1->type) {
|
|
|
case E_EQUAL:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
|
|
|
case E_SYMBOL:
|
|
@@ -587,6 +599,10 @@ struct expr *expr_transform(struct expr *e)
|
|
|
return NULL;
|
|
|
switch (e->type) {
|
|
|
case E_EQUAL:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
case E_SYMBOL:
|
|
|
case E_LIST:
|
|
@@ -659,6 +675,22 @@ struct expr *expr_transform(struct expr *e)
|
|
|
e = tmp;
|
|
|
e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
|
|
|
break;
|
|
|
+ case E_LEQ:
|
|
|
+ case E_GEQ:
|
|
|
+ // !a<='x' -> a>'x'
|
|
|
+ tmp = e->left.expr;
|
|
|
+ free(e);
|
|
|
+ e = tmp;
|
|
|
+ e->type = e->type == E_LEQ ? E_GTH : E_LTH;
|
|
|
+ break;
|
|
|
+ case E_LTH:
|
|
|
+ case E_GTH:
|
|
|
+ // !a<'x' -> a>='x'
|
|
|
+ tmp = e->left.expr;
|
|
|
+ free(e);
|
|
|
+ e = tmp;
|
|
|
+ e->type = e->type == E_LTH ? E_GEQ : E_LEQ;
|
|
|
+ break;
|
|
|
case E_OR:
|
|
|
// !(a || b) -> !a && !b
|
|
|
tmp = e->left.expr;
|
|
@@ -729,6 +761,10 @@ int expr_contains_symbol(struct expr *dep, struct symbol *sym)
|
|
|
case E_SYMBOL:
|
|
|
return dep->left.sym == sym;
|
|
|
case E_EQUAL:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
return dep->left.sym == sym ||
|
|
|
dep->right.sym == sym;
|
|
@@ -803,6 +839,10 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
|
|
|
case E_NOT:
|
|
|
return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
|
|
|
case E_UNEQUAL:
|
|
|
+ case E_LTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_GEQ:
|
|
|
case E_EQUAL:
|
|
|
if (type == E_EQUAL) {
|
|
|
if (sym == &symbol_yes)
|
|
@@ -830,10 +870,57 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+enum string_value_kind {
|
|
|
+ k_string,
|
|
|
+ k_signed,
|
|
|
+ k_unsigned,
|
|
|
+ k_invalid
|
|
|
+};
|
|
|
+
|
|
|
+union string_value {
|
|
|
+ unsigned long long u;
|
|
|
+ signed long long s;
|
|
|
+};
|
|
|
+
|
|
|
+static enum string_value_kind expr_parse_string(const char *str,
|
|
|
+ enum symbol_type type,
|
|
|
+ union string_value *val)
|
|
|
+{
|
|
|
+ char *tail;
|
|
|
+ enum string_value_kind kind;
|
|
|
+
|
|
|
+ errno = 0;
|
|
|
+ switch (type) {
|
|
|
+ case S_BOOLEAN:
|
|
|
+ case S_TRISTATE:
|
|
|
+ return k_string;
|
|
|
+ case S_INT:
|
|
|
+ val->s = strtoll(str, &tail, 10);
|
|
|
+ kind = k_signed;
|
|
|
+ break;
|
|
|
+ case S_HEX:
|
|
|
+ val->u = strtoull(str, &tail, 16);
|
|
|
+ kind = k_unsigned;
|
|
|
+ break;
|
|
|
+ case S_STRING:
|
|
|
+ case S_UNKNOWN:
|
|
|
+ val->s = strtoll(str, &tail, 0);
|
|
|
+ kind = k_signed;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return k_invalid;
|
|
|
+ }
|
|
|
+ return !errno && !*tail && tail > str && isxdigit(tail[-1])
|
|
|
+ ? kind : k_string;
|
|
|
+}
|
|
|
+
|
|
|
tristate expr_calc_value(struct expr *e)
|
|
|
{
|
|
|
tristate val1, val2;
|
|
|
const char *str1, *str2;
|
|
|
+ enum string_value_kind k1 = k_string, k2 = k_string;
|
|
|
+ union string_value lval = {}, rval = {};
|
|
|
+ int res;
|
|
|
|
|
|
if (!e)
|
|
|
return yes;
|
|
@@ -854,21 +941,57 @@ tristate expr_calc_value(struct expr *e)
|
|
|
val1 = expr_calc_value(e->left.expr);
|
|
|
return EXPR_NOT(val1);
|
|
|
case E_EQUAL:
|
|
|
- sym_calc_value(e->left.sym);
|
|
|
- sym_calc_value(e->right.sym);
|
|
|
- str1 = sym_get_string_value(e->left.sym);
|
|
|
- str2 = sym_get_string_value(e->right.sym);
|
|
|
- return !strcmp(str1, str2) ? yes : no;
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
case E_UNEQUAL:
|
|
|
- sym_calc_value(e->left.sym);
|
|
|
- sym_calc_value(e->right.sym);
|
|
|
- str1 = sym_get_string_value(e->left.sym);
|
|
|
- str2 = sym_get_string_value(e->right.sym);
|
|
|
- return !strcmp(str1, str2) ? no : yes;
|
|
|
+ break;
|
|
|
default:
|
|
|
printf("expr_calc_value: %d?\n", e->type);
|
|
|
return no;
|
|
|
}
|
|
|
+
|
|
|
+ sym_calc_value(e->left.sym);
|
|
|
+ sym_calc_value(e->right.sym);
|
|
|
+ str1 = sym_get_string_value(e->left.sym);
|
|
|
+ str2 = sym_get_string_value(e->right.sym);
|
|
|
+
|
|
|
+ if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
|
|
|
+ k1 = expr_parse_string(str1, e->left.sym->type, &lval);
|
|
|
+ k2 = expr_parse_string(str2, e->right.sym->type, &rval);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (k1 == k_string || k2 == k_string)
|
|
|
+ res = strcmp(str1, str2);
|
|
|
+ else if (k1 == k_invalid || k2 == k_invalid) {
|
|
|
+ if (e->type != E_EQUAL && e->type != E_UNEQUAL) {
|
|
|
+ printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2);
|
|
|
+ return no;
|
|
|
+ }
|
|
|
+ res = strcmp(str1, str2);
|
|
|
+ } else if (k1 == k_unsigned || k2 == k_unsigned)
|
|
|
+ res = (lval.u > rval.u) - (lval.u < rval.u);
|
|
|
+ else /* if (k1 == k_signed && k2 == k_signed) */
|
|
|
+ res = (lval.s > rval.s) - (lval.s < rval.s);
|
|
|
+
|
|
|
+ switch(e->type) {
|
|
|
+ case E_EQUAL:
|
|
|
+ return res ? no : yes;
|
|
|
+ case E_GEQ:
|
|
|
+ return res >= 0 ? yes : no;
|
|
|
+ case E_GTH:
|
|
|
+ return res > 0 ? yes : no;
|
|
|
+ case E_LEQ:
|
|
|
+ return res <= 0 ? yes : no;
|
|
|
+ case E_LTH:
|
|
|
+ return res < 0 ? yes : no;
|
|
|
+ case E_UNEQUAL:
|
|
|
+ return res ? yes : no;
|
|
|
+ default:
|
|
|
+ printf("expr_calc_value: relation %d?\n", e->type);
|
|
|
+ return no;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static int expr_compare_type(enum expr_type t1, enum expr_type t2)
|
|
@@ -876,6 +999,12 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
|
|
|
if (t1 == t2)
|
|
|
return 0;
|
|
|
switch (t1) {
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ if (t2 == E_EQUAL || t2 == E_UNEQUAL)
|
|
|
+ return 1;
|
|
|
case E_EQUAL:
|
|
|
case E_UNEQUAL:
|
|
|
if (t2 == E_NOT)
|
|
@@ -969,6 +1098,24 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
|
|
|
fn(data, NULL, "=");
|
|
|
fn(data, e->right.sym, e->right.sym->name);
|
|
|
break;
|
|
|
+ case E_LEQ:
|
|
|
+ case E_LTH:
|
|
|
+ if (e->left.sym->name)
|
|
|
+ fn(data, e->left.sym, e->left.sym->name);
|
|
|
+ else
|
|
|
+ fn(data, NULL, "<choice>");
|
|
|
+ fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
|
|
|
+ fn(data, e->right.sym, e->right.sym->name);
|
|
|
+ break;
|
|
|
+ case E_GEQ:
|
|
|
+ case E_GTH:
|
|
|
+ if (e->left.sym->name)
|
|
|
+ fn(data, e->left.sym, e->left.sym->name);
|
|
|
+ else
|
|
|
+ fn(data, NULL, "<choice>");
|
|
|
+ fn(data, NULL, e->type == E_LEQ ? ">=" : ">");
|
|
|
+ fn(data, e->right.sym, e->right.sym->name);
|
|
|
+ break;
|
|
|
case E_UNEQUAL:
|
|
|
if (e->left.sym->name)
|
|
|
fn(data, e->left.sym, e->left.sym->name);
|