/** * expr_lookup - return the expression with the given type and sub-nodes * This looks up an expression with the specified type and sub-nodes. If such * an expression is found in the hash table, it is returned. Otherwise, a new * expression node is allocated and added to the hash table. * @type: expression type * @l: left node * @r: right node * return: expression
*/ staticstruct expr *expr_lookup(enum expr_type type, void *l, void *r)
{ struct expr *e; int hash;
/* * expr_eliminate_eq() helper. * * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared * against all other leaves. Two equal leaves are both replaced with either 'y' * or 'n' as appropriate for 'type', to be eliminated later.
*/ staticvoid __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
{ struct expr *l, *r;
/* Recurse down to leaves */
if ((*ep1)->type == type) {
l = (*ep1)->left.expr;
r = (*ep1)->right.expr;
__expr_eliminate_eq(type, &l, ep2);
__expr_eliminate_eq(type, &r, ep2);
*ep1 = expr_alloc_two(type, l, r); return;
} if ((*ep2)->type == type) {
l = (*ep2)->left.expr;
r = (*ep2)->right.expr;
__expr_eliminate_eq(type, ep1, &l);
__expr_eliminate_eq(type, ep1, &r);
*ep2 = expr_alloc_two(type, l, r); return;
}
/* * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both. * Example reductions: * * ep1: A && B -> ep1: y * ep2: A && B && C -> ep2: C * * ep1: A || B -> ep1: n * ep2: A || B || C -> ep2: C * * ep1: A && (B && FOO) -> ep1: FOO * ep2: (BAR && B) && A -> ep2: BAR * * ep1: A && (B || C) -> ep1: y * ep2: (C || B) && A -> ep2: y * * Comparisons are done between all operands at the same "level" of && or ||. * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the * following operands will be compared: * * - 'e1', 'e2 || e3', and 'e4 || e5', against each other * - e2 against e3 * - e4 against e5 * * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and * '(e1 && e2) && e3' are both a single level. * * See __expr_eliminate_eq() as well.
*/ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{ if (!*ep1 || !*ep2) return; switch ((*ep1)->type) { case E_OR: case E_AND:
__expr_eliminate_eq((*ep1)->type, ep1, ep2); default:
;
} if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) { case E_OR: case E_AND:
__expr_eliminate_eq((*ep2)->type, ep1, ep2); default:
;
}
*ep1 = expr_eliminate_yn(*ep1);
*ep2 = expr_eliminate_yn(*ep2);
}
/* * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two * &&/|| expressions are considered equal if every operand in one expression * equals some operand in the other (operands do not need to appear in the same * order), recursively.
*/ bool expr_eq(struct expr *e1, struct expr *e2)
{ int old_count; bool res;
/* * A NULL expr is taken to be yes, but there's also a different way to * represent yes. expr_is_yes() checks for either representation.
*/ if (!e1 || !e2) return expr_is_yes(e1) && expr_is_yes(e2);
if (e1->type != e2->type) returnfalse; 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: return e1->left.sym == e2->left.sym; case E_NOT: return expr_eq(e1->left.expr, e2->left.expr); case E_AND: case E_OR:
old_count = trans_count;
expr_eliminate_eq(&e1, &e2);
res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
e1->left.sym == e2->left.sym);
trans_count = old_count; return res; case E_RANGE: case E_NONE: /* panic */;
}
/* * Recursively performs the following simplifications (as well as the * corresponding simplifications with swapped operands): * * expr && n -> n * expr && y -> expr * expr || n -> expr * expr || y -> y * * Returns the optimized expression.
*/ staticstruct expr *expr_eliminate_yn(struct expr *e)
{ struct expr *l, *r;
if (e) switch (e->type) { case E_AND:
l = expr_eliminate_yn(e->left.expr);
r = expr_eliminate_yn(e->right.expr); if (l->type == E_SYMBOL) { if (l->left.sym == &symbol_no) return l; elseif (l->left.sym == &symbol_yes) return r;
} if (r->type == E_SYMBOL) { if (r->left.sym == &symbol_no) return r; elseif (r->left.sym == &symbol_yes) return l;
} break; case E_OR:
l = expr_eliminate_yn(e->left.expr);
r = expr_eliminate_yn(e->right.expr); if (l->type == E_SYMBOL) { if (l->left.sym == &symbol_no) return r; elseif (l->left.sym == &symbol_yes) return l;
} if (r->type == E_SYMBOL) { if (r->left.sym == &symbol_no) return l; elseif (r->left.sym == &symbol_yes) return r;
} break; default:
;
} return e;
}
/* * expr_eliminate_dups() helper. * * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared * against all other leaves to look for simplifications.
*/ staticvoid expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
{ struct expr *tmp, *l, *r;
/* Recurse down to leaves */
if ((*ep1)->type == type) {
l = (*ep1)->left.expr;
r = (*ep1)->right.expr;
expr_eliminate_dups1(type, &l, ep2);
expr_eliminate_dups1(type, &r, ep2);
*ep1 = expr_alloc_two(type, l, r); return;
} if ((*ep2)->type == type) {
l = (*ep2)->left.expr;
r = (*ep2)->right.expr;
expr_eliminate_dups1(type, ep1, &l);
expr_eliminate_dups1(type, ep1, &r);
*ep2 = expr_alloc_two(type, l, r); return;
}
/* *ep1 and *ep2 are leaves. Compare and process them. */
/* * Rewrites 'e' in-place to remove ("join") duplicate and other redundant * operands. * * Example simplifications: * * A || B || A -> A || B * A && B && A=y -> A=y && B * * Returns the deduplicated expression.
*/ struct expr *expr_eliminate_dups(struct expr *e)
{ int oldcount; if (!e) return e;
oldcount = trans_count; do { struct expr *l, *r;
trans_count = 0; switch (e->type) { case E_OR: case E_AND:
l = expr_eliminate_dups(e->left.expr);
r = expr_eliminate_dups(e->right.expr);
expr_eliminate_dups1(e->type, &l, &r);
e = expr_alloc_two(e->type, l, r); default:
;
}
e = expr_eliminate_yn(e);
} while (trans_count); /* repeat until we get no more simplifications */
trans_count = oldcount; return e;
}
/* * Performs various simplifications involving logical operators and * comparisons. * * For bool type: * A=n -> !A * A=m -> n * A=y -> A * A!=n -> A * A!=m -> y * A!=y -> !A * * For any type: * !!A -> A * !(A=B) -> A!=B * !(A!=B) -> A=B * !(A<=B) -> A>B * !(A>=B) -> A<B * !(A<B) -> A>=B * !(A>B) -> A<=B * !(A || B) -> !A && !B * !(A && B) -> !A || !B * * For constant: * !y -> n * !m -> m * !n -> y * * Allocates and returns a new expression.
*/ struct expr *expr_transform(struct expr *e)
{ if (!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: break; default:
e = expr_alloc_two(e->type,
expr_transform(e->left.expr),
expr_transform(e->right.expr));
}
switch (e->type) { case E_EQUAL: if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { // A=n -> !A
e = expr_alloc_one(E_NOT, expr_alloc_symbol(e->left.sym)); break;
} if (e->right.sym == &symbol_mod) { // A=m -> n
printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
e = expr_alloc_symbol(&symbol_no); break;
} if (e->right.sym == &symbol_yes) { // A=y -> A
e = expr_alloc_symbol(e->left.sym); break;
} break; case E_UNEQUAL: if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { // A!=n -> A
e = expr_alloc_symbol(e->left.sym); break;
} if (e->right.sym == &symbol_mod) { // A!=m -> y
printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
e = expr_alloc_symbol(&symbol_yes); break;
} if (e->right.sym == &symbol_yes) { // A!=y -> !A
e = expr_alloc_one(E_NOT, e->left.expr); break;
} break; case E_NOT: switch (e->left.expr->type) { case E_NOT: // !!A -> A
e = e->left.expr->left.expr; break; case E_EQUAL: case E_UNEQUAL: // !(A=B) -> A!=B
e = expr_alloc_comp(e->left.expr->type == E_EQUAL ? E_UNEQUAL : E_EQUAL,
e->left.expr->left.sym,
e->left.expr->right.sym); break; case E_LEQ: case E_GEQ: // !(A<=B) -> A>B
e = expr_alloc_comp(e->left.expr->type == E_LEQ ? E_GTH : E_LTH,
e->left.expr->left.sym,
e->left.expr->right.sym); break; case E_LTH: case E_GTH: // !(A<B) -> A>=B
e = expr_alloc_comp(e->left.expr->type == E_LTH ? E_GEQ : E_LEQ,
e->left.expr->left.sym,
e->left.expr->right.sym); break; case E_OR: // !(A || B) -> !A && !B
e = expr_alloc_and(expr_alloc_one(E_NOT, e->left.expr->left.expr),
expr_alloc_one(E_NOT, e->left.expr->right.expr));
e = expr_transform(e); break; case E_AND: // !(A && B) -> !A || !B
e = expr_alloc_or(expr_alloc_one(E_NOT, e->left.expr->left.expr),
expr_alloc_one(E_NOT, e->left.expr->right.expr));
e = expr_transform(e); break; case E_SYMBOL: if (e->left.expr->left.sym == &symbol_yes) // !'y' -> 'n'
e = expr_alloc_symbol(&symbol_no); elseif (e->left.expr->left.sym == &symbol_mod) // !'m' -> 'm'
e = expr_alloc_symbol(&symbol_mod); elseif (e->left.expr->left.sym == &symbol_no) // !'n' -> 'y'
e = expr_alloc_symbol(&symbol_yes); break; default:
;
} break; default:
;
} return e;
}
bool expr_contains_symbol(struct expr *dep, struct symbol *sym)
{ if (!dep) returnfalse;
switch (dep->type) { case E_AND: case E_OR: return expr_contains_symbol(dep->left.expr, sym) ||
expr_contains_symbol(dep->right.expr, 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; case E_NOT: return expr_contains_symbol(dep->left.expr, sym); default:
;
} returnfalse;
}
bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
{ if (!dep) returnfalse;
switch (dep->type) { case E_AND: return expr_depends_symbol(dep->left.expr, sym) ||
expr_depends_symbol(dep->right.expr, sym); case E_SYMBOL: return dep->left.sym == sym; case E_EQUAL: if (dep->left.sym == sym) { if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) returntrue;
} break; case E_UNEQUAL: if (dep->left.sym == sym) { if (dep->right.sym == &symbol_no) returntrue;
} break; default:
;
} returnfalse;
}
/* * Inserts explicit comparisons of type 'type' to symbol 'sym' into the * expression 'e'. * * Examples transformations for type == E_UNEQUAL, sym == &symbol_no: * * A -> A!=n * !A -> A=n * A && B -> !(A=n || B=n) * A || B -> !(A=n && B=n) * A && (B || C) -> !(A=n || (B=n && C=n)) * * Allocates and returns a new expression.
*/ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
{ struct expr *e1, *e2;
if (!e) {
e = expr_alloc_symbol(sym); if (type == E_UNEQUAL)
e = expr_alloc_one(E_NOT, e); return e;
} switch (e->type) { case E_AND:
e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); if (sym == &symbol_yes)
e = expr_alloc_two(E_AND, e1, e2); if (sym == &symbol_no)
e = expr_alloc_two(E_OR, e1, e2); if (type == E_UNEQUAL)
e = expr_alloc_one(E_NOT, e); return e; case E_OR:
e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); if (sym == &symbol_yes)
e = expr_alloc_two(E_OR, e1, e2); if (sym == &symbol_no)
e = expr_alloc_two(E_AND, e1, e2); if (type == E_UNEQUAL)
e = expr_alloc_one(E_NOT, e); return e; 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) return e; if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_no); if (sym == &symbol_no) return expr_alloc_one(E_NOT, e);
} else { if (sym == &symbol_yes) return expr_alloc_one(E_NOT, e); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_yes); if (sym == &symbol_no) return e;
} break; case E_SYMBOL: return expr_alloc_comp(type, e->left.sym, sym); case E_RANGE: case E_NONE: /* panic */;
} return NULL;
}
if (k1 == k_string || k2 == k_string)
res = strcmp(str1, str2); elseif (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;
}
}
/** * expr_calc_value - return the tristate value of the given expression * @e: expression * return: tristate value of the expression
*/
tristate expr_calc_value(struct expr *e)
{ if (!e) return yes;
if (!e->val_is_valid) {
e->val = __expr_calc_value(e);
e->val_is_valid = true;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.