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_copy(struct expr *e) { if (!e) { return NULL; } struct expr *copy = expr_make(e->kind, NULL, NULL, NULL, e->constant); if (e->name) { copy->name = malloc(strlen(e->name) + 1); strcpy(copy->name, e->name); } copy->left = expr_copy(e->left); copy->right = expr_copy(e->right); copy->symbol = e->symbol; return copy; }
struct stmt *stmt_copy(struct stmt const *stmt) { struct stmt *copy = malloc(sizeof(*copy)); switch (copy->type = stmt->type) { case STMT_ASSIGN: copy->assign.identifier = strdup(stmt->assign.identifier); copy->assign.value = expr_copy(stmt->assign.value); break; case STMT_PRINT: copy->print = expr_copy(stmt->print); break; } return copy; }
static int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; if (e1->type != e2->type) 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: 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: e1 = expr_copy(e1); e2 = expr_copy(e2); old_count = trans_count; expr_eliminate_eq(&e1, &e2); res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym); expr_free(e1); expr_free(e2); trans_count = old_count; return res; case E_LIST: case E_RANGE: case E_NONE: /* panic */; } if (DEBUG_EXPR) { expr_fprint(e1, stdout); printf(" = "); expr_fprint(e2, stdout); printf(" ?\n"); } return 0; }
void expr_list_append(struct expr_list **list, struct expr const *expr) { while (*list) { list = &(*list)->next; } *list = malloc(sizeof(**list)); (*list)->expr = expr_copy(expr); (*list)->next = NULL; }
static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) { struct property *prop = prop_alloc(type, current_entry->sym); prop->menu = current_entry; prop->expr = expr; prop->visible.expr = menu_check_dep(dep); if (prompt) { /* For crostool-NG, a leading pipe followed with spaces * means that pipe shall be removed, and the spaces should * not be trimmed. */ if (*prompt == '|') prompt++; else if (isspace(*prompt)) { prop_warn(prop, "leading whitespace ignored"); while (isspace(*prompt)) prompt++; } if (current_entry->prompt && current_entry != &rootmenu) prop_warn(prop, "prompt redefined"); /* Apply all upper menus' visibilities to actual prompts. */ if(type == P_PROMPT) { struct menu *menu = current_entry; while ((menu = menu->parent) != NULL) { struct expr *dup_expr; if (!menu->visibility) continue; /* * Do not add a reference to the * menu's visibility expression but * use a copy of it. Otherwise the * expression reduction functions * will modify expressions that have * multiple references which can * cause unwanted side effects. */ dup_expr = expr_copy(menu->visibility); prop->visible.expr = expr_alloc_and(prop->visible.expr, dup_expr); } } current_entry->prompt = prop; } prop->text = prompt; return prop; }
static inline struct expr * expr_get_leftmost_symbol(const struct expr *e) { if (e == NULL) return NULL; while (e->type != E_SYMBOL) e = e->left.expr; return expr_copy(e); }
expression *expr_copy(expression *orig) { expression *copy; expression *oc; expression **cptr; if (NULL == orig) return NULL; /* fields */ copy = (expression*)calloc(1,sizeof(expression)); copy->type = orig->type; copy->qn = copy_qname(orig->qn); copy->xmlnode = orig->xmlnode; copy->ident = orig->ident ? strdup(orig->ident) : NULL; copy->axis = orig->axis; copy->num = orig->num; copy->str = orig->str ? strdup(orig->str) : NULL; copy->orig = orig->orig ? strdup(orig->orig) : NULL; copy->kind = orig->kind; /* branches */ copy->r.test = expr_copy(orig->r.test); copy->r.left = expr_copy(orig->r.left); copy->r.right = expr_copy(orig->r.right); copy->r.name_avt = expr_copy(orig->r.name_avt); copy->r.value_avt = expr_copy(orig->r.value_avt); copy->r.namespace_avt = expr_copy(orig->r.namespace_avt); /* children and attributes */ cptr = ©->r.children; for (oc = orig->r.children; oc; oc = oc->next) { *cptr = expr_copy(oc); cptr = &(*cptr)->next; } cptr = ©->r.attributes; for (oc = orig->r.attributes; oc; oc = oc->next) { *cptr = expr_copy(oc); cptr = &(*cptr)->next; } /* don't want to copy these properties - they're unique to the instance */ copy->restype = RESTYPE_UNKNOWN; copy->derivatives = NULL; copy->called = 0; return copy; }
struct expr *expr_copy(const struct expr *org) { struct expr *e; if (!org) return NULL; e = xmalloc(sizeof(*org)); memcpy(e, org, sizeof(*org)); switch (org->type) { case E_SYMBOL: e->left = org->left; break; case E_NOT: 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; break; case E_AND: case E_OR: case E_LIST: e->left.expr = expr_copy(org->left.expr); e->right.expr = expr_copy(org->right.expr); break; default: printf("can't copy type %d\n", e->type); free(e); e = NULL; break; } return e; }
int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; if (e1->type != e2->type) return 0; switch (e1->type) { case E_EQUAL: 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: e1 = expr_copy(e1); e2 = expr_copy(e2); old_count = trans_count; expr_eliminate_eq(&e1, &e2); res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && e1->left.sym == e2->left.sym); expr_free(e1); expr_free(e2); trans_count = old_count; return res; case E_CHOICE: case E_NONE: /* panic */ ; } print_expr(0, e1, 0); printf(" = "); print_expr(0, e2, 0); printf(" ?\n"); return 0; }
/* * Given expression `e1' and `e2', returns the leaf of the longest * sub-expression of `e1' not containing 'e2. */ struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) { struct expr *ret; switch (e1->type) { case E_OR: return expr_alloc_and( expr_simplify_unmet_dep(e1->left.expr, e2), expr_simplify_unmet_dep(e1->right.expr, e2)); case E_AND: { struct expr *e; e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); e = expr_eliminate_dups(e); ret = (!expr_eq(e, e1)) ? e1 : NULL; expr_free(e); break; } default: ret = e1; break; } return expr_get_leftmost_symbol(ret); }
struct expr *expr_copy(struct expr const *expr) { struct expr *copy = malloc(sizeof(*copy)); switch (copy->type = expr->type) { case EXPR_NUMBER: copy->number = expr->number; break; case EXPR_IDENTIFIER: copy->identifier = strdup(expr->identifier); break; case EXPR_STRING: copy->string = strdup(expr->string); break; case EXPR_UNARY: copy->unary.type = expr->unary.type; copy->unary.arg = expr_copy(expr->unary.arg); break; case EXPR_BINARY: copy->binary.type = expr->binary.type; copy->binary.lhs = expr_copy(expr->binary.lhs); copy->binary.rhs = expr_copy(expr->binary.rhs); break; case EXPR_LIST: copy->list = expr_list_copy(expr->list); break; case EXPR_DICT: copy->dict = expr_list_copy(expr->dict); break; case EXPR_ATTR: copy->attr.expr = expr_copy(expr->attr.expr); copy->attr.identifier = strdup(expr->attr.identifier); break; } return copy; }
stmt_ty * stmt_command_new(expr_list_ty *args, expr_list_ty *flags, expr_ty *input, expr_position_ty *pp) { stmt_ty *sp; stmt_command_ty *this; trace(("stmt_command_new()\n{\n")); sp = stmt_private_new(&method); this = (stmt_command_ty *)sp; expr_list_copy_constructor(&this->args, args); expr_list_copy_constructor(&this->flags, flags); this->input = (input ? expr_copy(input) : (expr_ty *)0); expr_position_copy_constructor(&this->pos, pp); trace(("return %8.8lX;\n", (long)sp)); trace(("}\n")); return sp; }
struct expr *expr_unary(enum expr_unary_type type, struct expr const *arg) { struct expr *expr = expr_alloc(EXPR_UNARY); expr->unary.type = type; expr->unary.arg = expr_copy(arg); return expr; }
// recursively copy all the way down. struct type * type_copy(struct type *t){ if(!t) return NULL; struct type * temp = type_create(t->kind, param_list_copy(t->params), type_copy(t->subtype), expr_copy(t->opt_expr)); return temp; }
void menu_finalize(struct menu *parent) { struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; struct expr *parentdep, *basedep, *dep, *dep2, **ep; sym = parent->sym; if (parent->list) { if (sym && sym_is_choice(sym)) { /* find the first choice value and find out choice type */ for (menu = parent->list; menu; menu = menu->next) { if (menu->sym) { current_entry = parent; menu_set_type(menu->sym->type); current_entry = menu; menu_set_type(sym->type); break; } } parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) { parentdep = parent->prompt->visible.expr; } else { parentdep = parent->dep; } for (menu = parent->list; menu; menu = menu->next) { basedep = expr_transform(menu->dep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; if (menu->sym) { prop = menu->sym->prop; } else { prop = menu->prompt; } for (; prop; prop = prop->next) { if (prop->menu != menu) { continue; } dep = expr_transform(prop->visible.expr); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) { dep = expr_trans_bool(dep); } prop->visible.expr = dep; if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); } } } for (menu = parent->list; menu; menu = menu->next) { menu_finalize(menu); } } else if (sym) { basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) { break; } if (expr_depends_symbol(dep, sym)) { goto next; } dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { expr_free(dep2); break; } expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; last_menu->next = NULL; } } for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym) { menu->sym->flags |= SYMBOL_CHOICEVAL; if (!menu->prompt) { menu_warn(menu, "choice value must have a prompt"); } for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type == P_PROMPT && prop->menu != menu) { prop_warn(prop, "choice values " "currently only support a " "single prompt"); } if (prop->type == P_DEFAULT) prop_warn(prop, "defaults for choice " "values not supported"); } current_entry = menu; menu_set_type(sym->type); menu_add_symbol(P_CHOICE, sym, NULL); prop = sym_get_choice_prop(sym); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) ; *ep = expr_alloc_one(E_CHOICE, NULL); (*ep)->right.sym = menu->sym; } if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { last_menu->parent = parent; if (!last_menu->next) { break; } } last_menu->next = menu->next; menu->next = menu->list; menu->list = NULL; } } if (sym && !(sym->flags & SYMBOL_WARNED)) { if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined " "without type\n"); if (sym_is_choice(sym) && !parent->prompt) { menu_warn(parent, "choice must have a prompt\n"); } /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; } if (sym && !sym_is_optional(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, expr_alloc_symbol(&symbol_mod))); } }
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_NONE: /* panic */ ; } return NULL; }
/* * e1 || e2 -> ? */ struct expr * expr_join_or(struct expr *e1, struct expr *e2) { struct expr *tmp; struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) return expr_copy(e1); if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) return NULL; if (e1->type == E_NOT) { tmp = e1->left.expr; if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) return NULL; sym1 = tmp->left.sym; } else sym1 = e1->left.sym; if (e2->type == E_NOT) { if (e2->left.expr->type != E_SYMBOL) return NULL; sym2 = e2->left.expr->left.sym; } else sym2 = e2->left.sym; if (sym1 != sym2) return NULL; if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) return NULL; if (sym1->type == S_TRISTATE) { if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { // (a='y') || (a='m') -> (a!='n') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); } if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { // (a='y') || (a='n') -> (a!='m') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); } if (e1->type == E_EQUAL && e2->type == E_EQUAL && ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { // (a='m') || (a='n') -> (a!='y') return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); } } if (sym1->type == S_BOOLEAN && sym1 == sym2) { if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) return expr_alloc_symbol(&symbol_yes); } printf("optimize "); print_expr(0, e1, 0); printf(" || "); print_expr(0, e2, 0); printf(" ?\n"); return NULL; }
void menu_finalize(struct menu *parent) { struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; struct expr *parentdep, *basedep, *dep, *dep2; sym = parent->sym; if (parent->list) { if (sym && sym_is_choice(sym)) { /* find the first choice value and find out choice type */ for (menu = parent->list; menu; menu = menu->next) { if (menu->sym) { current_entry = parent; menu_set_type(menu->sym->type); current_entry = menu; menu_set_type(sym->type); break; } } parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) parentdep = E_EXPR(parent->prompt->visible); else parentdep = parent->dep; for (menu = parent->list; menu; menu = menu->next) { basedep = expr_transform(menu->dep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; if (menu->sym) prop = menu->sym->prop; else prop = menu->prompt; for (; prop; prop = prop->next) { if (prop->menu != menu) continue; dep = expr_transform(E_EXPR(prop->visible)); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); E_EXPR(prop->visible) = dep; } } for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym && parent->prompt) { basedep = E_EXPR(parent->prompt->visible); basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep; if (!expr_contains_symbol(dep, sym)) break; if (expr_depends_symbol(dep, sym)) goto next; dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { expr_free(dep2); break; } expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; last_menu->next = NULL; } } for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym) { menu->sym->flags |= SYMBOL_CHOICEVAL; current_entry = menu; menu_set_type(sym->type); menu_add_prop(P_CHOICE, NULL, parent->sym, NULL); prop = sym_get_choice_prop(parent->sym); //dep = expr_alloc_one(E_CHOICE, dep); //dep->right.sym = menu->sym; prop->dep = expr_alloc_one(E_CHOICE, prop->dep); prop->dep->right.sym = menu->sym; } if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list;; last_menu = last_menu->next) { last_menu->parent = parent; if (!last_menu->next) break; } last_menu->next = menu->next; menu->next = menu->list; menu->list = NULL; } } }
void menu_finalize(struct menu *parent) { struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; struct expr *parentdep, *basedep, *dep, *dep2, **ep; sym = parent->sym; if (parent->list) { /* * This menu node has children. We (recursively) process them * and propagate parent dependencies before moving on. */ if (sym && sym_is_choice(sym)) { if (sym->type == S_UNKNOWN) { /* find the first choice value to find out choice type */ current_entry = parent; for (menu = parent->list; menu; menu = menu->next) { if (menu->sym && menu->sym->type != S_UNKNOWN) { menu_set_type(menu->sym->type); break; } } } /* set the type of the remaining choice values */ for (menu = parent->list; menu; menu = menu->next) { current_entry = menu; if (menu->sym && menu->sym->type == S_UNKNOWN) menu_set_type(sym->type); } /* * Use the choice itself as the parent dependency of * the contained items. This turns the mode of the * choice into an upper bound on the visibility of the * choice value symbols. */ parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) /* Menu node for 'menu' */ parentdep = parent->prompt->visible.expr; else /* Menu node for 'if' */ parentdep = parent->dep; /* For each child menu node... */ for (menu = parent->list; menu; menu = menu->next) { /* * Propagate parent dependencies to the child menu * node, also rewriting and simplifying expressions */ basedep = rewrite_m(menu->dep); basedep = expr_transform(basedep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; if (menu->sym) /* * Note: For symbols, all prompts are included * too in the symbol's own property list */ prop = menu->sym->prop; else /* * For non-symbol menu nodes, we just need to * handle the prompt */ prop = menu->prompt; /* For each property... */ for (; prop; prop = prop->next) { if (prop->menu != menu) /* * Two possibilities: * * 1. The property lacks dependencies * and so isn't location-specific, * e.g. an 'option' * * 2. The property belongs to a symbol * defined in multiple locations and * is from some other location. It * will be handled there in that * case. * * Skip the property. */ continue; /* * Propagate parent dependencies to the * property's condition, rewriting and * simplifying expressions at the same time */ dep = rewrite_m(prop->visible.expr); dep = expr_transform(dep); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); prop->visible.expr = dep; /* * Handle selects and implies, which modify the * dependencies of the selected/implied symbol */ if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); } else if (prop->type == P_IMPLY) { struct symbol *es = prop_get_symbol(prop); es->implied.expr = expr_alloc_or(es->implied.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); } } } if (sym && sym_is_choice(sym)) expr_free(parentdep); /* * Recursively process children in the same fashion before * moving on */ for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym) { /* * Automatic submenu creation. If sym is a symbol and A, B, C, * ... are consecutive items (symbols, menus, ifs, etc.) that * all depend on sym, then the following menu structure is * created: * * sym * +-A * +-B * +-C * ... * * This also works recursively, giving the following structure * if A is a symbol and B depends on A: * * sym * +-A * | +-B * +-C * ... */ basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); /* Examine consecutive elements after sym */ last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) /* No dependency, quit */ break; if (expr_depends_symbol(dep, sym)) /* Absolute dependency, put in submenu */ goto next; /* * Also consider it a dependency on sym if our * dependencies contain sym and are a "superset" of * sym's dependencies, e.g. '(sym || Q) && R' when sym * depends on R. * * Note that 'R' might be from an enclosing menu or if, * making this a more common case than it might seem. */ dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { /* Not superset, quit */ expr_free(dep2); break; } /* Superset, put in submenu */ expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } expr_free(basedep); if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; last_menu->next = NULL; } sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); } for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym && !sym_is_choice_value(menu->sym)) { current_entry = menu; menu->sym->flags |= SYMBOL_CHOICEVAL; if (!menu->prompt) menu_warn(menu, "choice value must have a prompt"); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type == P_DEFAULT) prop_warn(prop, "defaults for choice " "values not supported"); if (prop->menu == menu) continue; if (prop->type == P_PROMPT && prop->menu->parent->sym != sym) prop_warn(prop, "choice value used outside its choice group"); } /* Non-tristate choice values of tristate choices must * depend on the choice being set to Y. The choice * values' dependencies were propagated to their * properties above, so the change here must be re- * propagated. */ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); menu->dep = expr_alloc_and(basedep, menu->dep); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; prop->visible.expr = expr_alloc_and(expr_copy(basedep), prop->visible.expr); } } menu_add_symbol(P_CHOICE, sym, NULL); prop = sym_get_choice_prop(sym); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) ; *ep = expr_alloc_one(E_LIST, NULL); (*ep)->right.sym = menu->sym; } /* * This code serves two purposes: * * (1) Flattening 'if' blocks, which do not specify a submenu * and only add dependencies. * * (Automatic submenu creation might still create a submenu * from an 'if' before this code runs.) * * (2) "Undoing" any automatic submenus created earlier below * promptless symbols. * * Before: * * A * if ... (or promptless symbol) * +-B * +-C * D * * After: * * A * if ... (or promptless symbol) * B * C * D */ if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { last_menu->parent = parent; if (!last_menu->next) break; } last_menu->next = menu->next; menu->next = menu->list; menu->list = NULL; } } if (sym && !(sym->flags & SYMBOL_WARNED)) { if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined without type"); if (sym_is_choice(sym) && !parent->prompt) menu_warn(parent, "choice must have a prompt"); /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; } /* * For non-optional choices, add a reverse dependency (corresponding to * a select) of '<visibility> && m'. This prevents the user from * setting the choice mode to 'n' when the choice is visible. * * This would also work for non-choice symbols, but only non-optional * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented * as a type of symbol. */ if (sym && !sym_is_optional(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, expr_alloc_symbol(&symbol_mod))); } }
struct expr *expr_attr(struct expr const *lhs, char const *rhs) { struct expr *expr = expr_alloc(EXPR_ATTR); expr->attr.expr = expr_copy(lhs); expr->attr.identifier = strdup(rhs); return expr; }
struct stmt *stmt_assign(char const *identifier, struct expr const *expr) { struct stmt *stmt = stmt_alloc(STMT_ASSIGN); stmt->assign.identifier = strdup(identifier); stmt->assign.value = expr_copy(expr); return stmt; }
static struct expr *expr_join_and(struct expr *e1, struct expr *e2) { struct expr *tmp; struct symbol *sym1, *sym2; if (expr_eq(e1, e2)) return expr_copy(e1); if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) return NULL; if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) return NULL; if (e1->type == E_NOT) { tmp = e1->left.expr; if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) return NULL; sym1 = tmp->left.sym; } else sym1 = e1->left.sym; if (e2->type == E_NOT) { if (e2->left.expr->type != E_SYMBOL) return NULL; sym2 = e2->left.expr->left.sym; } else sym2 = e2->left.sym; if (sym1 != sym2) return NULL; if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) return NULL; if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) // (a) && (a='y') -> (a='y') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) // (a) && (a!='n') -> (a) return expr_alloc_symbol(sym1); if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) // (a) && (a!='m') -> (a='y') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if (sym1->type == S_TRISTATE) { if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' sym2 = e1->right.sym; if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) : expr_alloc_symbol(&symbol_no); } if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' sym2 = e2->right.sym; if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) : expr_alloc_symbol(&symbol_no); } if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) // (a!='y') && (a!='n') -> (a='m') return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) // (a!='y') && (a!='m') -> (a='n') return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) // (a!='m') && (a!='n') -> (a='m') return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) return NULL; } if (DEBUG_EXPR) { printf("optimize ("); expr_fprint(e1, stdout); printf(") && ("); expr_fprint(e2, stdout); printf(")?\n"); } return NULL; }
void menu_finalize(struct menu *parent) { struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; struct expr *parentdep, *basedep, *dep, *dep2, **ep; sym = parent->sym; if (parent->list) { if (sym && sym_is_choice(sym)) { if (sym->type == S_UNKNOWN) { /* find the first choice value to find out choice type */ current_entry = parent; for (menu = parent->list; menu; menu = menu->next) { if (menu->sym && menu->sym->type != S_UNKNOWN) { menu_set_type(menu->sym->type); break; } } } if (parent->prompt && !expr_is_yes(parent->prompt->visible.expr)) { parent->visibility = expr_alloc_and (parent->visibility, parent->prompt->visible.expr); } /* set the type of the remaining choice values */ for (menu = parent->list; menu; menu = menu->next) { current_entry = menu; if (menu->sym && menu->sym->type == S_UNKNOWN) menu_set_type(sym->type); } parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) parentdep = parent->prompt->visible.expr; else parentdep = parent->dep; for (menu = parent->list; menu; menu = menu->next) { basedep = expr_transform(menu->dep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); basedep = expr_eliminate_dups(basedep); menu->dep = basedep; if (menu->sym) prop = menu->sym->prop; else prop = menu->prompt; for (; prop; prop = prop->next) { if (prop->menu != menu) continue; dep = expr_transform(prop->visible.expr); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); prop->visible.expr = dep; if (prop->type == P_SELECT) { struct symbol *es = prop_get_symbol(prop); es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); } } } for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym) { basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) break; if (expr_depends_symbol(dep, sym)) goto next; dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); dep = expr_eliminate_dups(expr_transform(dep)); dep2 = expr_copy(basedep); expr_eliminate_eq(&dep, &dep2); expr_free(dep); if (!expr_is_yes(dep2)) { expr_free(dep2); break; } expr_free(dep2); next: menu_finalize(menu); menu->parent = parent; last_menu = menu; } if (last_menu) { parent->list = parent->next; parent->next = last_menu->next; last_menu->next = NULL; } sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); } for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym && !sym_is_choice_value(menu->sym)) { current_entry = menu; menu->sym->flags |= SYMBOL_CHOICEVAL; if (!menu->prompt) menu_warn(menu, "choice value must have a prompt"); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->type == P_DEFAULT) prop_warn(prop, "defaults for choice " "values not supported"); if (prop->menu == menu) continue; if (prop->type == P_PROMPT && prop->menu->parent->sym != sym) prop_warn(prop, "choice value used outside its choice group"); } /* Non-tristate choice values of tristate choices must * depend on the choice being set to Y. The choice * values' dependencies were propagated to their * properties above, so the change here must be re- * propagated. */ if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); menu->dep = expr_alloc_and(basedep, menu->dep); for (prop = menu->sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; prop->visible.expr = expr_alloc_and(expr_copy(basedep), prop->visible.expr); } } menu_add_symbol(P_CHOICE, sym, NULL); prop = sym_get_choice_prop(sym); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) ; *ep = expr_alloc_one(E_LIST, NULL); (*ep)->right.sym = menu->sym; } if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { last_menu->parent = parent; if (!last_menu->next) break; } last_menu->next = menu->next; menu->next = menu->list; menu->list = NULL; } } if (sym && !(sym->flags & SYMBOL_WARNED)) { if (sym->type == S_UNKNOWN) menu_warn(parent, "config symbol defined without type"); if (sym_is_choice(sym) && !parent->prompt) menu_warn(parent, "choice must have a prompt"); /* Check properties connected to this symbol */ sym_check_prop(sym); sym->flags |= SYMBOL_WARNED; } if (sym && !sym_is_optional(sym) && parent->prompt) { sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, expr_alloc_and(parent->prompt->visible.expr, expr_alloc_symbol(&symbol_mod))); } }
struct stmt *stmt_print(struct expr const *expr) { struct stmt *stmt = stmt_alloc(STMT_PRINT); stmt->print = expr_copy(expr); return stmt; }