-rw-r--r-- | scripts/kconfig/cml1.y | 2482 |
1 files changed, 2482 insertions, 0 deletions
diff --git a/scripts/kconfig/cml1.y b/scripts/kconfig/cml1.y new file mode 100644 index 0000000..42c4216 --- a/dev/null +++ b/scripts/kconfig/cml1.y @@ -0,0 +1,2482 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define PRINTD 0x0001 +#define DEBUG_PARSE 0x0002 +#define DEBUG_OPT 0x0004 +#define DEBUG_OPT1 0x0008 +#define DEBUG_OPT2 0x0010 +#define DEBUG_OPT3 0x0020 +#define DEBUG_OPT4 0x0040 +#define DEBUG_OPT5 0x0080 +#define DEBUG_DEP 0x0100 + +int cdebug = PRINTD;//DEBUG_OPT|-1; + +#define YYERROR_VERBOSE +%} + +%union +{ + char *string; + struct expr *expr; + struct symbol *symbol; + struct statement *stmt; +} + +%token <string> T_WORD +%token <string> T_WORD_QUOTE +%token <string> T_WORD_DQUOTE +%token T_MAINMENU_NAME +%token T_MAINMENU_OPTION +%token T_NEXT_COMMENT +%token T_ENDMENU +%token T_COMMENT +%token T_BOOL +%token T_HEX +%token T_INT +%token T_STRING +%token T_TRISTATE +%token T_DEFINE_BOOL +%token T_DEFINE_HEX +%token T_DEFINE_INT +%token T_DEFINE_STRING +%token T_DEFINE_TRISTATE +%token T_DEP_BOOL +%token T_DEP_MBOOL +%token T_DEP_TRISTATE +%token T_UNSET +%token T_CHOICE +%token T_SOURCE +%token T_IF +%token T_ELSE +%token T_FI +%token T_THEN +%token T_UNEQUAL +%token <string> T_SH_COMMENT + +%type <string> prompt +%type <string> word +%type <string> menu_comment +%type <symbol> symbol +%type <symbol> symbol_ref +%type <symbol> symbol_other +%type <stmt> statement +%type <expr> expr +%type <expr> dep +%type <expr> deps +%type <stmt> comment_opt + +%left T_OR +%left T_AND +%nonassoc '!' +%left '=' T_UNEQUAL + +%{ +#include "cml1.h" + +extern int cml1lex(void); +static void cml1error(const char *err); +extern int lineno(void); +extern void scan_nextfile(char *file); + +struct statement *create_stmt(int token); +struct statement *add_stmt(struct symbol *sym, int token, + char *prompt, struct symbol *def); +void print_expr(int mask, struct expr *e, int prevtoken); +void print_dep(int mask, struct statement *stmt); + +void eliminate_eq(int token, struct expr **ep1, struct expr **ep2); +static inline int expr_is_yes(struct expr *e); +static inline int expr_is_no(struct expr *e); +struct expr *trans_dep_bool(struct expr *e); +struct expr *trans_bool_expr(struct expr *e); +struct expr *fixup_expr(struct expr *e); +struct expr *trans_expr(struct expr *e); +void extract_eq(int token, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *extract_eq_or(struct expr **ep1, struct expr **ep2); +struct expr *optimize_expr_or(struct expr *e); +struct expr *eliminate_dups(struct expr *e); +struct expr *eliminate_yn(struct expr *e); +void eliminate_dep(struct symbol *sym, struct expr *dep); +int contains_expr(struct expr *dep, struct expr *e); + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) +#define fprintd(f, mask, fmt...) if (cdebug & (mask)) fprintf(f, fmt) + +static struct expr *if_expr; +static struct menu root_menu; +static struct menu *current_menu = &root_menu; + +struct symbol *symbol_hash[257]; +%} +%% +input: line +; + +line: /* empty */ +; + +line: line statement +; + +line: line '\n' +; + +statement: T_SH_COMMENT +{ + $$ = create_stmt(T_SH_COMMENT); + $$->text = $1; +}; + +statement: T_MAINMENU_NAME prompt '\n' +{ + $$ = create_stmt(T_MAINMENU_NAME); + $$->text = $2; + printd(DEBUG_PARSE, "%d:mainmenu_name: %s\n", lineno(), $2); +}; + +statement: T_COMMENT prompt '\n' +{ + $$ = create_stmt(T_COMMENT); + $$->text = $2; + $$->dep = trans_expr(fixup_expr(expr_copy(if_expr))); + printd(DEBUG_PARSE, "%d:comment: %s\n", lineno(), $2); +}; + +statement: T_BOOL prompt symbol dep '\n' +{ + $$ = add_stmt($3, T_BOOL, $2, NULL); + printd(DEBUG_PARSE, "%d:bool: %s %s\n", lineno(), $2, $3->name); + if ($4) { + printf("%s:%d: warning ignoring dependencies\n", current_file->name, current_file->lineno); + expr_free($4); + } + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_HEX prompt symbol symbol_other '\n' +{ + $$ = add_stmt($3, T_HEX, $2, NULL); + add_stmt($3, T_DEFINE_HEX, NULL, $4); + printd(DEBUG_PARSE, "%d:hex: %s %s %s\n", lineno(), $2, $3->name, $4->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_INT prompt symbol symbol_other '\n' +{ + $$ = add_stmt($3, T_INT, $2, NULL); + add_stmt($3, T_DEFINE_INT, NULL, $4); + printd(DEBUG_PARSE, "%d:int: %s %s %s\n", lineno(), $2, $3->name, $4->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_STRING prompt symbol symbol_other '\n' +{ + $$ = add_stmt($3, T_STRING, $2, NULL); + add_stmt($3, T_DEFINE_STRING, NULL, $4); + printd(DEBUG_PARSE, "%d:string: %s %s %s\n", lineno(), $2, $3->name, $4->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_TRISTATE prompt symbol dep '\n' +{ + $$ = add_stmt($3, T_TRISTATE, $2, NULL); + printd(DEBUG_PARSE, "%d:tristate: %s %s\n", lineno(), $2, $3->name); + if ($4) { + printf("%s:%d: warning ignoring dependencies\n", current_file->name, current_file->lineno); + expr_free($4); + } + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEFINE_BOOL symbol symbol_ref comment_opt '\n' +{ + $$ = add_stmt($2, T_DEFINE_BOOL, NULL, $3); + printd(DEBUG_PARSE, "%d:define_bool: %s %s\n", lineno(), $2->name, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEFINE_HEX symbol symbol_other '\n' +{ + $$ = add_stmt($2, T_DEFINE_HEX, NULL, $3); + printd(DEBUG_PARSE, "%d:define_hex: %s %s\n", lineno(), $2->name, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEFINE_INT symbol symbol_other comment_opt '\n' +{ + $$ = add_stmt($2, T_DEFINE_INT, NULL, $3); + printd(DEBUG_PARSE, "%d:define_int: %s %s\n", lineno(), $2->name, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEFINE_STRING symbol symbol_other '\n' +{ + $$ = add_stmt($2, T_DEFINE_STRING, NULL, $3); + printd(DEBUG_PARSE, "%d:define_string: %s %s\n", lineno(), $2->name, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEFINE_TRISTATE symbol symbol_ref '\n' +{ + $$ = add_stmt($2, T_DEFINE_TRISTATE, NULL, $3); + printd(DEBUG_PARSE, "%d:define_tristate: %s %s\n", lineno(), $2->name, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEP_BOOL prompt symbol dep '\n' +{ + $$ = add_stmt($3, T_DEP_BOOL, $2, NULL); + if (!($$->dep2 = $4)) + printf("%s:%d: warning dep_bool without dependencies\n", current_file->name, current_file->lineno); + printd(DEBUG_PARSE, "%d:dep_bool: %s %s\n", lineno(), $2, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEP_MBOOL prompt symbol dep '\n' +{ + $$ = add_stmt($3, T_DEP_MBOOL, $2, NULL); + if (!($$->dep2 = $4)) + printf("%s:%d: warning dep_mbool without dependencies\n", current_file->name, current_file->lineno); + printd(DEBUG_PARSE, "%d:dep_mbool: %s %s\n", lineno(), $2, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_DEP_TRISTATE prompt symbol dep '\n' +{ + $$ = add_stmt($3, T_DEP_TRISTATE, $2, NULL); + if (!($$->dep2 = $4)) + printf("%s:%d: warning dep_tristate without dependencies\n", current_file->name, current_file->lineno); + printd(DEBUG_PARSE, "%d:dep_tristate: %s %s\n", lineno(), $2, $3->name); + print_dep(DEBUG_PARSE, $$); +}; + +statement: T_UNSET deps '\n' +{ + //add_stmt($2, T_UNSET, NULL, NULL); + printd(DEBUG_PARSE, "%d:unset\n", lineno()); + print_dep(DEBUG_PARSE, NULL); +}; + +statement: T_CHOICE prompt word word '\n' +{ + struct statement *stmt; + struct symbol *sym; + struct expr **depp; + char *ptr, *name, *def, end; + + printd(DEBUG_PARSE, "%d:choice: %s %s %s\n", lineno(), $2, $3, $4); + $$ = create_stmt('^'); + $$->text = $2; + ptr = $3; + depp = &$$->dep; + do { + while (isspace(*ptr)) + ptr++; + if (!*ptr) + break; + def = ptr; + while (*ptr && !isspace(*ptr)) + ptr++; + *ptr++ = 0; + //def = lookup_symbol(name, SYMBOL_OTHER); + while (isspace(*ptr)) + ptr++; + if (!*ptr) + break; + name = ptr; + while (*ptr && !isspace(*ptr)) + ptr++; + end = *ptr; + *ptr++ = 0; + sym = lookup_symbol(name, SYMBOL_BOOLEAN); + if (!$$->def) { + if (!strncmp(def, $4, strlen($4))) + $$->def = sym; + } + sym->flags |= SYMBOL_CHOICE; + stmt = add_stmt(sym, T_BOOL, strdup(def), NULL); + if (!stmt->next) { + stmt->next = $$; + } else + printf("warning: unexpected stmt for choice symbol %s\n", sym->name); + *depp = expr_alloc_one('^', NULL); + (*depp)->right.sym = sym; + depp = &(*depp)->left.expr; + printd(DEBUG_PARSE, "added symbol: %s %s\n", sym->name, stmt->text); + } while (end); + print_dep(DEBUG_PARSE, NULL); +}; + +statement: T_IF '[' expr ']' semi_or_nl T_THEN comment_opt '\n' +{ + struct expr *e; + printd(DEBUG_PARSE, "%d:if ", lineno()); + print_expr(DEBUG_PARSE, $3, 0); + printd(DEBUG_PARSE, "\n"); + e = expr_alloc_one(T_IF, $3); + e->right.expr = if_expr; + if_expr = e; + $$ = NULL; +}; + +semi_or_nl: ';' | '\n' +; + +statement: T_ELSE comment_opt '\n' +{ + printd(DEBUG_PARSE, "%d:else\n", lineno()); + if_expr->token = T_ELSE; + $$ = NULL; +}; + +statement: T_FI comment_opt '\n' +{ + struct expr *e; + printd(DEBUG_PARSE, "%d:fi\n", lineno()); + e = if_expr; + if (e) { + if_expr = e->right.expr; + expr_free(e->left.expr); + free(e); + } else + YYABORT; + $$ = NULL; +}; + +statement: T_MAINMENU_OPTION T_NEXT_COMMENT menu_comment '\n' +{ + printd(DEBUG_PARSE, "%d:mainmenu_option: %s\n", lineno(), $3); + $$ = create_stmt(T_MAINMENU_OPTION); + $$->text = $3; + $$->dep = trans_expr(fixup_expr(expr_copy(if_expr))); + current_menu = $$->menu; +}; + +menu_comment: '\n' T_COMMENT prompt { $$ = $3; } + | '\n' menu_comment { $$ = $2; } +; + +statement: T_ENDMENU '\n' +{ + $$ = create_stmt(T_ENDMENU); + printd(DEBUG_PARSE, "%d:endmenu\n", lineno()); + current_menu = current_menu->parent; +}; + +statement: T_SOURCE word '\n' +{ + static char helppath[256]; + char *p; + $$ = create_stmt(T_SOURCE); + $$->text = $2; + printd(DEBUG_PARSE, "%d:source: %s\n", lineno(), $2); + strcpy(helppath, $2); + p = strrchr(helppath, '.'); + if (p) { + strcpy(p, ".help"); + helplex(helppath); + } + scan_nextfile($2); +}; + +comment_opt: /* empty */ { $$ = NULL; } + | T_SH_COMMENT +{ + $$ = create_stmt(T_SH_COMMENT); + $$->text = $1; +}; + +prompt: T_WORD_QUOTE + | T_WORD_DQUOTE +; + +word: T_WORD + | T_WORD_QUOTE + | T_WORD_DQUOTE +; + +dep: /* empty */ { $$ = NULL; } + | deps { $$ = $1; } +; + +deps: symbol_ref { $$ = expr_alloc_symbol($1); } + | deps symbol_ref { $$ = expr_alloc_two('&', $1, expr_alloc_symbol($2)); } +; + +symbol: T_WORD { $$ = lookup_symbol($1, SYMBOL_UNKNOWN); free($1); } +; + +expr: symbol_ref '=' symbol_ref { $$ = expr_alloc_comp('=', $1, $3); } + | symbol_ref T_UNEQUAL symbol_ref { $$ = expr_alloc_comp(T_UNEQUAL, $1, $3); } + | '!' expr { $$ = expr_alloc_one('!', $2); } + | expr T_AND expr { $$ = expr_alloc_two(T_AND, $1, $3); } + | expr T_OR expr { $$ = expr_alloc_two(T_OR, $1, $3); } +; + +symbol_ref: T_WORD { $$ = lookup_symbol_ref($1); free($1); } + | T_WORD_QUOTE { $$ = lookup_symbol_ref($1); free($1); } + | T_WORD_DQUOTE { $$ = lookup_symbol_ref($1); free($1); } +; + +symbol_other: T_WORD { $$ = lookup_symbol($1, SYMBOL_OTHER); free($1); } + | T_WORD_QUOTE { $$ = lookup_symbol($1, SYMBOL_OTHER); free($1); } + | T_WORD_DQUOTE { $$ = lookup_symbol($1, SYMBOL_OTHER); free($1); } +; + +%% + +static void yyerror(const char *err) +{ + printf("%s:%d: %s\n", current_file->name, current_file->lineno + 1, err); + exit(1); +} + +void print_dep(int mask, struct statement *stmt) +{ + printd(mask, "dep: "); + if (stmt) { + if (stmt->dep2) + printd(mask, "["); + print_expr(mask, stmt->dep, 0); + if (stmt->dep2) { + printd(mask, " & "); + print_expr(mask, stmt->dep2, 0); + printd(mask, "]"); + } + } else + print_expr(mask, if_expr, 0); + printd(mask, "\n"); +} + +struct symbol *lookup_symbol(char *name, int type) +{ + struct symbol *symbol; + char *ptr; + int hash = 0; + + //printf("lookup: %s -> ", name); + if (type != SYMBOL_OTHER && !strncmp(name, "CONFIG_", 7)) { + name += 7; + } else { + //printf("Warning: Invalid symbol name '%s'\n", name); + type = SYMBOL_OTHER; + } + + for (ptr = name; *ptr; ptr++) + hash += *ptr; + + for (symbol = symbol_hash[hash&255]; symbol; symbol = symbol->next) { + if (!strcmp(symbol->name, name)) { + //printf("h:%p\n", symbol); + if (type == SYMBOL_BOOLEAN) + symbol->type = SYMBOL_BOOLEAN; + return symbol; + } + } + + symbol = malloc(sizeof(*symbol)); + memset(symbol, 0, sizeof(*symbol)); + symbol->name = strdup(name); + symbol->type = type; + + symbol->next = symbol_hash[hash&255]; + symbol_hash[hash&255] = symbol; + + //printf("n:%p\n", symbol); + return symbol; +} + +struct symbol *lookup_symbol_ref(char *name) +{ + if (name[0] == 'y' && !name[1]) + return &symbol_yes; + if (name[0] == 'm' && !name[1]) + return &symbol_mod; + if (name[0] == 'n' && !name[1]) + return &symbol_no; + if (name[0] == '$') + return lookup_symbol(name+1, SYMBOL_UNKNOWN); + return lookup_symbol(name, SYMBOL_OTHER); +} + +struct statement *create_stmt(int token) +{ + struct statement *stmt; + struct menu *menu, **menup; + + stmt = malloc(sizeof(*stmt)); + memset(stmt, 0, sizeof(*stmt)); + stmt->token = token; + stmt->file = current_file; + stmt->lineno = lineno(); + + if (!current_file->stmt) + current_file->stmt = stmt; + if (current_file->last_stmt) + current_file->last_stmt->next_pos = stmt; + current_file->last_stmt = stmt; + + menu = malloc(sizeof(*menu)); + memset(menu, 0, sizeof(*menu)); + menu->prompt = stmt; + menu->parent = current_menu; + for (menup = ¤t_menu->list; *menup; menup = &(*menup)->next) + ; + *menup = menu; + + stmt->menu = menu; + + return stmt; +} + +struct statement *add_stmt(struct symbol *sym, int token, char *prompt, struct symbol *def) +{ + struct statement *stmt = create_stmt(token); + + stmt->dep = expr_copy(if_expr); + stmt->text = prompt; + stmt->def = def; + + stmt->sym = sym; + stmt->next = sym->stmt; + sym->stmt = stmt; + + return stmt; +} + +void print_quoted_string(FILE *out, const char *str) +{ + const char *p; + int len; + + putc('"', out); + while ((p = strchr(str, '"'))) { + len = p - str; + if (len) + fprintf(out, "%.*s", len, str); + fputs("\\\"", out); + str += len + 1; + } + fputs(str, out); + putc('"', out); +} + +const char *skip_space(const char *p) +{ + while (*p == ' ') + p++; + return p; +} + +void do_print_symbol(FILE *out, struct symbol *sym) +{ + struct statement *zero_stmt, *stmt, *stmt2; + struct expr *dep, *dep2; + +#define VALID_STMT(s) (s->token && s->token != '^' && s->menu && s->menu->parent == current_menu) + + dep = NULL; + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (!VALID_STMT(stmt)) + continue; + if (!dep) { + if (!stmt->dep) + break; + dep = stmt->dep; + stmt->dep = NULL; + } else { + struct expr *e = dep; + if (stmt->dep) { + dep = extract_eq_and(&e, &stmt->dep); + if (expr_is_yes(e)) { + expr_free(e); + continue; + } + } else + dep = NULL; + for (stmt2 = sym->stmt; stmt != stmt2; stmt2 = stmt2->next) { + if (!VALID_STMT(stmt2)) + continue; + stmt2->dep = !stmt2->dep ? expr_copy(e) : + expr_alloc_two(T_AND, expr_copy(e), stmt2->dep); + } + expr_free(e); + if (!dep) + break; + } + } + + zero_stmt = NULL; + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (!stmt->token) + zero_stmt = stmt; + if (VALID_STMT(stmt)) + break; + } + if (!stmt) { + if (sym->flags & SYMBOL_PRINTED) + return; + if (!zero_stmt) + return; + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (stmt->token) + return; + } + stmt = zero_stmt; + } + + fprintf(out, "config %s\n", sym->name); + + switch (sym->type) { + case SYMBOL_BOOLEAN: fputs("\tbool", out); break; + case SYMBOL_TRISTATE: fputs("\ttristate", out); break; + case SYMBOL_INT: fputs("\tint", out); break; + case SYMBOL_HEX: fputs("\thex", out); break; + case SYMBOL_STRING: fputs("\tstring", out); break; + default: fputs("\t#unknown type?", out); break; + } + + if (stmt->text) { + fputc(' ', out); + print_quoted_string(out, skip_space(stmt->text)); + if (!expr_is_yes(stmt->dep)) { + fputs(" if ", out); + fprint_expr(out, stmt->dep, 0); + } + stmt->menu = NULL; + stmt = stmt->next; + } + fputc('\n', out); + + if (sym->dep || dep) { + dep = expr_alloc_and(expr_copy(sym->dep), dep); + dep = eliminate_yn(dep); + if (current_menu->prompt && current_menu->prompt->dep) { + dep2 = expr_copy(current_menu->prompt->dep); + switch (sym->type) { + case SYMBOL_BOOLEAN: case SYMBOL_INT: case SYMBOL_HEX: case SYMBOL_STRING: + dep2 = trans_bool_expr(dep2); + break; + } + eliminate_eq(T_AND, &dep, &dep2); + dep = eliminate_yn(dep); +#if 0 + dep2 = eliminate_yn(dep2); + if (!expr_is_yes(dep2)) { + printf("Warning, I'm still confused (%s)?\n", sym->name); + print_expr(PRINTD, dep, 0); + printf(" - "); + print_expr(PRINTD, dep2, 0); + printf("\n"); + } +#endif + expr_free(dep2); + } + if (!expr_is_yes(dep)) { + fputs("\tdepends on ", out); + fprint_expr(out, eliminate_yn(dep), 0); + fputc('\n', out); + } + } + for (; stmt; stmt = stmt->next) { + if (!VALID_STMT(stmt)) + continue; + if (stmt->text) { + ; + } else if (stmt->def) { + if (sym->flags & SYMBOL_CHOICE) + printf("Choice value %s has default value!\n", sym->name); + fputs( "\tdefault ", out); + switch (sym->type) { + case SYMBOL_BOOLEAN: + case SYMBOL_TRISTATE: + fputs(stmt->def->name, out); + break; + default: + print_quoted_string(out, stmt->def->name); + break; + } + if (!expr_is_yes(stmt->dep)) { + fputs(" if ", out); + fprint_expr(out, eliminate_yn(stmt->dep), 0); + } + fputc('\n', out); + stmt->menu = NULL; + } + } + if (sym->help && !(sym->flags & SYMBOL_PRINTED)) { + int len = strlen(sym->help); + char *p, *p2; + int cnt; + + while (sym->help[--len] == '\n') + sym->help[len] = 0; + for (p = sym->help, cnt = 0; (p = strchr(p, '\n')); p++, cnt++) + ; + if (cnt >= 9) + fprintf(out, "\t---help---\n"); + else + fprintf(out, "\thelp\n"); + for (p = sym->help;; p = p2 + 1) { + while (*p == ' ') + p++; + if (*p == '\n') { + fputc('\n', out); + p2 = p; + continue; + } + p2 = strchr(p, '\n'); + if (!p2) + break; + fprintf(out, "\t %.*s\n", p2 - p, p); + } + fprintf(out, "\t %s\n", p); + } + fputc('\n', out); + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (!VALID_STMT(stmt)) + continue; + if (stmt->text) { + fprintf(out, "config %s\n", sym->name); + fputs( "\tprompt ", out); + print_quoted_string(out, skip_space(stmt->text)); + fputc('\n', out); + dep2 = expr_alloc_and(expr_copy(dep), expr_copy(stmt->dep)); + dep2 = eliminate_dups(dep2); + if (!expr_is_yes(dep2)) { + fputs("\tdepends on ", out); + fprint_expr(out, dep2, 0); + fputc('\n', out); + } + expr_free(dep2); + fputc('\n', out); + stmt->menu = NULL; + } + } + sym->flags |= SYMBOL_PRINTED; + expr_free(dep); +} + +void print_choice(FILE *out, struct symbol *sym) +{ + struct statement *stmt; + struct expr *lst, *dep, *tmp, *tmp2; + + if (sym->flags & SYMBOL_PRINTED) + return; + + for (stmt = sym->stmt; stmt; stmt = stmt->next) + if (stmt->token == '^') + break; + if (!stmt) + //warn? + return; + + fputs("choice\n", out); + if (stmt->text) { + fputs("\tprompt ", out); + print_quoted_string(out, skip_space(stmt->text)); + fputc('\n', out); + } + + dep = NULL; + for (lst = stmt->dep; lst; lst = lst->left.expr) { + sym = lst->right.sym; + if (sym == &symbol_no) { + fputs("\toptional\n", out); + continue; + } + if (!dep) { + if (!sym->dep) + break; + dep = sym->dep; + sym->dep = NULL; + } else { + tmp = dep; + if (sym->dep) { + dep = extract_eq_and(&tmp, &sym->dep); + if (expr_is_yes(tmp)) { + expr_free(tmp); + continue; + } + } else + dep = NULL; + for (tmp2 = stmt->dep; tmp2 != lst; tmp2 = tmp2->left.expr) { + sym = tmp2->right.sym; + if (sym == &symbol_no) + continue; + sym->dep = !sym->dep ? expr_copy(tmp) : + expr_alloc_two(T_AND, expr_copy(tmp), sym->dep); + sym->dep = eliminate_yn(sym->dep); + } + expr_free(tmp); + if (!dep) + break; + } + } + for (;lst; lst = lst->left.expr) { + sym = lst->right.sym; + if (sym == &symbol_no) { + fputs("\toptional\n", out); + continue; + } + } + if (!expr_is_yes(dep)) { + fputs("\tdepends on ", out); + fprint_expr(out, dep, 0); + fputc('\n', out); + } + if (stmt->def) + fprintf(out, "\tdefault %s\n", stmt->def->name); + + fputc('\n', out); + + for (lst = stmt->dep; lst; lst = lst->left.expr) { + sym = lst->right.sym; + if (sym == &symbol_no) + continue; + do_print_symbol(out, sym); + sym->flags |= SYMBOL_PRINTED; + } + + fputs("endchoice\n\n", out); +} + +void print_symbols(FILE *out, struct symbol *sym) +{ + //if (sym->flags & SYMBOL_PRINTED) + // return; + //sym->flags |= SYMBOL_PRINTED; + + if (sym->flags & SYMBOL_CHOICE) { + print_choice(out, sym); + return; + } + do_print_symbol(out, sym); +} + +char *gen_filename(const char *name) +{ + static char newname[128]; + char *p; + + strcpy(newname, name); + p = strrchr(newname, '/'); + if (!p) + p = newname; + else + p++; +#if 0 + p = strrchr(p, '.'); + if (!p) + p = newname + strlen(newname); + strcpy(p, ".new"); +#else +#if 0 + memcpy(p, "Build", 5); + memmove(p + 5, p + 6, strlen(p) - 5); + p = strrchr(p, '.'); + if (!p) + p = newname + strlen(newname); + strcpy(p, ".conf"); +#else + memmove(p + 1, p, strlen(p) + 1); + p[0] = 'K'; + p[1] = 'c'; + p = strrchr(p, '.'); + *p = 0; +#endif +#endif + return newname; +} + +void print_files(FILE *all_out, const char *name) +{ + struct file *file; + FILE *out = all_out; + struct symbol *sym; + struct statement *stmt; + struct expr *dep1, *dep2; + char *p; + + print_type = 0; + + file = lookup_file(name); + if (!file) { + fprintf(stderr, "# file %s not found!\n\n", file->name); + return; + } else if (file->flags & FILE_PRINTED) { + fprintf(stderr, "# file %s skipped\n\n", file->name); + return; + } + + if (!out) { + p = gen_filename(file->name); + strcat(p, ".lkc"); + out = fopen(p, "w"); + if (!out) { + printf("unable to open %s for writing!\n", p); + exit(1); + } + } + + if (all_out) + fprintf(all_out, "# file %s\n\n", file->name); + file->flags |= FILE_PRINTED; + + for (stmt = file->stmt; stmt; stmt = stmt->next_pos) { + sym = stmt->sym; + if (!sym) { + switch (stmt->token) { + case T_MAINMENU_NAME: + fputs("\nmainmenu ", out); + print_quoted_string(out, skip_space(stmt->text)); + fputs("\n\n", out); + break; + case T_COMMENT: + fputs("comment ", out); + print_quoted_string(out, skip_space(stmt->text)); + stmt->dep = eliminate_dups(trans_expr(stmt->dep)); + dep1 = expr_copy(stmt->dep); + if (dep1 && current_menu->prompt && current_menu->prompt->dep) { + dep2 = expr_copy(current_menu->prompt->dep); + eliminate_eq(T_AND, &dep1, &dep2); + dep1 = eliminate_yn(dep1); + dep2 = eliminate_yn(dep2); + if (!expr_is_yes(dep2)) { + printf("Warning, I'm confused!\n"); + } + expr_free(dep2); + } + if (!expr_is_yes(dep1)) { + dep1 = trans_bool_expr(dep1); + fputs("\n\tdepends on ", out); + fprint_expr(out, dep1, 0); + } + expr_free(dep1); + fputs("\n\n", out); + break; + case T_SH_COMMENT: + fprintf(out, "%s\n", stmt->text); + break; + case T_MAINMENU_OPTION: + fputs("\nmenu ", out); + print_quoted_string(out, skip_space(stmt->text)); + stmt->dep = eliminate_dups(trans_expr(stmt->dep)); + dep1 = expr_copy(stmt->dep); + if (dep1 && current_menu->prompt && current_menu->prompt->dep) { + dep2 = expr_copy(current_menu->prompt->dep); + eliminate_eq(T_AND, &dep1, &dep2); + dep1 = eliminate_yn(dep1); + dep2 = eliminate_yn(dep2); + if (!expr_is_yes(dep2)) { + printf("Warning, I'm confused!\n"); + } + expr_free(dep2); + } + if (!expr_is_yes(dep1)) { + fputs("\n\tdepends on ", out); + fprint_expr(out, dep1, 0); + } + expr_free(dep1); + fputs("\n\n", out); + current_menu = stmt->menu; + break; + case T_ENDMENU: + fputs("endmenu\n\n", out); + current_menu = current_menu->parent; + break; + case T_SOURCE: + fprintf(out, "%ssource ", all_out ? "#" : ""); + print_quoted_string(out, gen_filename(stmt->text)); + fputs("\n\n", out); + print_files(all_out, stmt->text); + break; + } + } else + print_symbols(out, sym); + } + + if (all_out) + fprintf(out, "# fileend %s\n\n", file->name); +} + +static int trans_count; + +void eliminate_eq(int token, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + + if (e1->token == token) { + eliminate_eq(token, &e1->left.expr, &e2); + eliminate_eq(token, &e1->right.expr, &e2); + return; + } + if (e2->token == token) { + eliminate_eq(token, &e1, &e2->left.expr); + eliminate_eq(token, &e1, &e2->right.expr); + return; + } + if (e1->token == T_WORD && e2->token == T_WORD && + e1->left.sym == e2->left.sym && (e1->left.sym->flags & (SYMBOL_YES|SYMBOL_NO))) + return; + if (!expr_eq(e1, e2)) + return; + trans_count++; + expr_free(e1); expr_free(e2); + switch (token) { + case T_OR: + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + break; + case T_AND: + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + break; + } +#undef e1 +#undef e2 +} + +int expr_eq(struct expr *e1, struct expr *e2) +{ + int res, old_count; + + if (e1->token != e2->token) + return 0; + switch (e1->token) { + case '=': + case T_UNEQUAL: + return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; + case T_WORD: + return e1->left.sym == e2->left.sym; + case '!': + return expr_eq(e1->left.expr, e2->left.expr); + case T_AND: + case T_OR: + e1 = expr_copy(e1); + e2 = expr_copy(e2); + old_count = trans_count; + eliminate_eq(e1->token, &e1, &e2); + e1 = eliminate_yn(e1); + e2 = eliminate_yn(e2); + res = (e1->token == T_WORD && + e2->token == T_WORD && + e1->left.sym == e2->left.sym); + expr_free(e1); + expr_free(e2); + trans_count = old_count; + return res; + } + print_expr(PRINTD, e1, 0); + printf(" = "); + print_expr(PRINTD, e2, 0); + printf(" ?\n"); + return 0; +} + +/* + * dep_bool FOO -> FOO=y + */ +struct expr *trans_dep_bool(struct expr *e) +{ + switch (e->token) { + case '&': + case T_AND: + e->left.expr = trans_dep_bool(e->left.expr); + e->right.expr = trans_dep_bool(e->right.expr); + break; + case T_WORD: + if (e->left.sym->type == SYMBOL_TRISTATE) { + e->token = '='; + e->right.sym = &symbol_yes; + } + break; + } + return e; +} + +/* + * bool FOO!=n => FOO + */ +struct expr *trans_bool_expr(struct expr *e) +{ + if (!e) + return NULL; + switch (e->token) { + case T_AND: + case T_OR: + case '!': + e->left.expr = trans_bool_expr(e->left.expr); + e->right.expr = trans_bool_expr(e->right.expr); + break; + case T_UNEQUAL: + // FOO!=n -> FOO + if (e->left.sym->type == SYMBOL_TRISTATE) { + if (e->right.sym == &symbol_no) { + e->token = T_WORD; + e->right.sym = NULL; + } + } + break; + } + return e; +} + +struct expr *fixup_expr(struct expr *e) +{ + struct expr *tmp; + + if (!e) + return NULL; + + switch (e->token) { + case T_IF: + // if expr if expr ... -> expr && expr ... + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, " -> "); + tmp = e->left.expr; + if (!e->right.expr) { + free(e); + e = fixup_expr(tmp); + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + return e; + } + e->left.expr = e->right.expr; + e->right.expr = tmp; + e->token = T_AND; + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + break; + case T_ELSE: + // if expr else expr ... -> expr && !expr ... + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, " -> "); + e->token = '!'; + if (!e->right.expr) { + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + break; + } + tmp = e; + e = expr_alloc_two(T_AND, e->right.expr, e); + tmp->right.expr = NULL; + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + break; + case '&': + // expr & expr -> expr && expr + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, " -> "); + e->token = T_AND; + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + break; + case '=': + case T_UNEQUAL: + if (!(e->left.sym->flags & SYMBOL_CONST)) + return e; + if (e->right.sym->flags & SYMBOL_CONST) { + if (e->left.sym == e->right.sym) { + e->left.sym = e->token == '=' ? &symbol_yes : &symbol_no; + } else { + e->left.sym = e->token != '=' ? &symbol_yes : &symbol_no; + } + e->token = T_WORD; + e->right.sym = NULL; + } else { + // y/n/m = sym -> sym = y/n/m + struct symbol *sym; + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, " -> "); + sym = e->left.sym; + e->left.sym = e->right.sym; + e->right.sym = sym; + print_expr(DEBUG_OPT1, e, 0); + printd(DEBUG_OPT1, "\n"); + } + return e; + case T_WORD: + case '^': + return e; + } + e->left.expr = fixup_expr(e->left.expr); + e->right.expr = fixup_expr(e->right.expr); + return e; +} + +struct 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->token != '=' && e1->token != T_UNEQUAL && e1->token != T_WORD && e1->token != '!') + return NULL; + if (e2->token != '=' && e2->token != T_UNEQUAL && e2->token != T_WORD && e2->token != '!') + return NULL; + if (e1->token == '!') { + tmp = e1->left.expr; + if (tmp->token != '=' && tmp->token != T_UNEQUAL && tmp->token != T_WORD) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->token == '!') { + if (e2->left.expr->token != T_WORD) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != SYMBOL_BOOLEAN && sym1->type != SYMBOL_TRISTATE) + return NULL; + if (sym1->type == SYMBOL_TRISTATE) { + if (e1->token == '=' && e2->token == '=' && + ((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(T_UNEQUAL, sym1, &symbol_no); + } + if (e1->token == '=' && e2->token == '=' && + ((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(T_UNEQUAL, sym1, &symbol_mod); + } + if (e1->token == '=' && e2->token == '=' && + ((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(T_UNEQUAL, sym1, &symbol_yes); + } + } + if (sym1->type == SYMBOL_BOOLEAN && sym1 == sym2) { + if ((e1->token == '!' && e1->left.expr->token == T_WORD && e2->token == T_WORD) || + (e2->token == '!' && e2->left.expr->token == T_WORD && e1->token == T_WORD)) + return expr_alloc_symbol(&symbol_yes); + } + + printf("optimize "); + print_expr(PRINTD, e1, 0); + printf(" || "); + print_expr(PRINTD, e2, 0); + printf(" ?\n"); + return NULL; +} + +struct 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->token != '=' && e1->token != T_UNEQUAL && e1->token != T_WORD && e1->token != '!') + return NULL; + if (e2->token != '=' && e2->token != T_UNEQUAL && e2->token != T_WORD && e2->token != '!') + return NULL; + if (e1->token == '!') { + tmp = e1->left.expr; + if (tmp->token != '=' && tmp->token != T_UNEQUAL && tmp->token != T_WORD) + return NULL; + sym1 = tmp->left.sym; + } else + sym1 = e1->left.sym; + if (e2->token == '!') { + if (e2->left.expr->token != T_WORD) + return NULL; + sym2 = e2->left.expr->left.sym; + } else + sym2 = e2->left.sym; + if (sym1 != sym2) + return NULL; + if (sym1->type != SYMBOL_BOOLEAN && sym1->type != SYMBOL_TRISTATE) + return NULL; + + if ((e1->token == T_WORD && e2->token == '=' && e2->right.sym == &symbol_yes) || + (e2->token == T_WORD && e1->token == '=' && e1->right.sym == &symbol_yes)) + // (a) && (a='y') -> (a='y') + return expr_alloc_comp('=', sym1, &symbol_yes); + + if ((e1->token == T_WORD && e2->token == T_UNEQUAL && e2->right.sym == &symbol_no) || + (e2->token == T_WORD && e1->token == T_UNEQUAL && e1->right.sym == &symbol_no)) + // (a) && (a!='n') -> (a) + return expr_alloc_symbol(sym1); + + if (sym1->type == SYMBOL_TRISTATE) { + if (e1->token == '=' && e2->token == T_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('=', sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->token == T_UNEQUAL && e2->token == '=') { + // (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('=', sym1, sym2) + : expr_alloc_symbol(&symbol_no); + } + if (e1->token == T_UNEQUAL && e2->token == T_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('=', sym1, &symbol_mod); + + if (e1->token == T_UNEQUAL && e2->token == T_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('=', sym1, &symbol_no); + + if (e1->token == T_UNEQUAL && e2->token == T_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('=', sym1, &symbol_yes); + + if ((e1->token == T_WORD && e2->token == '=' && e2->right.sym == &symbol_mod) || + (e2->token == T_WORD && e1->token == '=' && e1->right.sym == &symbol_mod) || + (e1->token == T_WORD && e2->token == T_UNEQUAL && e2->right.sym == &symbol_yes) || + (e2->token == T_WORD && e1->token == T_UNEQUAL && e1->right.sym == &symbol_yes)) + return NULL; + } + printf("optimize "); + print_expr(PRINTD, e1, 0); + printf(" && "); + print_expr(PRINTD, e2, 0); + printf(" ?\n"); + return NULL; +} + +void eliminate_dups1(int token, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp; + + if (e1->token == token) { + eliminate_dups1(token, &e1->left.expr, &e2); + eliminate_dups1(token, &e1->right.expr, &e2); + return; + } + if (e2->token == token) { + eliminate_dups1(token, &e1, &e2->left.expr); + eliminate_dups1(token, &e1, &e2->right.expr); + return; + } + if (e1 == e2) + return; + + switch (e1->token) { + case T_OR: case T_AND: + eliminate_dups1(e1->token, &e1, &e1); + } + + switch (token) { + case T_OR: + tmp = join_or(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_no); + e2 = tmp; + trans_count++; + } + break; + case T_AND: + tmp = join_and(e1, e2); + if (tmp) { + expr_free(e1); expr_free(e2); + e1 = expr_alloc_symbol(&symbol_yes); + e2 = tmp; + trans_count++; + } + break; + } +#undef e1 +#undef e2 +} + +void eliminate_dups2(int token, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + struct expr *tmp, *tmp1, *tmp2; + + if (e1->token == token) { + eliminate_dups2(token, &e1->left.expr, &e2); + eliminate_dups2(token, &e1->right.expr, &e2); + return; + } + if (e2->token == token) { + eliminate_dups2(token, &e1, &e2->left.expr); + eliminate_dups2(token, &e1, &e2->right.expr); + } + if (e1 == e2) + return; + + switch (e1->token) { + case T_OR: + eliminate_dups2(e1->token, &e1, &e1); + // (FOO || BAR) && (!FOO && !BAR) -> n + tmp1 = trans_expr(expr_alloc_one('!', expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = 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 T_AND: + eliminate_dups2(e1->token, &e1, &e1); + // (FOO && BAR) || (!FOO || !BAR) -> y + tmp1 = trans_expr(expr_alloc_one('!', expr_copy(e1))); + tmp2 = expr_copy(e2); + tmp = 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; + } +#undef e1 +#undef e2 +} + +struct expr *eliminate_dups(struct expr *e) +{ + int oldcount; + if (!e) + return e; + + oldcount = trans_count; + while (1) { + trans_count = 0; + switch (e->token) { + case T_OR: case T_AND: + eliminate_dups1(e->token, &e, &e); + eliminate_dups2(e->token, &e, &e); + } + if (!trans_count) + break; + e = eliminate_yn(e); + } + trans_count = oldcount; + return e; +} + +struct expr *eliminate_yn(struct expr *e) +{ + struct expr *tmp; + + if (e) switch (e->token) { + case T_AND: + e->left.expr = eliminate_yn(e->left.expr); + e->right.expr = eliminate_yn(e->right.expr); + if (e->left.expr->token == T_WORD) { + if (e->left.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->token = T_WORD; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } + } + if (e->right.expr->token == T_WORD) { + if (e->right.expr->left.sym == &symbol_no) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->token = T_WORD; + e->left.sym = &symbol_no; + e->right.expr = NULL; + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } + } + break; + case T_OR: + e->left.expr = eliminate_yn(e->left.expr); + e->right.expr = eliminate_yn(e->right.expr); + if (e->left.expr->token == T_WORD) { + if (e->left.expr->left.sym == &symbol_no) { + free(e->left.expr); + tmp = e->right.expr; + *e = *(e->right.expr); + free(tmp); + return e; + } else if (e->left.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->token = T_WORD; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + if (e->right.expr->token == T_WORD) { + if (e->right.expr->left.sym == &symbol_no) { + free(e->right.expr); + tmp = e->left.expr; + *e = *(e->left.expr); + free(tmp); + return e; + } else if (e->right.expr->left.sym == &symbol_yes) { + expr_free(e->left.expr); + expr_free(e->right.expr); + e->token = T_WORD; + e->left.sym = &symbol_yes; + e->right.expr = NULL; + return e; + } + } + break; + } + return e; +} + +struct expr *trans_expr(struct expr *e) +{ + struct expr *tmp; + + if (!e) + return NULL; + switch (e->token) { + case '=': + case T_UNEQUAL: + case T_WORD: + case '^': + break; + default: + e->left.expr = trans_expr(e->left.expr); + e->right.expr = trans_expr(e->right.expr); + } + + switch (e->token) { + case '=': + if (e->left.sym->type != SYMBOL_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + e->token = '!'; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); + e->token = T_WORD; + e->left.sym = &symbol_no; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + e->token = T_WORD; + e->right.sym = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + break; + case T_UNEQUAL: + if (e->left.sym->type != SYMBOL_BOOLEAN) + break; + if (e->right.sym == &symbol_no) { + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + e->token = T_WORD; + e->right.sym = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + if (e->right.sym == &symbol_mod) { + printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); + e->token = T_WORD; + e->left.sym = &symbol_yes; + e->right.sym = NULL; + break; + } + if (e->right.sym == &symbol_yes) { + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + e->token = '!'; + e->left.expr = expr_alloc_symbol(e->left.sym); + e->right.sym = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + break; + case '!': + switch (e->left.expr->token) { + case '!': + // !!a -> a + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr->left.expr; + free(e->left.expr); + free(e); + e = tmp; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + e = trans_expr(e); + break; + case '=': + case T_UNEQUAL: + // !a='x' -> a!='x' + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr; + free(e); + e = tmp; + if (e->token == '=') + e->token = T_UNEQUAL; + else + e->token = '='; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + case T_OR: + // !(a || b) -> !a && !b + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr; + e->token = T_AND; + e->right.expr = expr_alloc_one('!', tmp->right.expr); + tmp->token = '!'; + tmp->right.expr = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + e = trans_expr(e); + break; + case T_AND: + // !(a && b) -> !a || !b + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr; + e->token = T_OR; + e->right.expr = expr_alloc_one('!', tmp->right.expr); + tmp->token = '!'; + tmp->right.expr = NULL; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + e = trans_expr(e); + break; + case T_WORD: + if (e->left.expr->left.sym == &symbol_yes) { + // !'y' -> 'n' + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr; + free(e); + e = tmp; + e->token = T_WORD; + e->left.sym = &symbol_no; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + if (e->left.expr->left.sym == &symbol_no) { + // !'n' -> 'y' + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, " -> "); + tmp = e->left.expr; + free(e); + e = tmp; + e->token = T_WORD; + e->left.sym = &symbol_yes; + print_expr(DEBUG_OPT2, e, 0); + printd(DEBUG_OPT2, "\n"); + break; + } + break; + } + break; + } + return e; +} + +struct expr *extract_eq_and(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + extract_eq(T_AND, &tmp, ep1, ep2); + if (tmp) { + *ep1 = eliminate_yn(*ep1); + *ep2 = eliminate_yn(*ep2); + } + return tmp; +} + +struct expr *extract_eq_or(struct expr **ep1, struct expr **ep2) +{ + struct expr *tmp = NULL; + extract_eq(T_OR, &tmp, ep1, ep2); + if (tmp) { + *ep1 = eliminate_yn(*ep1); + *ep2 = eliminate_yn(*ep2); + } + return tmp; +} + +void extract_eq(int token, struct expr **ep, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) + if (e1->token == token) { + extract_eq(token, ep, &e1->left.expr, &e2); + extract_eq(token, ep, &e1->right.expr, &e2); + return; + } + if (e2->token == token) { + extract_eq(token, ep, ep1, &e2->left.expr); + extract_eq(token, ep, ep1, &e2->right.expr); + return; + } + if (expr_eq(e1, e2)) { + *ep = *ep ? expr_alloc_two(token, *ep, e1) : e1; + expr_free(e2); + if (token == T_AND) { + e1 = expr_alloc_symbol(&symbol_yes); + e2 = expr_alloc_symbol(&symbol_yes); + } else if (token == T_OR) { + e1 = expr_alloc_symbol(&symbol_no); + e2 = expr_alloc_symbol(&symbol_no); + } + } +#undef e1 +#undef e2 +} + +struct expr *optimize_expr_or(struct expr *e) +{ + struct expr *tmp; + + if (!e || e->token != T_OR) + return e; + + e->left.expr = optimize_expr_or(e->left.expr); + e->right.expr = optimize_expr_or(e->right.expr); + + tmp = extract_eq_and(&e->left.expr, &e->right.expr); + if (!tmp) + return e; + return expr_alloc_two(T_AND, tmp, e); +} + +int contains_expr(struct expr *dep, struct expr *e) +{ + if (!dep) + return 0; + if (dep->token == T_AND) + return contains_expr(dep->left.expr, e) || contains_expr(dep->right.expr, e); + return expr_eq(dep, e); +} + +struct expr *trans_comp_expr(struct expr *e, int token, struct symbol *sym) +{ + struct expr *e1, *e2; + + switch (e->token) { + case T_AND: + e1 = trans_comp_expr(e->left.expr, '=', sym); + e2 = trans_comp_expr(e->right.expr, '=', sym); + if (sym == &symbol_yes) + e = expr_alloc_two(T_AND, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(T_OR, e1, e2); + if (token == T_UNEQUAL) + e = expr_alloc_one('!', e); + return e; + case T_OR: + e1 = trans_comp_expr(e->left.expr, '=', sym); + e2 = trans_comp_expr(e->right.expr, '=', sym); + if (sym == &symbol_yes) + e = expr_alloc_two(T_OR, e1, e2); + if (sym == &symbol_no) + e = expr_alloc_two(T_AND, e1, e2); + if (token == T_UNEQUAL) + e = expr_alloc_one('!', e); + return e; + case '!': + switch (token) { + case '=': + return trans_comp_expr(e->left.expr, T_UNEQUAL, sym); + case T_UNEQUAL: + return trans_comp_expr(e->left.expr, '=', sym); + } + break; + case T_UNEQUAL: + case '=': + if (token == '=') { + 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('!', expr_copy(e)); + } else { + if (sym == &symbol_yes) + return expr_alloc_one('!', expr_copy(e)); + if (sym == &symbol_mod) + return expr_alloc_symbol(&symbol_yes); + if (sym == &symbol_no) + return expr_copy(e); + } + break; + case T_WORD: + return expr_alloc_comp(token, e->left.sym, sym); + } + return NULL; +} + +void eliminate_dep(struct symbol *sym, struct expr *dep) +{ + struct symbol *sym2; + struct expr *dep2; + + if (dep->token == T_AND) { + eliminate_dep(sym, dep->left.expr); + eliminate_dep(sym, dep->right.expr); + } +#if 0 + if (dep->token == T_WORD || + (sym->type == SYMBOL_BOOLEAN && + ((dep->token == T_UNEQUAL && dep->right.sym == &symbol_no) || + (dep->token == '=' && dep->right.sym == &symbol_yes)))) { + sym2 = dep->left.sym; + if (sym2->dep) { + if (!sym2->dep2) + eliminate_dep(sym2, sym2->dep); + sym->dep2 = !sym->dep2 ? expr_copy(sym2->dep2) + : expr_alloc_two(T_AND, expr_copy(sym2->dep2), sym->dep2); + } + } +#else + switch (dep->token) { + case T_WORD: + case T_UNEQUAL: + case '=': + sym2 = dep->left.sym; + if (sym2->type != SYMBOL_BOOLEAN && sym2->type != SYMBOL_TRISTATE) + break; + if (!sym2->dep) + break; + if (!sym2->dep2) + eliminate_dep(sym2, sym2->dep); + if (dep->token == T_WORD) { + if (sym2->type == SYMBOL_BOOLEAN) + dep2 = trans_comp_expr(sym2->dep2, T_UNEQUAL, &symbol_no); + else + dep2 = expr_copy(sym2->dep2); + } else { + //if ((dep->token == T_UNEQUAL && dep->right.sym == &symbol_no) || + // (sym2->type == SYMBOL_BOOLEAN && + // dep->token == '=' && dep->right.sym == &symbol_yes)) + if ((dep->token == '=' && dep->right.sym == &symbol_yes) || + (sym2->type == SYMBOL_BOOLEAN && + dep->token == T_UNEQUAL && dep->right.sym == &symbol_no)) + dep2 = trans_comp_expr(sym2->dep2, dep->token, dep->right.sym); + else + break; + } + dep2 = eliminate_yn(trans_expr(fixup_expr(dep2))); + sym->dep2 = !sym->dep2 ? dep2 : expr_alloc_two(T_AND, dep2, sym->dep2); + } +#endif + if (sym->dep == dep) { + printd(DEBUG_DEP, "el: %s (", sym->name); + print_expr(DEBUG_DEP, sym->dep, 0); + printd(DEBUG_DEP, ")\n"); + if (sym->dep2) { + print_expr(DEBUG_DEP, sym->dep2, 0); printd(DEBUG_DEP, "\n"); + sym->dep2 = eliminate_yn(eliminate_dups(sym->dep2)); + switch (sym->type) { + case SYMBOL_BOOLEAN: case SYMBOL_INT: case SYMBOL_HEX: case SYMBOL_STRING: + sym->dep2 = trans_bool_expr(sym->dep2); + break; + } + print_expr(DEBUG_DEP, sym->dep2, 0); printd(DEBUG_DEP, "\n"); + sym->dep = expr_alloc_two(T_AND, expr_copy(sym->dep2), sym->dep); + sym->dep = eliminate_dups(sym->dep); + print_expr(DEBUG_DEP, sym->dep, 0); printd(DEBUG_DEP, "\n"); + dep = expr_copy(sym->dep2); + eliminate_eq(T_AND, &dep, &sym->dep); + sym->dep = eliminate_yn(sym->dep); + sym->dep2 = expr_alloc_two(T_AND, sym->dep2, expr_copy(sym->dep)); + } else + sym->dep2 = expr_copy(sym->dep); + printd(DEBUG_DEP, " -> "); + print_expr(DEBUG_DEP, sym->dep2, 0); + printd(DEBUG_DEP, " -> "); + print_expr(DEBUG_DEP, sym->dep, 0); + printd(DEBUG_DEP, "\n"); + } +} + +struct symbol * dep_check_symbol(struct symbol *sym); + +struct symbol *dep_check_expr(struct expr *e) +{ + struct symbol *sym; + if (!e) + return 0; + switch (e->token) { + case T_WORD: + case T_WORD_QUOTE: + case T_WORD_DQUOTE: + return dep_check_symbol(e->left.sym); + case '=': + case T_UNEQUAL: + sym = dep_check_symbol(e->left.sym); + if (sym) + return sym; + return dep_check_symbol(e->right.sym); + case T_OR: + case T_AND: + sym = dep_check_expr(e->left.expr); + if (sym) + return sym; + return dep_check_expr(e->right.expr); + case '!': + return dep_check_expr(e->left.expr); + } + printf("how to check %d?\n", e->token); + return NULL; +} + +struct symbol *dep_check_symbol(struct symbol *sym) +{ + struct statement *stmt, *stmt2; + struct symbol *sym2; + struct expr *e1, *e2; + + if (sym->flags & SYMBOL_CHECK) { + printf("recursive dependency: %s", sym->name); + return sym; + } + + sym->flags |= SYMBOL_CHECK; + sym2 = dep_check_expr(sym->dep); + if (sym2) { + printf(" %s", sym->name); + if (sym->type != sym2->type) + goto out; + switch (sym->type) { + case SYMBOL_TRISTATE: + e1 = expr_alloc_comp(T_UNEQUAL, sym, &symbol_yes); + e2 = expr_alloc_comp(T_UNEQUAL, sym2, &symbol_yes); + break; + case SYMBOL_BOOLEAN: + e1 = expr_alloc_one('!', expr_alloc_symbol(sym)); + e2 = expr_alloc_one('!', expr_alloc_symbol(sym2)); + break; + default: + goto out; + } + if (contains_expr(sym->dep, e2) && contains_expr(sym2->dep, e1)) { + printf(" (choice(%d) detected)", sym->type); + sym->flags |= SYMBOL_CHOICE; + eliminate_eq(T_AND, &sym->dep, &e2); + sym->dep = eliminate_yn(sym->dep); + sym2->flags |= SYMBOL_CHOICE; + eliminate_eq(T_AND, &sym2->dep, &e1); + sym2->dep = eliminate_yn(sym2->dep); + stmt = malloc(sizeof(*stmt)); + memset(stmt, 0, sizeof(*stmt)); + stmt->token = '^'; + stmt->text = "change me!"; + stmt->dep = expr_alloc_one('^', NULL); + stmt->dep->right.sym = sym; + stmt->dep = expr_alloc_one('^', stmt->dep); + stmt->dep->right.sym = sym2; + stmt->dep = expr_alloc_one('^', stmt->dep); + stmt->dep->right.sym = &symbol_no; + for (stmt2 = sym->stmt; stmt2->next; stmt2 = stmt2->next) + ; + if (stmt2->token == '^') + printf("warning: symbol %s has dup choice statement?\n", sym->name); + else + stmt2->next = stmt; + for (stmt2 = sym2->stmt; stmt2->next; stmt2 = stmt2->next) + ; + if (stmt2->token == '^') + printf("warning: symbol %s has dup choice statement?\n", sym->name); + else + stmt2->next = stmt; + } + expr_free(e1); + expr_free(e2); + } + if (!sym2) for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (!stmt->token || stmt->token == '^') + continue; + sym2 = dep_check_expr(stmt->dep); + if (sym2) { + printf(" %s", sym->name); + break; + } + } +out: + sym->flags &= ~SYMBOL_CHECK; + + return sym2; +} + +const char *sym_typename(int type) +{ + switch (type) { + case SYMBOL_UNKNOWN: return "unknown"; + case SYMBOL_BOOLEAN: return "bool"; + case SYMBOL_TRISTATE: return "tristate"; + case SYMBOL_INT: return "integer"; + case SYMBOL_HEX: return "hex"; + case SYMBOL_STRING: return "string"; + case SYMBOL_OTHER: return "other"; + default: return "???"; + } +} + +void optimize_config(void) +{ + struct symbol *sym; + struct statement *stmt, *stmt2, **stmtp; + struct expr *e; + int i; + + for_all_symbols(i, sym) { + again: + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + switch (stmt->token) { + case '^': + case T_BOOL: + case T_DEP_BOOL: + case T_DEP_MBOOL: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_BOOLEAN; + if (sym->type != SYMBOL_BOOLEAN) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_BOOLEAN)); + if (sym->type == SYMBOL_TRISTATE) { + printf("%s:%d:Force stmt to dep_tristate\n", + stmt->file->name, stmt->lineno); + stmt->token = T_DEP_TRISTATE; + } + break; + case T_DEFINE_BOOL: + if (stmt->def == &symbol_mod) { + printf("%s:%d:warning: symbol %s set to 'm', force stmt to define_tristate\n", + stmt->file->name, stmt->lineno, sym->name); + stmt->token = T_DEFINE_TRISTATE; + } + break; + case T_HEX: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_HEX; + if (sym->type != SYMBOL_HEX) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_HEX)); + break; + case T_INT: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_INT; + if (sym->type != SYMBOL_INT) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_INT)); + break; + case T_STRING: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_STRING; + if (sym->type != SYMBOL_STRING) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_STRING)); + break; + case T_TRISTATE: + case T_DEP_TRISTATE: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_TRISTATE; + if (sym->type != SYMBOL_TRISTATE) { + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s), force symbol to tristate\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_TRISTATE)); + sym->type = SYMBOL_TRISTATE; + goto again; + } + break; + } + } + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + switch (stmt->token) { + case T_DEFINE_BOOL: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_BOOLEAN; + if (sym->type != SYMBOL_BOOLEAN) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_BOOLEAN)); + if (sym->type == SYMBOL_TRISTATE) { + printf("%s:%d:Force stmt to define_tristate\n", + stmt->file->name, stmt->lineno); + stmt->token = T_DEFINE_TRISTATE; + } + break; + case T_DEFINE_TRISTATE: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_TRISTATE; + if (sym->type != SYMBOL_TRISTATE) { + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s), force symbol to tristate\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_TRISTATE)); + sym->type = SYMBOL_TRISTATE; + goto again; + } + break; + case T_DEFINE_HEX: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_HEX; + if (sym->type != SYMBOL_HEX) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_HEX)); + break; + case T_DEFINE_INT: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_INT; + if (sym->type != SYMBOL_INT) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_INT)); + break; + case T_DEFINE_STRING: + if (sym->type == SYMBOL_UNKNOWN) + sym->type = SYMBOL_STRING; + if (sym->type != SYMBOL_STRING) + printf("%s:%d:warning: symbol %s has conflicting types (%s,%s)\n", + stmt->file->name, stmt->lineno, sym->name, + sym_typename(sym->type), sym_typename(SYMBOL_STRING)); + break; + } + } + } + for_all_symbols(i, sym) { + printd(DEBUG_OPT1, "o1: %s\n", sym->name); + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + print_expr(DEBUG_OPT1, stmt->dep, 0); + printd(DEBUG_OPT1, " & "); + print_expr(DEBUG_OPT1, stmt->dep2, 0); + printd(DEBUG_OPT1, "\n"); + if (stmt->dep || stmt->dep2) { + struct expr *e = stmt->dep2; + if (stmt->token == T_DEP_BOOL) { + e = trans_dep_bool(e); + stmt->token = T_DEP_MBOOL; + } + if (stmt->dep && e) { + stmt->dep = expr_alloc_two(T_AND, stmt->dep, e); + } else if (e) + stmt->dep = e; + stmt->dep2 = NULL; + switch (stmt->token) { + case T_DEP_MBOOL: stmt->token = T_BOOL; break; + case T_DEP_TRISTATE: stmt->token = T_TRISTATE; break; + } + } + stmt->dep = fixup_expr(stmt->dep); + print_expr(DEBUG_OPT1, stmt->dep, 0); + printd(DEBUG_OPT1, "\n"); + } + } + for_all_symbols(i, sym) { + printd(DEBUG_OPT3, "o3: %s\n", sym->name); + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + print_expr(DEBUG_OPT3, stmt->dep, 0); + printd(DEBUG_OPT3, "\n"); + stmt->dep = eliminate_dups(trans_expr(stmt->dep)); + switch (sym->type) { + case SYMBOL_BOOLEAN: case SYMBOL_INT: case SYMBOL_HEX: case SYMBOL_STRING: + stmt->dep = trans_bool_expr(stmt->dep); + break; + } + print_expr(DEBUG_OPT3, stmt->dep, 0); + printd(DEBUG_OPT3, "\n"); + } + } + for_all_symbols(i, sym) { + sym->dep = eliminate_yn(sym->dep); + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + stmt->dep = eliminate_yn(stmt->dep); + if (expr_is_no(stmt->dep)) { + printf("%s:%d: stmt can never be reached, removed!\n", stmt->file->name, stmt->lineno); + stmt->token = 0; + } + } + } + for_all_symbols(i, sym) { + stmtp = &sym->stmt; + stmt = *stmtp; + if (!stmt) { + printf("undefined symbol %s\n", sym->name); + continue; + } + //if (sym->flags & SYMBOL_CHOICE) + // continue; + while (stmt) { + if (!stmt->token || stmt->token == '^') { + stmtp = &stmt->next; + stmt = *stmtp; + continue; + } +#if 1 + if ((stmt->token == T_DEFINE_BOOL || stmt->token == T_DEFINE_TRISTATE) && + (stmt->def == &symbol_no || expr_is_no(stmt->dep))) { + stmt->token = 0; + stmt->def = NULL; + expr_free(stmt->dep); + stmt->dep = NULL; + continue; + } +#endif + //if (stmt->text && stmt != sym->stmt) { + // if (sym->stmt->text) + // printf("warning: another stmt with prompt for %s????\n", sym->name); + // *stmtp = stmt->next; + // stmt->next = sym->stmt; + // sym->stmt = stmt; + //} + for (stmt2 = stmt->next; stmt2; stmt2 = stmt2->next) { + if (stmt->token != stmt2->token || stmt->def != stmt2->def || + stmt->menu->parent != stmt2->menu->parent) + continue; + if (stmt->text) { + if (strcmp(skip_space(stmt->text), skip_space(stmt2->text))) { + printf("warning: prompts differ for %s?\n", sym->name); + continue; + } + } + if (!stmt->dep) + stmt->dep = expr_alloc_symbol(&symbol_yes); + if (!stmt2->dep) + stmt2->dep = expr_alloc_symbol(&symbol_yes); + stmt->dep = optimize_expr_or(expr_alloc_two(T_OR, stmt->dep, stmt2->dep)); + stmt2->token = 0; + free((void *)stmt2->text); + stmt2->text = NULL; + stmt2->def = NULL; + stmt2->dep = NULL; + } + if (stmt->text && stmt != sym->stmt) { + *stmtp = stmt->next; + stmt->next = sym->stmt; + sym->stmt = stmt; + } else + stmtp = &stmt->next; + stmt = *stmtp; + } + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + if (!stmt->token || stmt->token == '^') + continue; + if (!sym->dep) { + if (!stmt->dep) + break; + sym->dep = stmt->dep; + stmt->dep = NULL; + } else { + e = sym->dep; + if (stmt->dep) { + sym->dep = extract_eq_and(&e, &stmt->dep); + if (expr_is_yes(e)) { + expr_free(e); + continue; + } + } else + sym->dep = NULL; + for (stmt2 = sym->stmt; stmt != stmt2; stmt2 = stmt2->next) { + if (!stmt2->token || stmt2->token == '^') + continue; + stmt2->dep = !stmt2->dep ? expr_copy(e) : + expr_alloc_two(T_AND, expr_copy(e), stmt2->dep); + } + expr_free(e); + if (!sym->dep) + break; + } + } +#if 0 + for (stmt1 = sym->stmt; stmt1; stmt1 = stmt1->next) + if (stmt1->token && stmt1->token != '^') + break; + if (stmt1 && !expr_is_yes(stmt1->dep)) { + e = trans_expr(expr_alloc_one('!', stmt1->dep)); + stmt1->dep = NULL; + for (stmt = stmt1->next; stmt; stmt = stmt->next) { + if (!stmt->token || stmt->token == '^') + continue; + if (stmt->dep) { + tmp = extract_eq_and(&e, &stmt->dep); + if (expr_is_yes(e)) { + expr_free(e); + e = tmp; + continue; + } + if (tmp) { + e = expr_alloc_two(T_AND, expr_copy(tmp), e); + stmt->dep = expr_alloc_two(T_AND, tmp, stmt->dep); + } + } + for (stmt2 = stmt1->next; stmt != stmt2; stmt2 = stmt2->next) { + if (!stmt2->token || stmt2->token == '^') + continue; + stmt2->dep = !stmt2->dep ? expr_copy(e) : + expr_alloc_two(T_AND, expr_copy(e), stmt2->dep); + } + stmt1->dep = trans_expr(expr_alloc_one('!', e)); + break; + } + if (!stmt1->dep) { + e = trans_expr(expr_alloc_one('!', e)); + //sym->dep = sym->dep ? expr_alloc_two(T_AND, sym->dep, e) : e; + stmt1->dep = e; + } + } + for (stmtp = &sym->stmt; *stmtp; stmtp = &stmt->next) { + stmt = *stmtp; + if (!stmt->token || stmt->token == '^') + continue; + if (!stmt->dep || stmt->text) + continue; + for (stmt2 = stmt->next; stmt2; stmt2 = stmt2->next) { + trans_count = 0; + if (!stmt2->dep || stmt2->text) + continue; + e = trans_expr(expr_alloc_one('!', expr_copy(stmt->dep))); + tmp = extract_eq_and(&e, &stmt2->dep); + if (expr_is_yes(e)) { + expr_free(e); + expr_free(tmp); + continue; + } + if (tmp) + stmt2->dep = expr_alloc_two(T_AND, tmp, stmt2->dep); + e = trans_expr(expr_alloc_one('!', expr_copy(stmt2->dep))); + tmp = extract_eq_and(&e, &stmt->dep); + if (expr_is_yes(e)) { + expr_free(e); + expr_free(tmp); + while (stmt->next != stmt2) + stmt = stmt->next; + stmt->next = *stmtp; + *stmtp = stmt2; + stmt = stmt->next; + stmt2 = stmt->next; + stmt->next = (*stmtp)->next; + (*stmtp)->next = stmt2; + continue; + } + if (tmp) + stmt->dep = expr_alloc_two(T_AND, tmp, stmt->dep); + } + } +#endif + } + for_all_symbols(i, sym) { + printd(DEBUG_OPT4, "o4: %s\n", sym->name); + print_expr(DEBUG_OPT4, sym->dep, 0); printd(DEBUG_OPT4, "\n"); + sym->dep = eliminate_dups(sym->dep); + sym->dep = eliminate_yn(sym->dep); + print_expr(DEBUG_OPT4, sym->dep, 0); printd(DEBUG_OPT4, "\n"); + for (stmt = sym->stmt; stmt; stmt = stmt->next) { + print_expr(DEBUG_OPT4, stmt->dep, 0); printd(DEBUG_OPT4, "\n"); + stmt->dep = eliminate_dups(stmt->dep); + stmt->dep = eliminate_yn(stmt->dep); + print_expr(DEBUG_OPT4, stmt->dep, 0); printd(DEBUG_OPT4, "\n"); + } + } + for_all_symbols(i, sym) { + if (dep_check_symbol(sym)) + printf("\n"); + } + for_all_symbols(i, sym) { + if (sym->dep && !sym->dep2) { + printd(DEBUG_OPT5, "o5: %s\n", sym->name); + print_expr(DEBUG_OPT5, sym->dep, 0); printd(DEBUG_OPT5, "\n"); + eliminate_dep(sym, sym->dep); + print_expr(DEBUG_OPT5, sym->dep, 0); printd(DEBUG_OPT5, "\n"); + } + } +} + +int main(int ac, char **av) +{ + FILE *out = NULL; + char name[128]; + struct symbol *sym; + struct statement *stmt; + + if (ac > 2) + cml1debug = 1; + helplex("Documentation/Configure.help"); + sprintf(name, "arch/%s/Config.help", av[1]); + helplex(name); + sprintf(name, "arch/%s/config.in", av[1]); + scan_init(name); + sym = lookup_symbol("CONFIG_ARCH", SYMBOL_STRING); + stmt = add_stmt(sym, T_DEFINE_STRING, NULL, lookup_symbol(av[1], SYMBOL_OTHER)); + stmt->menu = NULL; + cml1parse(); + optimize_config(); +#if 0 + out = fopen("config.new", "w"); + if (!out) { + printf("unable to open config.new!\n"); + exit(1); + } +#endif + print_files(out, name); + + return 0; +} |