📄 expr.c
字号:
if (tmp) { expr_free(e1); expr_free(e2); e1 = expr_alloc_symbol(&symbol_yes); e2 = tmp; trans_count++; } break; default: ; }#undef e1#undef e2}static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2){#define e1 (*ep1)#define e2 (*ep2) struct expr *tmp, *tmp1, *tmp2; if (e1->type == type) { expr_eliminate_dups2(type, &e1->left.expr, &e2); expr_eliminate_dups2(type, &e1->right.expr, &e2); return; } if (e2->type == type) { expr_eliminate_dups2(type, &e1, &e2->left.expr); expr_eliminate_dups2(type, &e1, &e2->right.expr); } if (e1 == e2) return; switch (e1->type) { case E_OR: expr_eliminate_dups2(e1->type, &e1, &e1); // (FOO || BAR) && (!FOO && !BAR) -> n tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); tmp2 = expr_copy(e2); tmp = expr_extract_eq_and(&tmp1, &tmp2); if (expr_is_yes(tmp1)) { expr_free(e1); e1 = expr_alloc_symbol(&symbol_no); trans_count++; } expr_free(tmp2); expr_free(tmp1); expr_free(tmp); break; case E_AND: expr_eliminate_dups2(e1->type, &e1, &e1); // (FOO && BAR) || (!FOO || !BAR) -> y tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); tmp2 = expr_copy(e2); tmp = expr_extract_eq_or(&tmp1, &tmp2); if (expr_is_no(tmp1)) { expr_free(e1); e1 = expr_alloc_symbol(&symbol_yes); trans_count++; } expr_free(tmp2); expr_free(tmp1); expr_free(tmp); break; default: ; }#undef e1#undef e2}struct expr *expr_eliminate_dups(struct expr *e){ int oldcount; if (!e) return e; oldcount = trans_count; while (1) { trans_count = 0; switch (e->type) { case E_OR: case E_AND: expr_eliminate_dups1(e->type, &e, &e); expr_eliminate_dups2(e->type, &e, &e); default: ; } if (!trans_count) break; e = expr_eliminate_yn(e); } trans_count = oldcount; return e;}struct expr *expr_transform(struct expr *e){ struct expr *tmp; if (!e) return NULL; switch (e->type) { case E_EQUAL: case E_UNEQUAL: case E_SYMBOL: case E_CHOICE: break; default: e->left.expr = expr_transform(e->left.expr); e->right.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) { e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_no; e->right.sym = NULL; break; } if (e->right.sym == &symbol_yes) { e->type = E_SYMBOL; e->right.sym = NULL; break; } break; case E_UNEQUAL: if (e->left.sym->type != S_BOOLEAN) break; if (e->right.sym == &symbol_no) { e->type = E_SYMBOL; e->right.sym = NULL; break; } if (e->right.sym == &symbol_mod) { printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); e->type = E_SYMBOL; e->left.sym = &symbol_yes; e->right.sym = NULL; break; } if (e->right.sym == &symbol_yes) { e->type = E_NOT; e->left.expr = expr_alloc_symbol(e->left.sym); e->right.sym = NULL; break; } break; case E_NOT: switch (e->left.expr->type) { case E_NOT: // !!a -> a tmp = e->left.expr->left.expr; free(e->left.expr); free(e); e = tmp; e = expr_transform(e); break; case E_EQUAL: case E_UNEQUAL: // !a='x' -> a!='x' tmp = e->left.expr; free(e); e = tmp; e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; break; case E_OR: // !(a || b) -> !a && !b tmp = e->left.expr; e->type = E_AND; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); tmp->type = E_NOT; tmp->right.expr = NULL; e = expr_transform(e); break; case E_AND: // !(a && b) -> !a || !b tmp = e->left.expr; e->type = E_OR; e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); tmp->type = E_NOT; tmp->right.expr = NULL; e = expr_transform(e); break; case E_SYMBOL: if (e->left.expr->left.sym == &symbol_yes) { // !'y' -> 'n' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_no; break; } if (e->left.expr->left.sym == &symbol_mod) { // !'m' -> 'm' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_mod; break; } if (e->left.expr->left.sym == &symbol_no) { // !'n' -> 'y' tmp = e->left.expr; free(e); e = tmp; e->type = E_SYMBOL; e->left.sym = &symbol_yes; break; } break; default: ; } break; default: ; } return e;}int expr_contains_symbol(struct expr *dep, struct symbol *sym){ if (!dep) return 0; 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_UNEQUAL: return dep->left.sym == sym || dep->right.sym == sym; case E_NOT: return expr_contains_symbol(dep->left.expr, sym); default: ; } return 0;}bool expr_depends_symbol(struct expr *dep, struct symbol *sym){ if (!dep) return false; 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) return true; } break; case E_UNEQUAL: if (dep->left.sym == sym) { if (dep->right.sym == &symbol_no) return true; } break; default: ; } return false;}struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2){ struct expr *tmp = NULL; expr_extract_eq(E_AND, &tmp, ep1, ep2); if (tmp) { *ep1 = expr_eliminate_yn(*ep1); *ep2 = expr_eliminate_yn(*ep2); } return tmp;}struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2){ struct expr *tmp = NULL; expr_extract_eq(E_OR, &tmp, ep1, ep2); if (tmp) { *ep1 = expr_eliminate_yn(*ep1); *ep2 = expr_eliminate_yn(*ep2); } return tmp;}void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2){#define e1 (*ep1)#define e2 (*ep2) if (e1->type == type) { expr_extract_eq(type, ep, &e1->left.expr, &e2); expr_extract_eq(type, ep, &e1->right.expr, &e2); return; } if (e2->type == type) { expr_extract_eq(type, ep, ep1, &e2->left.expr); expr_extract_eq(type, ep, ep1, &e2->right.expr); return; } if (expr_eq(e1, e2)) { *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; expr_free(e2); if (type == E_AND) { e1 = expr_alloc_symbol(&symbol_yes); e2 = expr_alloc_symbol(&symbol_yes); } else if (type == E_OR) { e1 = expr_alloc_symbol(&symbol_no); e2 = expr_alloc_symbol(&symbol_no); } }#undef e1#undef e2}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_EQUAL: if (type == E_EQUAL) { if (sym == &symbol_yes) return expr_copy(e); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_no); if (sym == &symbol_no) return expr_alloc_one(E_NOT, expr_copy(e)); } else { if (sym == &symbol_yes) return expr_alloc_one(E_NOT, expr_copy(e)); if (sym == &symbol_mod) return expr_alloc_symbol(&symbol_yes); if (sym == &symbol_no) return expr_copy(e); } break; case E_SYMBOL: return expr_alloc_comp(type, e->left.sym, sym); case E_CHOICE: case E_RANGE: case E_NONE: /* panic */; } return NULL;}tristate expr_calc_value(struct expr *e){ tristate val1, val2; const char *str1, *str2; if (!e) return yes; switch (e->type) { case E_SYMBOL: sym_calc_value(e->left.sym); return e->left.sym->curr.tri; case E_AND: val1 = expr_calc_value(e->left.expr); val2 = expr_calc_value(e->right.expr); return E_AND(val1, val2); case E_OR: val1 = expr_calc_value(e->left.expr); val2 = expr_calc_value(e->right.expr); return E_OR(val1, val2); case E_NOT: val1 = expr_calc_value(e->left.expr); return E_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_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; default: printf("expr_calc_value: %d?\n", e->type); return no; }}int expr_compare_type(enum expr_type t1, enum expr_type t2){#if 0 return 1;#else if (t1 == t2) return 0; switch (t1) { case E_EQUAL: case E_UNEQUAL: if (t2 == E_NOT) return 1; case E_NOT: if (t2 == E_AND) return 1; case E_AND: if (t2 == E_OR) return 1; case E_OR: if (t2 == E_CHOICE) return 1; case E_CHOICE: if (t2 == 0) return 1; default: return -1; } printf("[%dgt%d?]", t1, t2); return 0;#endif}void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, int prevtoken){ if (!e) { fn(data, "y"); return; } if (expr_compare_type(prevtoken, e->type) > 0) fn(data, "("); switch (e->type) { case E_SYMBOL: if (e->left.sym->name) fn(data, e->left.sym->name); else fn(data, "<choice>"); break; case E_NOT: fn(data, "!"); expr_print(e->left.expr, fn, data, E_NOT); break; case E_EQUAL: fn(data, e->left.sym->name); fn(data, "="); fn(data, e->right.sym->name); break; case E_UNEQUAL: fn(data, e->left.sym->name); fn(data, "!="); fn(data, e->right.sym->name); break; case E_OR: expr_print(e->left.expr, fn, data, E_OR); fn(data, " || "); expr_print(e->right.expr, fn, data, E_OR); break; case E_AND: expr_print(e->left.expr, fn, data, E_AND); fn(data, " && "); expr_print(e->right.expr, fn, data, E_AND); break; case E_CHOICE: fn(data, e->right.sym->name); if (e->left.expr) { fn(data, " ^ "); expr_print(e->left.expr, fn, data, E_CHOICE); } break; case E_RANGE: fn(data, "["); fn(data, e->left.sym->name); fn(data, " "); fn(data, e->right.sym->name); fn(data, "]"); break; default: { char buf[32]; sprintf(buf, "<unknown type %d>", e->type); fn(data, buf); break; } } if (expr_compare_type(prevtoken, e->type) > 0) fn(data, ")");}static void expr_print_file_helper(void *data, const char *str){ fwrite(str, strlen(str), 1, data);}void expr_fprint(struct expr *e, FILE *out){ expr_print(e, expr_print_file_helper, out, E_NONE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -