18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <ctype.h> 78c2ecf20Sopenharmony_ci#include <errno.h> 88c2ecf20Sopenharmony_ci#include <stdio.h> 98c2ecf20Sopenharmony_ci#include <stdlib.h> 108c2ecf20Sopenharmony_ci#include <string.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "lkc.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define DEBUG_EXPR 0 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic struct expr *expr_eliminate_yn(struct expr *e); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct expr *expr_alloc_symbol(struct symbol *sym) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci struct expr *e = xcalloc(1, sizeof(*e)); 218c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 228c2ecf20Sopenharmony_ci e->left.sym = sym; 238c2ecf20Sopenharmony_ci return e; 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct expr *expr_alloc_one(enum expr_type type, struct expr *ce) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct expr *e = xcalloc(1, sizeof(*e)); 298c2ecf20Sopenharmony_ci e->type = type; 308c2ecf20Sopenharmony_ci e->left.expr = ce; 318c2ecf20Sopenharmony_ci return e; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct expr *e = xcalloc(1, sizeof(*e)); 378c2ecf20Sopenharmony_ci e->type = type; 388c2ecf20Sopenharmony_ci e->left.expr = e1; 398c2ecf20Sopenharmony_ci e->right.expr = e2; 408c2ecf20Sopenharmony_ci return e; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct expr *e = xcalloc(1, sizeof(*e)); 468c2ecf20Sopenharmony_ci e->type = type; 478c2ecf20Sopenharmony_ci e->left.sym = s1; 488c2ecf20Sopenharmony_ci e->right.sym = s2; 498c2ecf20Sopenharmony_ci return e; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct expr *expr_alloc_and(struct expr *e1, struct expr *e2) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (!e1) 558c2ecf20Sopenharmony_ci return e2; 568c2ecf20Sopenharmony_ci return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct expr *expr_alloc_or(struct expr *e1, struct expr *e2) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci if (!e1) 628c2ecf20Sopenharmony_ci return e2; 638c2ecf20Sopenharmony_ci return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct expr *expr_copy(const struct expr *org) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct expr *e; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!org) 718c2ecf20Sopenharmony_ci return NULL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci e = xmalloc(sizeof(*org)); 748c2ecf20Sopenharmony_ci memcpy(e, org, sizeof(*org)); 758c2ecf20Sopenharmony_ci switch (org->type) { 768c2ecf20Sopenharmony_ci case E_SYMBOL: 778c2ecf20Sopenharmony_ci e->left = org->left; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case E_NOT: 808c2ecf20Sopenharmony_ci e->left.expr = expr_copy(org->left.expr); 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci case E_EQUAL: 838c2ecf20Sopenharmony_ci case E_GEQ: 848c2ecf20Sopenharmony_ci case E_GTH: 858c2ecf20Sopenharmony_ci case E_LEQ: 868c2ecf20Sopenharmony_ci case E_LTH: 878c2ecf20Sopenharmony_ci case E_UNEQUAL: 888c2ecf20Sopenharmony_ci e->left.sym = org->left.sym; 898c2ecf20Sopenharmony_ci e->right.sym = org->right.sym; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case E_AND: 928c2ecf20Sopenharmony_ci case E_OR: 938c2ecf20Sopenharmony_ci case E_LIST: 948c2ecf20Sopenharmony_ci e->left.expr = expr_copy(org->left.expr); 958c2ecf20Sopenharmony_ci e->right.expr = expr_copy(org->right.expr); 968c2ecf20Sopenharmony_ci break; 978c2ecf20Sopenharmony_ci default: 988c2ecf20Sopenharmony_ci fprintf(stderr, "can't copy type %d\n", e->type); 998c2ecf20Sopenharmony_ci free(e); 1008c2ecf20Sopenharmony_ci e = NULL; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return e; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_civoid expr_free(struct expr *e) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (!e) 1108c2ecf20Sopenharmony_ci return; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci switch (e->type) { 1138c2ecf20Sopenharmony_ci case E_SYMBOL: 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case E_NOT: 1168c2ecf20Sopenharmony_ci expr_free(e->left.expr); 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case E_EQUAL: 1198c2ecf20Sopenharmony_ci case E_GEQ: 1208c2ecf20Sopenharmony_ci case E_GTH: 1218c2ecf20Sopenharmony_ci case E_LEQ: 1228c2ecf20Sopenharmony_ci case E_LTH: 1238c2ecf20Sopenharmony_ci case E_UNEQUAL: 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case E_OR: 1268c2ecf20Sopenharmony_ci case E_AND: 1278c2ecf20Sopenharmony_ci expr_free(e->left.expr); 1288c2ecf20Sopenharmony_ci expr_free(e->right.expr); 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci default: 1318c2ecf20Sopenharmony_ci fprintf(stderr, "how to free type %d?\n", e->type); 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci free(e); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic int trans_count; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci#define e1 (*ep1) 1408c2ecf20Sopenharmony_ci#define e2 (*ep2) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* 1438c2ecf20Sopenharmony_ci * expr_eliminate_eq() helper. 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does 1468c2ecf20Sopenharmony_ci * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared 1478c2ecf20Sopenharmony_ci * against all other leaves. Two equal leaves are both replaced with either 'y' 1488c2ecf20Sopenharmony_ci * or 'n' as appropriate for 'type', to be eliminated later. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci /* Recurse down to leaves */ 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (e1->type == type) { 1558c2ecf20Sopenharmony_ci __expr_eliminate_eq(type, &e1->left.expr, &e2); 1568c2ecf20Sopenharmony_ci __expr_eliminate_eq(type, &e1->right.expr, &e2); 1578c2ecf20Sopenharmony_ci return; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci if (e2->type == type) { 1608c2ecf20Sopenharmony_ci __expr_eliminate_eq(type, &e1, &e2->left.expr); 1618c2ecf20Sopenharmony_ci __expr_eliminate_eq(type, &e1, &e2->right.expr); 1628c2ecf20Sopenharmony_ci return; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* e1 and e2 are leaves. Compare them. */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && 1688c2ecf20Sopenharmony_ci e1->left.sym == e2->left.sym && 1698c2ecf20Sopenharmony_ci (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci if (!expr_eq(e1, e2)) 1728c2ecf20Sopenharmony_ci return; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* e1 and e2 are equal leaves. Prepare them for elimination. */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci trans_count++; 1778c2ecf20Sopenharmony_ci expr_free(e1); expr_free(e2); 1788c2ecf20Sopenharmony_ci switch (type) { 1798c2ecf20Sopenharmony_ci case E_OR: 1808c2ecf20Sopenharmony_ci e1 = expr_alloc_symbol(&symbol_no); 1818c2ecf20Sopenharmony_ci e2 = expr_alloc_symbol(&symbol_no); 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case E_AND: 1848c2ecf20Sopenharmony_ci e1 = expr_alloc_symbol(&symbol_yes); 1858c2ecf20Sopenharmony_ci e2 = expr_alloc_symbol(&symbol_yes); 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci default: 1888c2ecf20Sopenharmony_ci ; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both. 1948c2ecf20Sopenharmony_ci * Example reductions: 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * ep1: A && B -> ep1: y 1978c2ecf20Sopenharmony_ci * ep2: A && B && C -> ep2: C 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * ep1: A || B -> ep1: n 2008c2ecf20Sopenharmony_ci * ep2: A || B || C -> ep2: C 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * ep1: A && (B && FOO) -> ep1: FOO 2038c2ecf20Sopenharmony_ci * ep2: (BAR && B) && A -> ep2: BAR 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * ep1: A && (B || C) -> ep1: y 2068c2ecf20Sopenharmony_ci * ep2: (C || B) && A -> ep2: y 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Comparisons are done between all operands at the same "level" of && or ||. 2098c2ecf20Sopenharmony_ci * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the 2108c2ecf20Sopenharmony_ci * following operands will be compared: 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * - 'e1', 'e2 || e3', and 'e4 || e5', against each other 2138c2ecf20Sopenharmony_ci * - e2 against e3 2148c2ecf20Sopenharmony_ci * - e4 against e5 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and 2178c2ecf20Sopenharmony_ci * '(e1 && e2) && e3' are both a single level. 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci * See __expr_eliminate_eq() as well. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_civoid expr_eliminate_eq(struct expr **ep1, struct expr **ep2) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci if (!e1 || !e2) 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci switch (e1->type) { 2268c2ecf20Sopenharmony_ci case E_OR: 2278c2ecf20Sopenharmony_ci case E_AND: 2288c2ecf20Sopenharmony_ci __expr_eliminate_eq(e1->type, ep1, ep2); 2298c2ecf20Sopenharmony_ci default: 2308c2ecf20Sopenharmony_ci ; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci if (e1->type != e2->type) switch (e2->type) { 2338c2ecf20Sopenharmony_ci case E_OR: 2348c2ecf20Sopenharmony_ci case E_AND: 2358c2ecf20Sopenharmony_ci __expr_eliminate_eq(e2->type, ep1, ep2); 2368c2ecf20Sopenharmony_ci default: 2378c2ecf20Sopenharmony_ci ; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci e1 = expr_eliminate_yn(e1); 2408c2ecf20Sopenharmony_ci e2 = expr_eliminate_yn(e2); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci#undef e1 2448c2ecf20Sopenharmony_ci#undef e2 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* 2478c2ecf20Sopenharmony_ci * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two 2488c2ecf20Sopenharmony_ci * &&/|| expressions are considered equal if every operand in one expression 2498c2ecf20Sopenharmony_ci * equals some operand in the other (operands do not need to appear in the same 2508c2ecf20Sopenharmony_ci * order), recursively. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ciint expr_eq(struct expr *e1, struct expr *e2) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci int res, old_count; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * A NULL expr is taken to be yes, but there's also a different way to 2588c2ecf20Sopenharmony_ci * represent yes. expr_is_yes() checks for either representation. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci if (!e1 || !e2) 2618c2ecf20Sopenharmony_ci return expr_is_yes(e1) && expr_is_yes(e2); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (e1->type != e2->type) 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci switch (e1->type) { 2668c2ecf20Sopenharmony_ci case E_EQUAL: 2678c2ecf20Sopenharmony_ci case E_GEQ: 2688c2ecf20Sopenharmony_ci case E_GTH: 2698c2ecf20Sopenharmony_ci case E_LEQ: 2708c2ecf20Sopenharmony_ci case E_LTH: 2718c2ecf20Sopenharmony_ci case E_UNEQUAL: 2728c2ecf20Sopenharmony_ci return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; 2738c2ecf20Sopenharmony_ci case E_SYMBOL: 2748c2ecf20Sopenharmony_ci return e1->left.sym == e2->left.sym; 2758c2ecf20Sopenharmony_ci case E_NOT: 2768c2ecf20Sopenharmony_ci return expr_eq(e1->left.expr, e2->left.expr); 2778c2ecf20Sopenharmony_ci case E_AND: 2788c2ecf20Sopenharmony_ci case E_OR: 2798c2ecf20Sopenharmony_ci e1 = expr_copy(e1); 2808c2ecf20Sopenharmony_ci e2 = expr_copy(e2); 2818c2ecf20Sopenharmony_ci old_count = trans_count; 2828c2ecf20Sopenharmony_ci expr_eliminate_eq(&e1, &e2); 2838c2ecf20Sopenharmony_ci res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && 2848c2ecf20Sopenharmony_ci e1->left.sym == e2->left.sym); 2858c2ecf20Sopenharmony_ci expr_free(e1); 2868c2ecf20Sopenharmony_ci expr_free(e2); 2878c2ecf20Sopenharmony_ci trans_count = old_count; 2888c2ecf20Sopenharmony_ci return res; 2898c2ecf20Sopenharmony_ci case E_LIST: 2908c2ecf20Sopenharmony_ci case E_RANGE: 2918c2ecf20Sopenharmony_ci case E_NONE: 2928c2ecf20Sopenharmony_ci /* panic */; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (DEBUG_EXPR) { 2968c2ecf20Sopenharmony_ci expr_fprint(e1, stdout); 2978c2ecf20Sopenharmony_ci printf(" = "); 2988c2ecf20Sopenharmony_ci expr_fprint(e2, stdout); 2998c2ecf20Sopenharmony_ci printf(" ?\n"); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * Recursively performs the following simplifications in-place (as well as the 3078c2ecf20Sopenharmony_ci * corresponding simplifications with swapped operands): 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * expr && n -> n 3108c2ecf20Sopenharmony_ci * expr && y -> expr 3118c2ecf20Sopenharmony_ci * expr || n -> expr 3128c2ecf20Sopenharmony_ci * expr || y -> y 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * Returns the optimized expression. 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistatic struct expr *expr_eliminate_yn(struct expr *e) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct expr *tmp; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (e) switch (e->type) { 3218c2ecf20Sopenharmony_ci case E_AND: 3228c2ecf20Sopenharmony_ci e->left.expr = expr_eliminate_yn(e->left.expr); 3238c2ecf20Sopenharmony_ci e->right.expr = expr_eliminate_yn(e->right.expr); 3248c2ecf20Sopenharmony_ci if (e->left.expr->type == E_SYMBOL) { 3258c2ecf20Sopenharmony_ci if (e->left.expr->left.sym == &symbol_no) { 3268c2ecf20Sopenharmony_ci expr_free(e->left.expr); 3278c2ecf20Sopenharmony_ci expr_free(e->right.expr); 3288c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 3298c2ecf20Sopenharmony_ci e->left.sym = &symbol_no; 3308c2ecf20Sopenharmony_ci e->right.expr = NULL; 3318c2ecf20Sopenharmony_ci return e; 3328c2ecf20Sopenharmony_ci } else if (e->left.expr->left.sym == &symbol_yes) { 3338c2ecf20Sopenharmony_ci free(e->left.expr); 3348c2ecf20Sopenharmony_ci tmp = e->right.expr; 3358c2ecf20Sopenharmony_ci *e = *(e->right.expr); 3368c2ecf20Sopenharmony_ci free(tmp); 3378c2ecf20Sopenharmony_ci return e; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci if (e->right.expr->type == E_SYMBOL) { 3418c2ecf20Sopenharmony_ci if (e->right.expr->left.sym == &symbol_no) { 3428c2ecf20Sopenharmony_ci expr_free(e->left.expr); 3438c2ecf20Sopenharmony_ci expr_free(e->right.expr); 3448c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 3458c2ecf20Sopenharmony_ci e->left.sym = &symbol_no; 3468c2ecf20Sopenharmony_ci e->right.expr = NULL; 3478c2ecf20Sopenharmony_ci return e; 3488c2ecf20Sopenharmony_ci } else if (e->right.expr->left.sym == &symbol_yes) { 3498c2ecf20Sopenharmony_ci free(e->right.expr); 3508c2ecf20Sopenharmony_ci tmp = e->left.expr; 3518c2ecf20Sopenharmony_ci *e = *(e->left.expr); 3528c2ecf20Sopenharmony_ci free(tmp); 3538c2ecf20Sopenharmony_ci return e; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci case E_OR: 3588c2ecf20Sopenharmony_ci e->left.expr = expr_eliminate_yn(e->left.expr); 3598c2ecf20Sopenharmony_ci e->right.expr = expr_eliminate_yn(e->right.expr); 3608c2ecf20Sopenharmony_ci if (e->left.expr->type == E_SYMBOL) { 3618c2ecf20Sopenharmony_ci if (e->left.expr->left.sym == &symbol_no) { 3628c2ecf20Sopenharmony_ci free(e->left.expr); 3638c2ecf20Sopenharmony_ci tmp = e->right.expr; 3648c2ecf20Sopenharmony_ci *e = *(e->right.expr); 3658c2ecf20Sopenharmony_ci free(tmp); 3668c2ecf20Sopenharmony_ci return e; 3678c2ecf20Sopenharmony_ci } else if (e->left.expr->left.sym == &symbol_yes) { 3688c2ecf20Sopenharmony_ci expr_free(e->left.expr); 3698c2ecf20Sopenharmony_ci expr_free(e->right.expr); 3708c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 3718c2ecf20Sopenharmony_ci e->left.sym = &symbol_yes; 3728c2ecf20Sopenharmony_ci e->right.expr = NULL; 3738c2ecf20Sopenharmony_ci return e; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci if (e->right.expr->type == E_SYMBOL) { 3778c2ecf20Sopenharmony_ci if (e->right.expr->left.sym == &symbol_no) { 3788c2ecf20Sopenharmony_ci free(e->right.expr); 3798c2ecf20Sopenharmony_ci tmp = e->left.expr; 3808c2ecf20Sopenharmony_ci *e = *(e->left.expr); 3818c2ecf20Sopenharmony_ci free(tmp); 3828c2ecf20Sopenharmony_ci return e; 3838c2ecf20Sopenharmony_ci } else if (e->right.expr->left.sym == &symbol_yes) { 3848c2ecf20Sopenharmony_ci expr_free(e->left.expr); 3858c2ecf20Sopenharmony_ci expr_free(e->right.expr); 3868c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 3878c2ecf20Sopenharmony_ci e->left.sym = &symbol_yes; 3888c2ecf20Sopenharmony_ci e->right.expr = NULL; 3898c2ecf20Sopenharmony_ci return e; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci ; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci return e; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/* 4008c2ecf20Sopenharmony_ci * bool FOO!=n => FOO 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_cistruct expr *expr_trans_bool(struct expr *e) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci if (!e) 4058c2ecf20Sopenharmony_ci return NULL; 4068c2ecf20Sopenharmony_ci switch (e->type) { 4078c2ecf20Sopenharmony_ci case E_AND: 4088c2ecf20Sopenharmony_ci case E_OR: 4098c2ecf20Sopenharmony_ci case E_NOT: 4108c2ecf20Sopenharmony_ci e->left.expr = expr_trans_bool(e->left.expr); 4118c2ecf20Sopenharmony_ci e->right.expr = expr_trans_bool(e->right.expr); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case E_UNEQUAL: 4148c2ecf20Sopenharmony_ci // FOO!=n -> FOO 4158c2ecf20Sopenharmony_ci if (e->left.sym->type == S_TRISTATE) { 4168c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_no) { 4178c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 4188c2ecf20Sopenharmony_ci e->right.sym = NULL; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci ; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci return e; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci/* 4298c2ecf20Sopenharmony_ci * e1 || e2 -> ? 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_cistatic struct expr *expr_join_or(struct expr *e1, struct expr *e2) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct expr *tmp; 4348c2ecf20Sopenharmony_ci struct symbol *sym1, *sym2; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (expr_eq(e1, e2)) 4378c2ecf20Sopenharmony_ci return expr_copy(e1); 4388c2ecf20Sopenharmony_ci if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) 4398c2ecf20Sopenharmony_ci return NULL; 4408c2ecf20Sopenharmony_ci if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) 4418c2ecf20Sopenharmony_ci return NULL; 4428c2ecf20Sopenharmony_ci if (e1->type == E_NOT) { 4438c2ecf20Sopenharmony_ci tmp = e1->left.expr; 4448c2ecf20Sopenharmony_ci if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) 4458c2ecf20Sopenharmony_ci return NULL; 4468c2ecf20Sopenharmony_ci sym1 = tmp->left.sym; 4478c2ecf20Sopenharmony_ci } else 4488c2ecf20Sopenharmony_ci sym1 = e1->left.sym; 4498c2ecf20Sopenharmony_ci if (e2->type == E_NOT) { 4508c2ecf20Sopenharmony_ci if (e2->left.expr->type != E_SYMBOL) 4518c2ecf20Sopenharmony_ci return NULL; 4528c2ecf20Sopenharmony_ci sym2 = e2->left.expr->left.sym; 4538c2ecf20Sopenharmony_ci } else 4548c2ecf20Sopenharmony_ci sym2 = e2->left.sym; 4558c2ecf20Sopenharmony_ci if (sym1 != sym2) 4568c2ecf20Sopenharmony_ci return NULL; 4578c2ecf20Sopenharmony_ci if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) 4588c2ecf20Sopenharmony_ci return NULL; 4598c2ecf20Sopenharmony_ci if (sym1->type == S_TRISTATE) { 4608c2ecf20Sopenharmony_ci if (e1->type == E_EQUAL && e2->type == E_EQUAL && 4618c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || 4628c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { 4638c2ecf20Sopenharmony_ci // (a='y') || (a='m') -> (a!='n') 4648c2ecf20Sopenharmony_ci return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci if (e1->type == E_EQUAL && e2->type == E_EQUAL && 4678c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || 4688c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { 4698c2ecf20Sopenharmony_ci // (a='y') || (a='n') -> (a!='m') 4708c2ecf20Sopenharmony_ci return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci if (e1->type == E_EQUAL && e2->type == E_EQUAL && 4738c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || 4748c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { 4758c2ecf20Sopenharmony_ci // (a='m') || (a='n') -> (a!='y') 4768c2ecf20Sopenharmony_ci return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci if (sym1->type == S_BOOLEAN && sym1 == sym2) { 4808c2ecf20Sopenharmony_ci if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || 4818c2ecf20Sopenharmony_ci (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) 4828c2ecf20Sopenharmony_ci return expr_alloc_symbol(&symbol_yes); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (DEBUG_EXPR) { 4868c2ecf20Sopenharmony_ci printf("optimize ("); 4878c2ecf20Sopenharmony_ci expr_fprint(e1, stdout); 4888c2ecf20Sopenharmony_ci printf(") || ("); 4898c2ecf20Sopenharmony_ci expr_fprint(e2, stdout); 4908c2ecf20Sopenharmony_ci printf(")?\n"); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci return NULL; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic struct expr *expr_join_and(struct expr *e1, struct expr *e2) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct expr *tmp; 4988c2ecf20Sopenharmony_ci struct symbol *sym1, *sym2; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (expr_eq(e1, e2)) 5018c2ecf20Sopenharmony_ci return expr_copy(e1); 5028c2ecf20Sopenharmony_ci if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) 5038c2ecf20Sopenharmony_ci return NULL; 5048c2ecf20Sopenharmony_ci if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) 5058c2ecf20Sopenharmony_ci return NULL; 5068c2ecf20Sopenharmony_ci if (e1->type == E_NOT) { 5078c2ecf20Sopenharmony_ci tmp = e1->left.expr; 5088c2ecf20Sopenharmony_ci if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) 5098c2ecf20Sopenharmony_ci return NULL; 5108c2ecf20Sopenharmony_ci sym1 = tmp->left.sym; 5118c2ecf20Sopenharmony_ci } else 5128c2ecf20Sopenharmony_ci sym1 = e1->left.sym; 5138c2ecf20Sopenharmony_ci if (e2->type == E_NOT) { 5148c2ecf20Sopenharmony_ci if (e2->left.expr->type != E_SYMBOL) 5158c2ecf20Sopenharmony_ci return NULL; 5168c2ecf20Sopenharmony_ci sym2 = e2->left.expr->left.sym; 5178c2ecf20Sopenharmony_ci } else 5188c2ecf20Sopenharmony_ci sym2 = e2->left.sym; 5198c2ecf20Sopenharmony_ci if (sym1 != sym2) 5208c2ecf20Sopenharmony_ci return NULL; 5218c2ecf20Sopenharmony_ci if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) 5228c2ecf20Sopenharmony_ci return NULL; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || 5258c2ecf20Sopenharmony_ci (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) 5268c2ecf20Sopenharmony_ci // (a) && (a='y') -> (a='y') 5278c2ecf20Sopenharmony_ci return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || 5308c2ecf20Sopenharmony_ci (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) 5318c2ecf20Sopenharmony_ci // (a) && (a!='n') -> (a) 5328c2ecf20Sopenharmony_ci return expr_alloc_symbol(sym1); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || 5358c2ecf20Sopenharmony_ci (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) 5368c2ecf20Sopenharmony_ci // (a) && (a!='m') -> (a='y') 5378c2ecf20Sopenharmony_ci return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (sym1->type == S_TRISTATE) { 5408c2ecf20Sopenharmony_ci if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { 5418c2ecf20Sopenharmony_ci // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' 5428c2ecf20Sopenharmony_ci sym2 = e1->right.sym; 5438c2ecf20Sopenharmony_ci if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) 5448c2ecf20Sopenharmony_ci return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) 5458c2ecf20Sopenharmony_ci : expr_alloc_symbol(&symbol_no); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { 5488c2ecf20Sopenharmony_ci // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' 5498c2ecf20Sopenharmony_ci sym2 = e2->right.sym; 5508c2ecf20Sopenharmony_ci if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) 5518c2ecf20Sopenharmony_ci return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) 5528c2ecf20Sopenharmony_ci : expr_alloc_symbol(&symbol_no); 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && 5558c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || 5568c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) 5578c2ecf20Sopenharmony_ci // (a!='y') && (a!='n') -> (a='m') 5588c2ecf20Sopenharmony_ci return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && 5618c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || 5628c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) 5638c2ecf20Sopenharmony_ci // (a!='y') && (a!='m') -> (a='n') 5648c2ecf20Sopenharmony_ci return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && 5678c2ecf20Sopenharmony_ci ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || 5688c2ecf20Sopenharmony_ci (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) 5698c2ecf20Sopenharmony_ci // (a!='m') && (a!='n') -> (a='m') 5708c2ecf20Sopenharmony_ci return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || 5738c2ecf20Sopenharmony_ci (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || 5748c2ecf20Sopenharmony_ci (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || 5758c2ecf20Sopenharmony_ci (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) 5768c2ecf20Sopenharmony_ci return NULL; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (DEBUG_EXPR) { 5808c2ecf20Sopenharmony_ci printf("optimize ("); 5818c2ecf20Sopenharmony_ci expr_fprint(e1, stdout); 5828c2ecf20Sopenharmony_ci printf(") && ("); 5838c2ecf20Sopenharmony_ci expr_fprint(e2, stdout); 5848c2ecf20Sopenharmony_ci printf(")?\n"); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci return NULL; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/* 5908c2ecf20Sopenharmony_ci * expr_eliminate_dups() helper. 5918c2ecf20Sopenharmony_ci * 5928c2ecf20Sopenharmony_ci * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does 5938c2ecf20Sopenharmony_ci * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared 5948c2ecf20Sopenharmony_ci * against all other leaves to look for simplifications. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_cistatic void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci#define e1 (*ep1) 5998c2ecf20Sopenharmony_ci#define e2 (*ep2) 6008c2ecf20Sopenharmony_ci struct expr *tmp; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Recurse down to leaves */ 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (e1->type == type) { 6058c2ecf20Sopenharmony_ci expr_eliminate_dups1(type, &e1->left.expr, &e2); 6068c2ecf20Sopenharmony_ci expr_eliminate_dups1(type, &e1->right.expr, &e2); 6078c2ecf20Sopenharmony_ci return; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (e2->type == type) { 6108c2ecf20Sopenharmony_ci expr_eliminate_dups1(type, &e1, &e2->left.expr); 6118c2ecf20Sopenharmony_ci expr_eliminate_dups1(type, &e1, &e2->right.expr); 6128c2ecf20Sopenharmony_ci return; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* e1 and e2 are leaves. Compare and process them. */ 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (e1 == e2) 6188c2ecf20Sopenharmony_ci return; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci switch (e1->type) { 6218c2ecf20Sopenharmony_ci case E_OR: case E_AND: 6228c2ecf20Sopenharmony_ci expr_eliminate_dups1(e1->type, &e1, &e1); 6238c2ecf20Sopenharmony_ci default: 6248c2ecf20Sopenharmony_ci ; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci switch (type) { 6288c2ecf20Sopenharmony_ci case E_OR: 6298c2ecf20Sopenharmony_ci tmp = expr_join_or(e1, e2); 6308c2ecf20Sopenharmony_ci if (tmp) { 6318c2ecf20Sopenharmony_ci expr_free(e1); expr_free(e2); 6328c2ecf20Sopenharmony_ci e1 = expr_alloc_symbol(&symbol_no); 6338c2ecf20Sopenharmony_ci e2 = tmp; 6348c2ecf20Sopenharmony_ci trans_count++; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci case E_AND: 6388c2ecf20Sopenharmony_ci tmp = expr_join_and(e1, e2); 6398c2ecf20Sopenharmony_ci if (tmp) { 6408c2ecf20Sopenharmony_ci expr_free(e1); expr_free(e2); 6418c2ecf20Sopenharmony_ci e1 = expr_alloc_symbol(&symbol_yes); 6428c2ecf20Sopenharmony_ci e2 = tmp; 6438c2ecf20Sopenharmony_ci trans_count++; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci break; 6468c2ecf20Sopenharmony_ci default: 6478c2ecf20Sopenharmony_ci ; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci#undef e1 6508c2ecf20Sopenharmony_ci#undef e2 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* 6548c2ecf20Sopenharmony_ci * Rewrites 'e' in-place to remove ("join") duplicate and other redundant 6558c2ecf20Sopenharmony_ci * operands. 6568c2ecf20Sopenharmony_ci * 6578c2ecf20Sopenharmony_ci * Example simplifications: 6588c2ecf20Sopenharmony_ci * 6598c2ecf20Sopenharmony_ci * A || B || A -> A || B 6608c2ecf20Sopenharmony_ci * A && B && A=y -> A=y && B 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * Returns the deduplicated expression. 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_cistruct expr *expr_eliminate_dups(struct expr *e) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci int oldcount; 6678c2ecf20Sopenharmony_ci if (!e) 6688c2ecf20Sopenharmony_ci return e; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci oldcount = trans_count; 6718c2ecf20Sopenharmony_ci while (1) { 6728c2ecf20Sopenharmony_ci trans_count = 0; 6738c2ecf20Sopenharmony_ci switch (e->type) { 6748c2ecf20Sopenharmony_ci case E_OR: case E_AND: 6758c2ecf20Sopenharmony_ci expr_eliminate_dups1(e->type, &e, &e); 6768c2ecf20Sopenharmony_ci default: 6778c2ecf20Sopenharmony_ci ; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci if (!trans_count) 6808c2ecf20Sopenharmony_ci /* No simplifications done in this pass. We're done */ 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci e = expr_eliminate_yn(e); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci trans_count = oldcount; 6858c2ecf20Sopenharmony_ci return e; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/* 6898c2ecf20Sopenharmony_ci * Performs various simplifications involving logical operators and 6908c2ecf20Sopenharmony_ci * comparisons. 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * Allocates and returns a new expression. 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_cistruct expr *expr_transform(struct expr *e) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct expr *tmp; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (!e) 6998c2ecf20Sopenharmony_ci return NULL; 7008c2ecf20Sopenharmony_ci switch (e->type) { 7018c2ecf20Sopenharmony_ci case E_EQUAL: 7028c2ecf20Sopenharmony_ci case E_GEQ: 7038c2ecf20Sopenharmony_ci case E_GTH: 7048c2ecf20Sopenharmony_ci case E_LEQ: 7058c2ecf20Sopenharmony_ci case E_LTH: 7068c2ecf20Sopenharmony_ci case E_UNEQUAL: 7078c2ecf20Sopenharmony_ci case E_SYMBOL: 7088c2ecf20Sopenharmony_ci case E_LIST: 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci default: 7118c2ecf20Sopenharmony_ci e->left.expr = expr_transform(e->left.expr); 7128c2ecf20Sopenharmony_ci e->right.expr = expr_transform(e->right.expr); 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci switch (e->type) { 7168c2ecf20Sopenharmony_ci case E_EQUAL: 7178c2ecf20Sopenharmony_ci if (e->left.sym->type != S_BOOLEAN) 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_no) { 7208c2ecf20Sopenharmony_ci e->type = E_NOT; 7218c2ecf20Sopenharmony_ci e->left.expr = expr_alloc_symbol(e->left.sym); 7228c2ecf20Sopenharmony_ci e->right.sym = NULL; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_mod) { 7268c2ecf20Sopenharmony_ci printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); 7278c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 7288c2ecf20Sopenharmony_ci e->left.sym = &symbol_no; 7298c2ecf20Sopenharmony_ci e->right.sym = NULL; 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_yes) { 7338c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 7348c2ecf20Sopenharmony_ci e->right.sym = NULL; 7358c2ecf20Sopenharmony_ci break; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci case E_UNEQUAL: 7398c2ecf20Sopenharmony_ci if (e->left.sym->type != S_BOOLEAN) 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_no) { 7428c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 7438c2ecf20Sopenharmony_ci e->right.sym = NULL; 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_mod) { 7478c2ecf20Sopenharmony_ci printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); 7488c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 7498c2ecf20Sopenharmony_ci e->left.sym = &symbol_yes; 7508c2ecf20Sopenharmony_ci e->right.sym = NULL; 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci if (e->right.sym == &symbol_yes) { 7548c2ecf20Sopenharmony_ci e->type = E_NOT; 7558c2ecf20Sopenharmony_ci e->left.expr = expr_alloc_symbol(e->left.sym); 7568c2ecf20Sopenharmony_ci e->right.sym = NULL; 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci break; 7608c2ecf20Sopenharmony_ci case E_NOT: 7618c2ecf20Sopenharmony_ci switch (e->left.expr->type) { 7628c2ecf20Sopenharmony_ci case E_NOT: 7638c2ecf20Sopenharmony_ci // !!a -> a 7648c2ecf20Sopenharmony_ci tmp = e->left.expr->left.expr; 7658c2ecf20Sopenharmony_ci free(e->left.expr); 7668c2ecf20Sopenharmony_ci free(e); 7678c2ecf20Sopenharmony_ci e = tmp; 7688c2ecf20Sopenharmony_ci e = expr_transform(e); 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci case E_EQUAL: 7718c2ecf20Sopenharmony_ci case E_UNEQUAL: 7728c2ecf20Sopenharmony_ci // !a='x' -> a!='x' 7738c2ecf20Sopenharmony_ci tmp = e->left.expr; 7748c2ecf20Sopenharmony_ci free(e); 7758c2ecf20Sopenharmony_ci e = tmp; 7768c2ecf20Sopenharmony_ci e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci case E_LEQ: 7798c2ecf20Sopenharmony_ci case E_GEQ: 7808c2ecf20Sopenharmony_ci // !a<='x' -> a>'x' 7818c2ecf20Sopenharmony_ci tmp = e->left.expr; 7828c2ecf20Sopenharmony_ci free(e); 7838c2ecf20Sopenharmony_ci e = tmp; 7848c2ecf20Sopenharmony_ci e->type = e->type == E_LEQ ? E_GTH : E_LTH; 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci case E_LTH: 7878c2ecf20Sopenharmony_ci case E_GTH: 7888c2ecf20Sopenharmony_ci // !a<'x' -> a>='x' 7898c2ecf20Sopenharmony_ci tmp = e->left.expr; 7908c2ecf20Sopenharmony_ci free(e); 7918c2ecf20Sopenharmony_ci e = tmp; 7928c2ecf20Sopenharmony_ci e->type = e->type == E_LTH ? E_GEQ : E_LEQ; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case E_OR: 7958c2ecf20Sopenharmony_ci // !(a || b) -> !a && !b 7968c2ecf20Sopenharmony_ci tmp = e->left.expr; 7978c2ecf20Sopenharmony_ci e->type = E_AND; 7988c2ecf20Sopenharmony_ci e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); 7998c2ecf20Sopenharmony_ci tmp->type = E_NOT; 8008c2ecf20Sopenharmony_ci tmp->right.expr = NULL; 8018c2ecf20Sopenharmony_ci e = expr_transform(e); 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci case E_AND: 8048c2ecf20Sopenharmony_ci // !(a && b) -> !a || !b 8058c2ecf20Sopenharmony_ci tmp = e->left.expr; 8068c2ecf20Sopenharmony_ci e->type = E_OR; 8078c2ecf20Sopenharmony_ci e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); 8088c2ecf20Sopenharmony_ci tmp->type = E_NOT; 8098c2ecf20Sopenharmony_ci tmp->right.expr = NULL; 8108c2ecf20Sopenharmony_ci e = expr_transform(e); 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci case E_SYMBOL: 8138c2ecf20Sopenharmony_ci if (e->left.expr->left.sym == &symbol_yes) { 8148c2ecf20Sopenharmony_ci // !'y' -> 'n' 8158c2ecf20Sopenharmony_ci tmp = e->left.expr; 8168c2ecf20Sopenharmony_ci free(e); 8178c2ecf20Sopenharmony_ci e = tmp; 8188c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 8198c2ecf20Sopenharmony_ci e->left.sym = &symbol_no; 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci if (e->left.expr->left.sym == &symbol_mod) { 8238c2ecf20Sopenharmony_ci // !'m' -> 'm' 8248c2ecf20Sopenharmony_ci tmp = e->left.expr; 8258c2ecf20Sopenharmony_ci free(e); 8268c2ecf20Sopenharmony_ci e = tmp; 8278c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 8288c2ecf20Sopenharmony_ci e->left.sym = &symbol_mod; 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci if (e->left.expr->left.sym == &symbol_no) { 8328c2ecf20Sopenharmony_ci // !'n' -> 'y' 8338c2ecf20Sopenharmony_ci tmp = e->left.expr; 8348c2ecf20Sopenharmony_ci free(e); 8358c2ecf20Sopenharmony_ci e = tmp; 8368c2ecf20Sopenharmony_ci e->type = E_SYMBOL; 8378c2ecf20Sopenharmony_ci e->left.sym = &symbol_yes; 8388c2ecf20Sopenharmony_ci break; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci default: 8428c2ecf20Sopenharmony_ci ; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci default: 8468c2ecf20Sopenharmony_ci ; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci return e; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciint expr_contains_symbol(struct expr *dep, struct symbol *sym) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci if (!dep) 8548c2ecf20Sopenharmony_ci return 0; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci switch (dep->type) { 8578c2ecf20Sopenharmony_ci case E_AND: 8588c2ecf20Sopenharmony_ci case E_OR: 8598c2ecf20Sopenharmony_ci return expr_contains_symbol(dep->left.expr, sym) || 8608c2ecf20Sopenharmony_ci expr_contains_symbol(dep->right.expr, sym); 8618c2ecf20Sopenharmony_ci case E_SYMBOL: 8628c2ecf20Sopenharmony_ci return dep->left.sym == sym; 8638c2ecf20Sopenharmony_ci case E_EQUAL: 8648c2ecf20Sopenharmony_ci case E_GEQ: 8658c2ecf20Sopenharmony_ci case E_GTH: 8668c2ecf20Sopenharmony_ci case E_LEQ: 8678c2ecf20Sopenharmony_ci case E_LTH: 8688c2ecf20Sopenharmony_ci case E_UNEQUAL: 8698c2ecf20Sopenharmony_ci return dep->left.sym == sym || 8708c2ecf20Sopenharmony_ci dep->right.sym == sym; 8718c2ecf20Sopenharmony_ci case E_NOT: 8728c2ecf20Sopenharmony_ci return expr_contains_symbol(dep->left.expr, sym); 8738c2ecf20Sopenharmony_ci default: 8748c2ecf20Sopenharmony_ci ; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci return 0; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cibool expr_depends_symbol(struct expr *dep, struct symbol *sym) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci if (!dep) 8828c2ecf20Sopenharmony_ci return false; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci switch (dep->type) { 8858c2ecf20Sopenharmony_ci case E_AND: 8868c2ecf20Sopenharmony_ci return expr_depends_symbol(dep->left.expr, sym) || 8878c2ecf20Sopenharmony_ci expr_depends_symbol(dep->right.expr, sym); 8888c2ecf20Sopenharmony_ci case E_SYMBOL: 8898c2ecf20Sopenharmony_ci return dep->left.sym == sym; 8908c2ecf20Sopenharmony_ci case E_EQUAL: 8918c2ecf20Sopenharmony_ci if (dep->left.sym == sym) { 8928c2ecf20Sopenharmony_ci if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) 8938c2ecf20Sopenharmony_ci return true; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci break; 8968c2ecf20Sopenharmony_ci case E_UNEQUAL: 8978c2ecf20Sopenharmony_ci if (dep->left.sym == sym) { 8988c2ecf20Sopenharmony_ci if (dep->right.sym == &symbol_no) 8998c2ecf20Sopenharmony_ci return true; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci default: 9038c2ecf20Sopenharmony_ci ; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci return false; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * Inserts explicit comparisons of type 'type' to symbol 'sym' into the 9108c2ecf20Sopenharmony_ci * expression 'e'. 9118c2ecf20Sopenharmony_ci * 9128c2ecf20Sopenharmony_ci * Examples transformations for type == E_UNEQUAL, sym == &symbol_no: 9138c2ecf20Sopenharmony_ci * 9148c2ecf20Sopenharmony_ci * A -> A!=n 9158c2ecf20Sopenharmony_ci * !A -> A=n 9168c2ecf20Sopenharmony_ci * A && B -> !(A=n || B=n) 9178c2ecf20Sopenharmony_ci * A || B -> !(A=n && B=n) 9188c2ecf20Sopenharmony_ci * A && (B || C) -> !(A=n || (B=n && C=n)) 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * Allocates and returns a new expression. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_cistruct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct expr *e1, *e2; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (!e) { 9278c2ecf20Sopenharmony_ci e = expr_alloc_symbol(sym); 9288c2ecf20Sopenharmony_ci if (type == E_UNEQUAL) 9298c2ecf20Sopenharmony_ci e = expr_alloc_one(E_NOT, e); 9308c2ecf20Sopenharmony_ci return e; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci switch (e->type) { 9338c2ecf20Sopenharmony_ci case E_AND: 9348c2ecf20Sopenharmony_ci e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); 9358c2ecf20Sopenharmony_ci e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); 9368c2ecf20Sopenharmony_ci if (sym == &symbol_yes) 9378c2ecf20Sopenharmony_ci e = expr_alloc_two(E_AND, e1, e2); 9388c2ecf20Sopenharmony_ci if (sym == &symbol_no) 9398c2ecf20Sopenharmony_ci e = expr_alloc_two(E_OR, e1, e2); 9408c2ecf20Sopenharmony_ci if (type == E_UNEQUAL) 9418c2ecf20Sopenharmony_ci e = expr_alloc_one(E_NOT, e); 9428c2ecf20Sopenharmony_ci return e; 9438c2ecf20Sopenharmony_ci case E_OR: 9448c2ecf20Sopenharmony_ci e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); 9458c2ecf20Sopenharmony_ci e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); 9468c2ecf20Sopenharmony_ci if (sym == &symbol_yes) 9478c2ecf20Sopenharmony_ci e = expr_alloc_two(E_OR, e1, e2); 9488c2ecf20Sopenharmony_ci if (sym == &symbol_no) 9498c2ecf20Sopenharmony_ci e = expr_alloc_two(E_AND, e1, e2); 9508c2ecf20Sopenharmony_ci if (type == E_UNEQUAL) 9518c2ecf20Sopenharmony_ci e = expr_alloc_one(E_NOT, e); 9528c2ecf20Sopenharmony_ci return e; 9538c2ecf20Sopenharmony_ci case E_NOT: 9548c2ecf20Sopenharmony_ci return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); 9558c2ecf20Sopenharmony_ci case E_UNEQUAL: 9568c2ecf20Sopenharmony_ci case E_LTH: 9578c2ecf20Sopenharmony_ci case E_LEQ: 9588c2ecf20Sopenharmony_ci case E_GTH: 9598c2ecf20Sopenharmony_ci case E_GEQ: 9608c2ecf20Sopenharmony_ci case E_EQUAL: 9618c2ecf20Sopenharmony_ci if (type == E_EQUAL) { 9628c2ecf20Sopenharmony_ci if (sym == &symbol_yes) 9638c2ecf20Sopenharmony_ci return expr_copy(e); 9648c2ecf20Sopenharmony_ci if (sym == &symbol_mod) 9658c2ecf20Sopenharmony_ci return expr_alloc_symbol(&symbol_no); 9668c2ecf20Sopenharmony_ci if (sym == &symbol_no) 9678c2ecf20Sopenharmony_ci return expr_alloc_one(E_NOT, expr_copy(e)); 9688c2ecf20Sopenharmony_ci } else { 9698c2ecf20Sopenharmony_ci if (sym == &symbol_yes) 9708c2ecf20Sopenharmony_ci return expr_alloc_one(E_NOT, expr_copy(e)); 9718c2ecf20Sopenharmony_ci if (sym == &symbol_mod) 9728c2ecf20Sopenharmony_ci return expr_alloc_symbol(&symbol_yes); 9738c2ecf20Sopenharmony_ci if (sym == &symbol_no) 9748c2ecf20Sopenharmony_ci return expr_copy(e); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci break; 9778c2ecf20Sopenharmony_ci case E_SYMBOL: 9788c2ecf20Sopenharmony_ci return expr_alloc_comp(type, e->left.sym, sym); 9798c2ecf20Sopenharmony_ci case E_LIST: 9808c2ecf20Sopenharmony_ci case E_RANGE: 9818c2ecf20Sopenharmony_ci case E_NONE: 9828c2ecf20Sopenharmony_ci /* panic */; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci return NULL; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cienum string_value_kind { 9888c2ecf20Sopenharmony_ci k_string, 9898c2ecf20Sopenharmony_ci k_signed, 9908c2ecf20Sopenharmony_ci k_unsigned, 9918c2ecf20Sopenharmony_ci}; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ciunion string_value { 9948c2ecf20Sopenharmony_ci unsigned long long u; 9958c2ecf20Sopenharmony_ci signed long long s; 9968c2ecf20Sopenharmony_ci}; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic enum string_value_kind expr_parse_string(const char *str, 9998c2ecf20Sopenharmony_ci enum symbol_type type, 10008c2ecf20Sopenharmony_ci union string_value *val) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci char *tail; 10038c2ecf20Sopenharmony_ci enum string_value_kind kind; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci errno = 0; 10068c2ecf20Sopenharmony_ci switch (type) { 10078c2ecf20Sopenharmony_ci case S_BOOLEAN: 10088c2ecf20Sopenharmony_ci case S_TRISTATE: 10098c2ecf20Sopenharmony_ci val->s = !strcmp(str, "n") ? 0 : 10108c2ecf20Sopenharmony_ci !strcmp(str, "m") ? 1 : 10118c2ecf20Sopenharmony_ci !strcmp(str, "y") ? 2 : -1; 10128c2ecf20Sopenharmony_ci return k_signed; 10138c2ecf20Sopenharmony_ci case S_INT: 10148c2ecf20Sopenharmony_ci val->s = strtoll(str, &tail, 10); 10158c2ecf20Sopenharmony_ci kind = k_signed; 10168c2ecf20Sopenharmony_ci break; 10178c2ecf20Sopenharmony_ci case S_HEX: 10188c2ecf20Sopenharmony_ci val->u = strtoull(str, &tail, 16); 10198c2ecf20Sopenharmony_ci kind = k_unsigned; 10208c2ecf20Sopenharmony_ci break; 10218c2ecf20Sopenharmony_ci default: 10228c2ecf20Sopenharmony_ci val->s = strtoll(str, &tail, 0); 10238c2ecf20Sopenharmony_ci kind = k_signed; 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci return !errno && !*tail && tail > str && isxdigit(tail[-1]) 10278c2ecf20Sopenharmony_ci ? kind : k_string; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_citristate expr_calc_value(struct expr *e) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci tristate val1, val2; 10338c2ecf20Sopenharmony_ci const char *str1, *str2; 10348c2ecf20Sopenharmony_ci enum string_value_kind k1 = k_string, k2 = k_string; 10358c2ecf20Sopenharmony_ci union string_value lval = {}, rval = {}; 10368c2ecf20Sopenharmony_ci int res; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (!e) 10398c2ecf20Sopenharmony_ci return yes; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci switch (e->type) { 10428c2ecf20Sopenharmony_ci case E_SYMBOL: 10438c2ecf20Sopenharmony_ci sym_calc_value(e->left.sym); 10448c2ecf20Sopenharmony_ci return e->left.sym->curr.tri; 10458c2ecf20Sopenharmony_ci case E_AND: 10468c2ecf20Sopenharmony_ci val1 = expr_calc_value(e->left.expr); 10478c2ecf20Sopenharmony_ci val2 = expr_calc_value(e->right.expr); 10488c2ecf20Sopenharmony_ci return EXPR_AND(val1, val2); 10498c2ecf20Sopenharmony_ci case E_OR: 10508c2ecf20Sopenharmony_ci val1 = expr_calc_value(e->left.expr); 10518c2ecf20Sopenharmony_ci val2 = expr_calc_value(e->right.expr); 10528c2ecf20Sopenharmony_ci return EXPR_OR(val1, val2); 10538c2ecf20Sopenharmony_ci case E_NOT: 10548c2ecf20Sopenharmony_ci val1 = expr_calc_value(e->left.expr); 10558c2ecf20Sopenharmony_ci return EXPR_NOT(val1); 10568c2ecf20Sopenharmony_ci case E_EQUAL: 10578c2ecf20Sopenharmony_ci case E_GEQ: 10588c2ecf20Sopenharmony_ci case E_GTH: 10598c2ecf20Sopenharmony_ci case E_LEQ: 10608c2ecf20Sopenharmony_ci case E_LTH: 10618c2ecf20Sopenharmony_ci case E_UNEQUAL: 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci default: 10648c2ecf20Sopenharmony_ci printf("expr_calc_value: %d?\n", e->type); 10658c2ecf20Sopenharmony_ci return no; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci sym_calc_value(e->left.sym); 10698c2ecf20Sopenharmony_ci sym_calc_value(e->right.sym); 10708c2ecf20Sopenharmony_ci str1 = sym_get_string_value(e->left.sym); 10718c2ecf20Sopenharmony_ci str2 = sym_get_string_value(e->right.sym); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) { 10748c2ecf20Sopenharmony_ci k1 = expr_parse_string(str1, e->left.sym->type, &lval); 10758c2ecf20Sopenharmony_ci k2 = expr_parse_string(str2, e->right.sym->type, &rval); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (k1 == k_string || k2 == k_string) 10798c2ecf20Sopenharmony_ci res = strcmp(str1, str2); 10808c2ecf20Sopenharmony_ci else if (k1 == k_unsigned || k2 == k_unsigned) 10818c2ecf20Sopenharmony_ci res = (lval.u > rval.u) - (lval.u < rval.u); 10828c2ecf20Sopenharmony_ci else /* if (k1 == k_signed && k2 == k_signed) */ 10838c2ecf20Sopenharmony_ci res = (lval.s > rval.s) - (lval.s < rval.s); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci switch(e->type) { 10868c2ecf20Sopenharmony_ci case E_EQUAL: 10878c2ecf20Sopenharmony_ci return res ? no : yes; 10888c2ecf20Sopenharmony_ci case E_GEQ: 10898c2ecf20Sopenharmony_ci return res >= 0 ? yes : no; 10908c2ecf20Sopenharmony_ci case E_GTH: 10918c2ecf20Sopenharmony_ci return res > 0 ? yes : no; 10928c2ecf20Sopenharmony_ci case E_LEQ: 10938c2ecf20Sopenharmony_ci return res <= 0 ? yes : no; 10948c2ecf20Sopenharmony_ci case E_LTH: 10958c2ecf20Sopenharmony_ci return res < 0 ? yes : no; 10968c2ecf20Sopenharmony_ci case E_UNEQUAL: 10978c2ecf20Sopenharmony_ci return res ? yes : no; 10988c2ecf20Sopenharmony_ci default: 10998c2ecf20Sopenharmony_ci printf("expr_calc_value: relation %d?\n", e->type); 11008c2ecf20Sopenharmony_ci return no; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic int expr_compare_type(enum expr_type t1, enum expr_type t2) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci if (t1 == t2) 11078c2ecf20Sopenharmony_ci return 0; 11088c2ecf20Sopenharmony_ci switch (t1) { 11098c2ecf20Sopenharmony_ci case E_LEQ: 11108c2ecf20Sopenharmony_ci case E_LTH: 11118c2ecf20Sopenharmony_ci case E_GEQ: 11128c2ecf20Sopenharmony_ci case E_GTH: 11138c2ecf20Sopenharmony_ci if (t2 == E_EQUAL || t2 == E_UNEQUAL) 11148c2ecf20Sopenharmony_ci return 1; 11158c2ecf20Sopenharmony_ci case E_EQUAL: 11168c2ecf20Sopenharmony_ci case E_UNEQUAL: 11178c2ecf20Sopenharmony_ci if (t2 == E_NOT) 11188c2ecf20Sopenharmony_ci return 1; 11198c2ecf20Sopenharmony_ci case E_NOT: 11208c2ecf20Sopenharmony_ci if (t2 == E_AND) 11218c2ecf20Sopenharmony_ci return 1; 11228c2ecf20Sopenharmony_ci case E_AND: 11238c2ecf20Sopenharmony_ci if (t2 == E_OR) 11248c2ecf20Sopenharmony_ci return 1; 11258c2ecf20Sopenharmony_ci case E_OR: 11268c2ecf20Sopenharmony_ci if (t2 == E_LIST) 11278c2ecf20Sopenharmony_ci return 1; 11288c2ecf20Sopenharmony_ci case E_LIST: 11298c2ecf20Sopenharmony_ci if (t2 == 0) 11308c2ecf20Sopenharmony_ci return 1; 11318c2ecf20Sopenharmony_ci default: 11328c2ecf20Sopenharmony_ci return -1; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci printf("[%dgt%d?]", t1, t2); 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_civoid expr_print(struct expr *e, 11398c2ecf20Sopenharmony_ci void (*fn)(void *, struct symbol *, const char *), 11408c2ecf20Sopenharmony_ci void *data, int prevtoken) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci if (!e) { 11438c2ecf20Sopenharmony_ci fn(data, NULL, "y"); 11448c2ecf20Sopenharmony_ci return; 11458c2ecf20Sopenharmony_ci } 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (expr_compare_type(prevtoken, e->type) > 0) 11488c2ecf20Sopenharmony_ci fn(data, NULL, "("); 11498c2ecf20Sopenharmony_ci switch (e->type) { 11508c2ecf20Sopenharmony_ci case E_SYMBOL: 11518c2ecf20Sopenharmony_ci if (e->left.sym->name) 11528c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 11538c2ecf20Sopenharmony_ci else 11548c2ecf20Sopenharmony_ci fn(data, NULL, "<choice>"); 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case E_NOT: 11578c2ecf20Sopenharmony_ci fn(data, NULL, "!"); 11588c2ecf20Sopenharmony_ci expr_print(e->left.expr, fn, data, E_NOT); 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci case E_EQUAL: 11618c2ecf20Sopenharmony_ci if (e->left.sym->name) 11628c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 11638c2ecf20Sopenharmony_ci else 11648c2ecf20Sopenharmony_ci fn(data, NULL, "<choice>"); 11658c2ecf20Sopenharmony_ci fn(data, NULL, "="); 11668c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 11678c2ecf20Sopenharmony_ci break; 11688c2ecf20Sopenharmony_ci case E_LEQ: 11698c2ecf20Sopenharmony_ci case E_LTH: 11708c2ecf20Sopenharmony_ci if (e->left.sym->name) 11718c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 11728c2ecf20Sopenharmony_ci else 11738c2ecf20Sopenharmony_ci fn(data, NULL, "<choice>"); 11748c2ecf20Sopenharmony_ci fn(data, NULL, e->type == E_LEQ ? "<=" : "<"); 11758c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci case E_GEQ: 11788c2ecf20Sopenharmony_ci case E_GTH: 11798c2ecf20Sopenharmony_ci if (e->left.sym->name) 11808c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 11818c2ecf20Sopenharmony_ci else 11828c2ecf20Sopenharmony_ci fn(data, NULL, "<choice>"); 11838c2ecf20Sopenharmony_ci fn(data, NULL, e->type == E_GEQ ? ">=" : ">"); 11848c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci case E_UNEQUAL: 11878c2ecf20Sopenharmony_ci if (e->left.sym->name) 11888c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 11898c2ecf20Sopenharmony_ci else 11908c2ecf20Sopenharmony_ci fn(data, NULL, "<choice>"); 11918c2ecf20Sopenharmony_ci fn(data, NULL, "!="); 11928c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci case E_OR: 11958c2ecf20Sopenharmony_ci expr_print(e->left.expr, fn, data, E_OR); 11968c2ecf20Sopenharmony_ci fn(data, NULL, " || "); 11978c2ecf20Sopenharmony_ci expr_print(e->right.expr, fn, data, E_OR); 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci case E_AND: 12008c2ecf20Sopenharmony_ci expr_print(e->left.expr, fn, data, E_AND); 12018c2ecf20Sopenharmony_ci fn(data, NULL, " && "); 12028c2ecf20Sopenharmony_ci expr_print(e->right.expr, fn, data, E_AND); 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case E_LIST: 12058c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 12068c2ecf20Sopenharmony_ci if (e->left.expr) { 12078c2ecf20Sopenharmony_ci fn(data, NULL, " ^ "); 12088c2ecf20Sopenharmony_ci expr_print(e->left.expr, fn, data, E_LIST); 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci case E_RANGE: 12128c2ecf20Sopenharmony_ci fn(data, NULL, "["); 12138c2ecf20Sopenharmony_ci fn(data, e->left.sym, e->left.sym->name); 12148c2ecf20Sopenharmony_ci fn(data, NULL, " "); 12158c2ecf20Sopenharmony_ci fn(data, e->right.sym, e->right.sym->name); 12168c2ecf20Sopenharmony_ci fn(data, NULL, "]"); 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci default: 12198c2ecf20Sopenharmony_ci { 12208c2ecf20Sopenharmony_ci char buf[32]; 12218c2ecf20Sopenharmony_ci sprintf(buf, "<unknown type %d>", e->type); 12228c2ecf20Sopenharmony_ci fn(data, NULL, buf); 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci if (expr_compare_type(prevtoken, e->type) > 0) 12278c2ecf20Sopenharmony_ci fn(data, NULL, ")"); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic void expr_print_file_helper(void *data, struct symbol *sym, const char *str) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci xfwrite(str, strlen(str), 1, data); 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_civoid expr_fprint(struct expr *e, FILE *out) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci expr_print(e, expr_print_file_helper, out, E_NONE); 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci struct gstr *gs = (struct gstr*)data; 12438c2ecf20Sopenharmony_ci const char *sym_str = NULL; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci if (sym) 12468c2ecf20Sopenharmony_ci sym_str = sym_get_string_value(sym); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci if (gs->max_width) { 12498c2ecf20Sopenharmony_ci unsigned extra_length = strlen(str); 12508c2ecf20Sopenharmony_ci const char *last_cr = strrchr(gs->s, '\n'); 12518c2ecf20Sopenharmony_ci unsigned last_line_length; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (sym_str) 12548c2ecf20Sopenharmony_ci extra_length += 4 + strlen(sym_str); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (!last_cr) 12578c2ecf20Sopenharmony_ci last_cr = gs->s; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci last_line_length = strlen(gs->s) - (last_cr - gs->s); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if ((last_line_length + extra_length) > gs->max_width) 12628c2ecf20Sopenharmony_ci str_append(gs, "\\\n"); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci str_append(gs, str); 12668c2ecf20Sopenharmony_ci if (sym && sym->type != S_UNKNOWN) 12678c2ecf20Sopenharmony_ci str_printf(gs, " [=%s]", sym_str); 12688c2ecf20Sopenharmony_ci} 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_civoid expr_gstr_print(struct expr *e, struct gstr *gs) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci expr_print(e, expr_print_gstr_helper, gs, E_NONE); 12738c2ecf20Sopenharmony_ci} 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci/* 12768c2ecf20Sopenharmony_ci * Transform the top level "||" tokens into newlines and prepend each 12778c2ecf20Sopenharmony_ci * line with a minus. This makes expressions much easier to read. 12788c2ecf20Sopenharmony_ci * Suitable for reverse dependency expressions. 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_cistatic void expr_print_revdep(struct expr *e, 12818c2ecf20Sopenharmony_ci void (*fn)(void *, struct symbol *, const char *), 12828c2ecf20Sopenharmony_ci void *data, tristate pr_type, const char **title) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci if (e->type == E_OR) { 12858c2ecf20Sopenharmony_ci expr_print_revdep(e->left.expr, fn, data, pr_type, title); 12868c2ecf20Sopenharmony_ci expr_print_revdep(e->right.expr, fn, data, pr_type, title); 12878c2ecf20Sopenharmony_ci } else if (expr_calc_value(e) == pr_type) { 12888c2ecf20Sopenharmony_ci if (*title) { 12898c2ecf20Sopenharmony_ci fn(data, NULL, *title); 12908c2ecf20Sopenharmony_ci *title = NULL; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci fn(data, NULL, " - "); 12948c2ecf20Sopenharmony_ci expr_print(e, fn, data, E_NONE); 12958c2ecf20Sopenharmony_ci fn(data, NULL, "\n"); 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_civoid expr_gstr_print_revdep(struct expr *e, struct gstr *gs, 13008c2ecf20Sopenharmony_ci tristate pr_type, const char *title) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title); 13038c2ecf20Sopenharmony_ci} 1304