10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 2002 Roman Zippel <[email protected]>
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
6558e78e3SMasahiro Yamada #include <ctype.h>
7558e78e3SMasahiro Yamada #include <errno.h>
81da177e4SLinus Torvalds #include <stdio.h>
91da177e4SLinus Torvalds #include <stdlib.h>
101da177e4SLinus Torvalds #include <string.h>
111da177e4SLinus Torvalds
12f93d6bfbSMasahiro Yamada #include <hash.h>
13a9d83d74SMasahiro Yamada #include <xalloc.h>
14f93d6bfbSMasahiro Yamada #include "internal.h"
151da177e4SLinus Torvalds #include "lkc.h"
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #define DEBUG_EXPR 0
181da177e4SLinus Torvalds
19f93d6bfbSMasahiro Yamada HASHTABLE_DEFINE(expr_hashtable, EXPR_HASHSIZE);
20f93d6bfbSMasahiro Yamada
21ad8d40cdSMichal Marek static struct expr *expr_eliminate_yn(struct expr *e);
22ad8d40cdSMichal Marek
23f93d6bfbSMasahiro Yamada /**
24f93d6bfbSMasahiro Yamada * expr_lookup - return the expression with the given type and sub-nodes
25f93d6bfbSMasahiro Yamada * This looks up an expression with the specified type and sub-nodes. If such
26f93d6bfbSMasahiro Yamada * an expression is found in the hash table, it is returned. Otherwise, a new
27f93d6bfbSMasahiro Yamada * expression node is allocated and added to the hash table.
28f93d6bfbSMasahiro Yamada * @type: expression type
29f93d6bfbSMasahiro Yamada * @l: left node
30f93d6bfbSMasahiro Yamada * @r: right node
31f93d6bfbSMasahiro Yamada * return: expression
32f93d6bfbSMasahiro Yamada */
expr_lookup(enum expr_type type,void * l,void * r)33f93d6bfbSMasahiro Yamada static struct expr *expr_lookup(enum expr_type type, void *l, void *r)
34f93d6bfbSMasahiro Yamada {
35f93d6bfbSMasahiro Yamada struct expr *e;
36f93d6bfbSMasahiro Yamada int hash;
37f93d6bfbSMasahiro Yamada
38f93d6bfbSMasahiro Yamada hash = hash_32((unsigned int)type ^ hash_ptr(l) ^ hash_ptr(r));
39f93d6bfbSMasahiro Yamada
40f93d6bfbSMasahiro Yamada hash_for_each_possible(expr_hashtable, e, node, hash) {
41f93d6bfbSMasahiro Yamada if (e->type == type && e->left._initdata == l &&
42f93d6bfbSMasahiro Yamada e->right._initdata == r)
43f93d6bfbSMasahiro Yamada return e;
44f93d6bfbSMasahiro Yamada }
45f93d6bfbSMasahiro Yamada
46f93d6bfbSMasahiro Yamada e = xmalloc(sizeof(*e));
47f93d6bfbSMasahiro Yamada e->type = type;
48f93d6bfbSMasahiro Yamada e->left._initdata = l;
49f93d6bfbSMasahiro Yamada e->right._initdata = r;
50*8d095547SMasahiro Yamada e->val_is_valid = false;
51f93d6bfbSMasahiro Yamada
52f93d6bfbSMasahiro Yamada hash_add(expr_hashtable, &e->node, hash);
53f93d6bfbSMasahiro Yamada
54f93d6bfbSMasahiro Yamada return e;
55f93d6bfbSMasahiro Yamada }
56f93d6bfbSMasahiro Yamada
expr_alloc_symbol(struct symbol * sym)571da177e4SLinus Torvalds struct expr *expr_alloc_symbol(struct symbol *sym)
581da177e4SLinus Torvalds {
59f93d6bfbSMasahiro Yamada return expr_lookup(E_SYMBOL, sym, NULL);
601da177e4SLinus Torvalds }
611da177e4SLinus Torvalds
expr_alloc_one(enum expr_type type,struct expr * ce)621da177e4SLinus Torvalds struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
631da177e4SLinus Torvalds {
64f93d6bfbSMasahiro Yamada return expr_lookup(type, ce, NULL);
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds
expr_alloc_two(enum expr_type type,struct expr * e1,struct expr * e2)671da177e4SLinus Torvalds struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
681da177e4SLinus Torvalds {
69f93d6bfbSMasahiro Yamada return expr_lookup(type, e1, e2);
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds
expr_alloc_comp(enum expr_type type,struct symbol * s1,struct symbol * s2)721da177e4SLinus Torvalds struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
731da177e4SLinus Torvalds {
74f93d6bfbSMasahiro Yamada return expr_lookup(type, s1, s2);
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds
expr_alloc_and(struct expr * e1,struct expr * e2)771da177e4SLinus Torvalds struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
781da177e4SLinus Torvalds {
791da177e4SLinus Torvalds if (!e1)
801da177e4SLinus Torvalds return e2;
811da177e4SLinus Torvalds return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds
expr_alloc_or(struct expr * e1,struct expr * e2)841da177e4SLinus Torvalds struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds if (!e1)
871da177e4SLinus Torvalds return e2;
881da177e4SLinus Torvalds return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds
911da177e4SLinus Torvalds static int trans_count;
921da177e4SLinus Torvalds
930735f7e5SUlf Magnusson /*
940735f7e5SUlf Magnusson * expr_eliminate_eq() helper.
950735f7e5SUlf Magnusson *
960735f7e5SUlf Magnusson * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
970735f7e5SUlf Magnusson * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
980735f7e5SUlf Magnusson * against all other leaves. Two equal leaves are both replaced with either 'y'
990735f7e5SUlf Magnusson * or 'n' as appropriate for 'type', to be eliminated later.
1000735f7e5SUlf Magnusson */
__expr_eliminate_eq(enum expr_type type,struct expr ** ep1,struct expr ** ep2)1011da177e4SLinus Torvalds static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
1021da177e4SLinus Torvalds {
103f93d6bfbSMasahiro Yamada struct expr *l, *r;
104f93d6bfbSMasahiro Yamada
1050735f7e5SUlf Magnusson /* Recurse down to leaves */
1060735f7e5SUlf Magnusson
1073c2f84ceSMasahiro Yamada if ((*ep1)->type == type) {
108f93d6bfbSMasahiro Yamada l = (*ep1)->left.expr;
109f93d6bfbSMasahiro Yamada r = (*ep1)->right.expr;
110f93d6bfbSMasahiro Yamada __expr_eliminate_eq(type, &l, ep2);
111f93d6bfbSMasahiro Yamada __expr_eliminate_eq(type, &r, ep2);
112f93d6bfbSMasahiro Yamada *ep1 = expr_alloc_two(type, l, r);
1131da177e4SLinus Torvalds return;
1141da177e4SLinus Torvalds }
1153c2f84ceSMasahiro Yamada if ((*ep2)->type == type) {
116f93d6bfbSMasahiro Yamada l = (*ep2)->left.expr;
117f93d6bfbSMasahiro Yamada r = (*ep2)->right.expr;
118f93d6bfbSMasahiro Yamada __expr_eliminate_eq(type, ep1, &l);
119f93d6bfbSMasahiro Yamada __expr_eliminate_eq(type, ep1, &r);
120f93d6bfbSMasahiro Yamada *ep2 = expr_alloc_two(type, l, r);
1211da177e4SLinus Torvalds return;
1221da177e4SLinus Torvalds }
1230735f7e5SUlf Magnusson
1243c2f84ceSMasahiro Yamada /* *ep1 and *ep2 are leaves. Compare them. */
1250735f7e5SUlf Magnusson
1263c2f84ceSMasahiro Yamada if ((*ep1)->type == E_SYMBOL && (*ep2)->type == E_SYMBOL &&
1273c2f84ceSMasahiro Yamada (*ep1)->left.sym == (*ep2)->left.sym &&
1283c2f84ceSMasahiro Yamada ((*ep1)->left.sym == &symbol_yes || (*ep1)->left.sym == &symbol_no))
1291da177e4SLinus Torvalds return;
1303c2f84ceSMasahiro Yamada if (!expr_eq(*ep1, *ep2))
1311da177e4SLinus Torvalds return;
1320735f7e5SUlf Magnusson
1333c2f84ceSMasahiro Yamada /* *ep1 and *ep2 are equal leaves. Prepare them for elimination. */
1340735f7e5SUlf Magnusson
1351da177e4SLinus Torvalds trans_count++;
1361da177e4SLinus Torvalds switch (type) {
1371da177e4SLinus Torvalds case E_OR:
1383c2f84ceSMasahiro Yamada *ep1 = expr_alloc_symbol(&symbol_no);
1393c2f84ceSMasahiro Yamada *ep2 = expr_alloc_symbol(&symbol_no);
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds case E_AND:
1423c2f84ceSMasahiro Yamada *ep1 = expr_alloc_symbol(&symbol_yes);
1433c2f84ceSMasahiro Yamada *ep2 = expr_alloc_symbol(&symbol_yes);
1441da177e4SLinus Torvalds break;
1451da177e4SLinus Torvalds default:
1461da177e4SLinus Torvalds ;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds }
1491da177e4SLinus Torvalds
1500735f7e5SUlf Magnusson /*
1510735f7e5SUlf Magnusson * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both.
1520735f7e5SUlf Magnusson * Example reductions:
1530735f7e5SUlf Magnusson *
1540735f7e5SUlf Magnusson * ep1: A && B -> ep1: y
1550735f7e5SUlf Magnusson * ep2: A && B && C -> ep2: C
1560735f7e5SUlf Magnusson *
1570735f7e5SUlf Magnusson * ep1: A || B -> ep1: n
1580735f7e5SUlf Magnusson * ep2: A || B || C -> ep2: C
1590735f7e5SUlf Magnusson *
1600735f7e5SUlf Magnusson * ep1: A && (B && FOO) -> ep1: FOO
1610735f7e5SUlf Magnusson * ep2: (BAR && B) && A -> ep2: BAR
1620735f7e5SUlf Magnusson *
1630735f7e5SUlf Magnusson * ep1: A && (B || C) -> ep1: y
1640735f7e5SUlf Magnusson * ep2: (C || B) && A -> ep2: y
1650735f7e5SUlf Magnusson *
1660735f7e5SUlf Magnusson * Comparisons are done between all operands at the same "level" of && or ||.
1670735f7e5SUlf Magnusson * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the
1680735f7e5SUlf Magnusson * following operands will be compared:
1690735f7e5SUlf Magnusson *
1700735f7e5SUlf Magnusson * - 'e1', 'e2 || e3', and 'e4 || e5', against each other
1710735f7e5SUlf Magnusson * - e2 against e3
1720735f7e5SUlf Magnusson * - e4 against e5
1730735f7e5SUlf Magnusson *
1740735f7e5SUlf Magnusson * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and
1750735f7e5SUlf Magnusson * '(e1 && e2) && e3' are both a single level.
1760735f7e5SUlf Magnusson *
1770735f7e5SUlf Magnusson * See __expr_eliminate_eq() as well.
1780735f7e5SUlf Magnusson */
expr_eliminate_eq(struct expr ** ep1,struct expr ** ep2)1791da177e4SLinus Torvalds void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
1801da177e4SLinus Torvalds {
1813c2f84ceSMasahiro Yamada if (!*ep1 || !*ep2)
1821da177e4SLinus Torvalds return;
1833c2f84ceSMasahiro Yamada switch ((*ep1)->type) {
1841da177e4SLinus Torvalds case E_OR:
1851da177e4SLinus Torvalds case E_AND:
1863c2f84ceSMasahiro Yamada __expr_eliminate_eq((*ep1)->type, ep1, ep2);
1871da177e4SLinus Torvalds default:
1881da177e4SLinus Torvalds ;
1891da177e4SLinus Torvalds }
1903c2f84ceSMasahiro Yamada if ((*ep1)->type != (*ep2)->type) switch ((*ep2)->type) {
1911da177e4SLinus Torvalds case E_OR:
1921da177e4SLinus Torvalds case E_AND:
1933c2f84ceSMasahiro Yamada __expr_eliminate_eq((*ep2)->type, ep1, ep2);
1941da177e4SLinus Torvalds default:
1951da177e4SLinus Torvalds ;
1961da177e4SLinus Torvalds }
1973c2f84ceSMasahiro Yamada *ep1 = expr_eliminate_yn(*ep1);
1983c2f84ceSMasahiro Yamada *ep2 = expr_eliminate_yn(*ep2);
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds
2010735f7e5SUlf Magnusson /*
2020735f7e5SUlf Magnusson * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
2030735f7e5SUlf Magnusson * &&/|| expressions are considered equal if every operand in one expression
2040735f7e5SUlf Magnusson * equals some operand in the other (operands do not need to appear in the same
2050735f7e5SUlf Magnusson * order), recursively.
2060735f7e5SUlf Magnusson */
expr_eq(struct expr * e1,struct expr * e2)207d607e0e7SMasahiro Yamada bool expr_eq(struct expr *e1, struct expr *e2)
2081da177e4SLinus Torvalds {
209d607e0e7SMasahiro Yamada int old_count;
210d607e0e7SMasahiro Yamada bool res;
2111da177e4SLinus Torvalds
212272a7210SThomas Hebb /*
213272a7210SThomas Hebb * A NULL expr is taken to be yes, but there's also a different way to
214272a7210SThomas Hebb * represent yes. expr_is_yes() checks for either representation.
215272a7210SThomas Hebb */
216272a7210SThomas Hebb if (!e1 || !e2)
217272a7210SThomas Hebb return expr_is_yes(e1) && expr_is_yes(e2);
218272a7210SThomas Hebb
2191da177e4SLinus Torvalds if (e1->type != e2->type)
220d607e0e7SMasahiro Yamada return false;
2211da177e4SLinus Torvalds switch (e1->type) {
2221da177e4SLinus Torvalds case E_EQUAL:
22331847b67SJan Beulich case E_GEQ:
22431847b67SJan Beulich case E_GTH:
22531847b67SJan Beulich case E_LEQ:
22631847b67SJan Beulich case E_LTH:
2271da177e4SLinus Torvalds case E_UNEQUAL:
2281da177e4SLinus Torvalds return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
2291da177e4SLinus Torvalds case E_SYMBOL:
2301da177e4SLinus Torvalds return e1->left.sym == e2->left.sym;
2311da177e4SLinus Torvalds case E_NOT:
2321da177e4SLinus Torvalds return expr_eq(e1->left.expr, e2->left.expr);
2331da177e4SLinus Torvalds case E_AND:
2341da177e4SLinus Torvalds case E_OR:
2351da177e4SLinus Torvalds old_count = trans_count;
2361da177e4SLinus Torvalds expr_eliminate_eq(&e1, &e2);
2371da177e4SLinus Torvalds res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
2381da177e4SLinus Torvalds e1->left.sym == e2->left.sym);
2391da177e4SLinus Torvalds trans_count = old_count;
2401da177e4SLinus Torvalds return res;
2411da177e4SLinus Torvalds case E_RANGE:
2421da177e4SLinus Torvalds case E_NONE:
2431da177e4SLinus Torvalds /* panic */;
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds if (DEBUG_EXPR) {
2471da177e4SLinus Torvalds expr_fprint(e1, stdout);
2481da177e4SLinus Torvalds printf(" = ");
2491da177e4SLinus Torvalds expr_fprint(e2, stdout);
2501da177e4SLinus Torvalds printf(" ?\n");
2511da177e4SLinus Torvalds }
2521da177e4SLinus Torvalds
253d607e0e7SMasahiro Yamada return false;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds
2560735f7e5SUlf Magnusson /*
257f93d6bfbSMasahiro Yamada * Recursively performs the following simplifications (as well as the
2580735f7e5SUlf Magnusson * corresponding simplifications with swapped operands):
2590735f7e5SUlf Magnusson *
2600735f7e5SUlf Magnusson * expr && n -> n
2610735f7e5SUlf Magnusson * expr && y -> expr
2620735f7e5SUlf Magnusson * expr || n -> expr
2630735f7e5SUlf Magnusson * expr || y -> y
2640735f7e5SUlf Magnusson *
2650735f7e5SUlf Magnusson * Returns the optimized expression.
2660735f7e5SUlf Magnusson */
expr_eliminate_yn(struct expr * e)267ad8d40cdSMichal Marek static struct expr *expr_eliminate_yn(struct expr *e)
2681da177e4SLinus Torvalds {
269f93d6bfbSMasahiro Yamada struct expr *l, *r;
2701da177e4SLinus Torvalds
2711da177e4SLinus Torvalds if (e) switch (e->type) {
2721da177e4SLinus Torvalds case E_AND:
273f93d6bfbSMasahiro Yamada l = expr_eliminate_yn(e->left.expr);
274f93d6bfbSMasahiro Yamada r = expr_eliminate_yn(e->right.expr);
275f93d6bfbSMasahiro Yamada if (l->type == E_SYMBOL) {
276f93d6bfbSMasahiro Yamada if (l->left.sym == &symbol_no)
277f93d6bfbSMasahiro Yamada return l;
278f93d6bfbSMasahiro Yamada else if (l->left.sym == &symbol_yes)
279f93d6bfbSMasahiro Yamada return r;
2801da177e4SLinus Torvalds }
281f93d6bfbSMasahiro Yamada if (r->type == E_SYMBOL) {
282f93d6bfbSMasahiro Yamada if (r->left.sym == &symbol_no)
283f93d6bfbSMasahiro Yamada return r;
284f93d6bfbSMasahiro Yamada else if (r->left.sym == &symbol_yes)
285f93d6bfbSMasahiro Yamada return l;
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds break;
2881da177e4SLinus Torvalds case E_OR:
289f93d6bfbSMasahiro Yamada l = expr_eliminate_yn(e->left.expr);
290f93d6bfbSMasahiro Yamada r = expr_eliminate_yn(e->right.expr);
291f93d6bfbSMasahiro Yamada if (l->type == E_SYMBOL) {
292f93d6bfbSMasahiro Yamada if (l->left.sym == &symbol_no)
293f93d6bfbSMasahiro Yamada return r;
294f93d6bfbSMasahiro Yamada else if (l->left.sym == &symbol_yes)
295f93d6bfbSMasahiro Yamada return l;
2961da177e4SLinus Torvalds }
297f93d6bfbSMasahiro Yamada if (r->type == E_SYMBOL) {
298f93d6bfbSMasahiro Yamada if (r->left.sym == &symbol_no)
299f93d6bfbSMasahiro Yamada return l;
300f93d6bfbSMasahiro Yamada else if (r->left.sym == &symbol_yes)
301f93d6bfbSMasahiro Yamada return r;
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds break;
3041da177e4SLinus Torvalds default:
3051da177e4SLinus Torvalds ;
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds return e;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds /*
3111da177e4SLinus Torvalds * e1 || e2 -> ?
3121da177e4SLinus Torvalds */
expr_join_or(struct expr * e1,struct expr * e2)3134356f489STrevor Keith static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
3141da177e4SLinus Torvalds {
3151da177e4SLinus Torvalds struct expr *tmp;
3161da177e4SLinus Torvalds struct symbol *sym1, *sym2;
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds if (expr_eq(e1, e2))
319f93d6bfbSMasahiro Yamada return e1;
3201da177e4SLinus Torvalds if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
3211da177e4SLinus Torvalds return NULL;
3221da177e4SLinus Torvalds if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
3231da177e4SLinus Torvalds return NULL;
3241da177e4SLinus Torvalds if (e1->type == E_NOT) {
3251da177e4SLinus Torvalds tmp = e1->left.expr;
3261da177e4SLinus Torvalds if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
3271da177e4SLinus Torvalds return NULL;
3281da177e4SLinus Torvalds sym1 = tmp->left.sym;
3291da177e4SLinus Torvalds } else
3301da177e4SLinus Torvalds sym1 = e1->left.sym;
3311da177e4SLinus Torvalds if (e2->type == E_NOT) {
3321da177e4SLinus Torvalds if (e2->left.expr->type != E_SYMBOL)
3331da177e4SLinus Torvalds return NULL;
3341da177e4SLinus Torvalds sym2 = e2->left.expr->left.sym;
3351da177e4SLinus Torvalds } else
3361da177e4SLinus Torvalds sym2 = e2->left.sym;
3371da177e4SLinus Torvalds if (sym1 != sym2)
3381da177e4SLinus Torvalds return NULL;
3391da177e4SLinus Torvalds if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
3401da177e4SLinus Torvalds return NULL;
3411da177e4SLinus Torvalds if (sym1->type == S_TRISTATE) {
3421da177e4SLinus Torvalds if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
3431da177e4SLinus Torvalds ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
3441da177e4SLinus Torvalds (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
3451da177e4SLinus Torvalds // (a='y') || (a='m') -> (a!='n')
3461da177e4SLinus Torvalds return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
3471da177e4SLinus Torvalds }
3481da177e4SLinus Torvalds if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
3491da177e4SLinus Torvalds ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
3501da177e4SLinus Torvalds (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
3511da177e4SLinus Torvalds // (a='y') || (a='n') -> (a!='m')
3521da177e4SLinus Torvalds return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
3551da177e4SLinus Torvalds ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
3561da177e4SLinus Torvalds (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
3571da177e4SLinus Torvalds // (a='m') || (a='n') -> (a!='y')
3581da177e4SLinus Torvalds return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
3591da177e4SLinus Torvalds }
3601da177e4SLinus Torvalds }
36131894d35SMasahiro Yamada if (sym1->type == S_BOOLEAN) {
3624fa146eaSMasahiro Yamada // a || !a -> y
3631da177e4SLinus Torvalds if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
3641da177e4SLinus Torvalds (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
3651da177e4SLinus Torvalds return expr_alloc_symbol(&symbol_yes);
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds if (DEBUG_EXPR) {
3691da177e4SLinus Torvalds printf("optimize (");
3701da177e4SLinus Torvalds expr_fprint(e1, stdout);
3711da177e4SLinus Torvalds printf(") || (");
3721da177e4SLinus Torvalds expr_fprint(e2, stdout);
3731da177e4SLinus Torvalds printf(")?\n");
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds return NULL;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds
expr_join_and(struct expr * e1,struct expr * e2)3784356f489STrevor Keith static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
3791da177e4SLinus Torvalds {
3801da177e4SLinus Torvalds struct expr *tmp;
3811da177e4SLinus Torvalds struct symbol *sym1, *sym2;
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds if (expr_eq(e1, e2))
384f93d6bfbSMasahiro Yamada return e1;
3851da177e4SLinus Torvalds if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
3861da177e4SLinus Torvalds return NULL;
3871da177e4SLinus Torvalds if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
3881da177e4SLinus Torvalds return NULL;
3891da177e4SLinus Torvalds if (e1->type == E_NOT) {
3901da177e4SLinus Torvalds tmp = e1->left.expr;
3911da177e4SLinus Torvalds if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
3921da177e4SLinus Torvalds return NULL;
3931da177e4SLinus Torvalds sym1 = tmp->left.sym;
3941da177e4SLinus Torvalds } else
3951da177e4SLinus Torvalds sym1 = e1->left.sym;
3961da177e4SLinus Torvalds if (e2->type == E_NOT) {
3971da177e4SLinus Torvalds if (e2->left.expr->type != E_SYMBOL)
3981da177e4SLinus Torvalds return NULL;
3991da177e4SLinus Torvalds sym2 = e2->left.expr->left.sym;
4001da177e4SLinus Torvalds } else
4011da177e4SLinus Torvalds sym2 = e2->left.sym;
4021da177e4SLinus Torvalds if (sym1 != sym2)
4031da177e4SLinus Torvalds return NULL;
4041da177e4SLinus Torvalds if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
4051da177e4SLinus Torvalds return NULL;
4061da177e4SLinus Torvalds
4071da177e4SLinus Torvalds if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
4081da177e4SLinus Torvalds (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
4091da177e4SLinus Torvalds // (a) && (a='y') -> (a='y')
4101da177e4SLinus Torvalds return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
4131da177e4SLinus Torvalds (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
4141da177e4SLinus Torvalds // (a) && (a!='n') -> (a)
4151da177e4SLinus Torvalds return expr_alloc_symbol(sym1);
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
4181da177e4SLinus Torvalds (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
4191da177e4SLinus Torvalds // (a) && (a!='m') -> (a='y')
4201da177e4SLinus Torvalds return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds if (sym1->type == S_TRISTATE) {
4231da177e4SLinus Torvalds if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
4241da177e4SLinus Torvalds // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
4251da177e4SLinus Torvalds sym2 = e1->right.sym;
4261da177e4SLinus Torvalds if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
4271da177e4SLinus Torvalds return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
4281da177e4SLinus Torvalds : expr_alloc_symbol(&symbol_no);
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
4311da177e4SLinus Torvalds // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
4321da177e4SLinus Torvalds sym2 = e2->right.sym;
4331da177e4SLinus Torvalds if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
4341da177e4SLinus Torvalds return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
4351da177e4SLinus Torvalds : expr_alloc_symbol(&symbol_no);
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
4381da177e4SLinus Torvalds ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
4391da177e4SLinus Torvalds (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
4401da177e4SLinus Torvalds // (a!='y') && (a!='n') -> (a='m')
4411da177e4SLinus Torvalds return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
4421da177e4SLinus Torvalds
4431da177e4SLinus Torvalds if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
4441da177e4SLinus Torvalds ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
4451da177e4SLinus Torvalds (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
4461da177e4SLinus Torvalds // (a!='y') && (a!='m') -> (a='n')
4471da177e4SLinus Torvalds return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
4481da177e4SLinus Torvalds
4491da177e4SLinus Torvalds if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
4501da177e4SLinus Torvalds ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
4511da177e4SLinus Torvalds (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
4521da177e4SLinus Torvalds // (a!='m') && (a!='n') -> (a='m')
4531da177e4SLinus Torvalds return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
4541da177e4SLinus Torvalds
4551da177e4SLinus Torvalds if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
4561da177e4SLinus Torvalds (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
4571da177e4SLinus Torvalds (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
4581da177e4SLinus Torvalds (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
4591da177e4SLinus Torvalds return NULL;
4601da177e4SLinus Torvalds }
4611da177e4SLinus Torvalds
4621da177e4SLinus Torvalds if (DEBUG_EXPR) {
4631da177e4SLinus Torvalds printf("optimize (");
4641da177e4SLinus Torvalds expr_fprint(e1, stdout);
4651da177e4SLinus Torvalds printf(") && (");
4661da177e4SLinus Torvalds expr_fprint(e2, stdout);
4671da177e4SLinus Torvalds printf(")?\n");
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds return NULL;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds
4720735f7e5SUlf Magnusson /*
4730735f7e5SUlf Magnusson * expr_eliminate_dups() helper.
4740735f7e5SUlf Magnusson *
4750735f7e5SUlf Magnusson * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
4760735f7e5SUlf Magnusson * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
4770735f7e5SUlf Magnusson * against all other leaves to look for simplifications.
4780735f7e5SUlf Magnusson */
expr_eliminate_dups1(enum expr_type type,struct expr ** ep1,struct expr ** ep2)4791da177e4SLinus Torvalds static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
4801da177e4SLinus Torvalds {
481f93d6bfbSMasahiro Yamada struct expr *tmp, *l, *r;
4821da177e4SLinus Torvalds
4830735f7e5SUlf Magnusson /* Recurse down to leaves */
4840735f7e5SUlf Magnusson
4853c2f84ceSMasahiro Yamada if ((*ep1)->type == type) {
486f93d6bfbSMasahiro Yamada l = (*ep1)->left.expr;
487f93d6bfbSMasahiro Yamada r = (*ep1)->right.expr;
488f93d6bfbSMasahiro Yamada expr_eliminate_dups1(type, &l, ep2);
489f93d6bfbSMasahiro Yamada expr_eliminate_dups1(type, &r, ep2);
490f93d6bfbSMasahiro Yamada *ep1 = expr_alloc_two(type, l, r);
4911da177e4SLinus Torvalds return;
4921da177e4SLinus Torvalds }
4933c2f84ceSMasahiro Yamada if ((*ep2)->type == type) {
494f93d6bfbSMasahiro Yamada l = (*ep2)->left.expr;
495f93d6bfbSMasahiro Yamada r = (*ep2)->right.expr;
496f93d6bfbSMasahiro Yamada expr_eliminate_dups1(type, ep1, &l);
497f93d6bfbSMasahiro Yamada expr_eliminate_dups1(type, ep1, &r);
498f93d6bfbSMasahiro Yamada *ep2 = expr_alloc_two(type, l, r);
4991da177e4SLinus Torvalds return;
5001da177e4SLinus Torvalds }
5010735f7e5SUlf Magnusson
5023c2f84ceSMasahiro Yamada /* *ep1 and *ep2 are leaves. Compare and process them. */
5030735f7e5SUlf Magnusson
5041da177e4SLinus Torvalds switch (type) {
5051da177e4SLinus Torvalds case E_OR:
5063c2f84ceSMasahiro Yamada tmp = expr_join_or(*ep1, *ep2);
5071da177e4SLinus Torvalds if (tmp) {
5083c2f84ceSMasahiro Yamada *ep1 = expr_alloc_symbol(&symbol_no);
5093c2f84ceSMasahiro Yamada *ep2 = tmp;
5101da177e4SLinus Torvalds trans_count++;
5111da177e4SLinus Torvalds }
5121da177e4SLinus Torvalds break;
5131da177e4SLinus Torvalds case E_AND:
5143c2f84ceSMasahiro Yamada tmp = expr_join_and(*ep1, *ep2);
5151da177e4SLinus Torvalds if (tmp) {
5163c2f84ceSMasahiro Yamada *ep1 = expr_alloc_symbol(&symbol_yes);
5173c2f84ceSMasahiro Yamada *ep2 = tmp;
5181da177e4SLinus Torvalds trans_count++;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds break;
5211da177e4SLinus Torvalds default:
5221da177e4SLinus Torvalds ;
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds }
5251da177e4SLinus Torvalds
5260735f7e5SUlf Magnusson /*
5270735f7e5SUlf Magnusson * Rewrites 'e' in-place to remove ("join") duplicate and other redundant
5280735f7e5SUlf Magnusson * operands.
5290735f7e5SUlf Magnusson *
5300735f7e5SUlf Magnusson * Example simplifications:
5310735f7e5SUlf Magnusson *
5320735f7e5SUlf Magnusson * A || B || A -> A || B
5330735f7e5SUlf Magnusson * A && B && A=y -> A=y && B
5340735f7e5SUlf Magnusson *
5350735f7e5SUlf Magnusson * Returns the deduplicated expression.
5360735f7e5SUlf Magnusson */
expr_eliminate_dups(struct expr * e)5371da177e4SLinus Torvalds struct expr *expr_eliminate_dups(struct expr *e)
5381da177e4SLinus Torvalds {
5391da177e4SLinus Torvalds int oldcount;
5401da177e4SLinus Torvalds if (!e)
5411da177e4SLinus Torvalds return e;
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds oldcount = trans_count;
5448bfd6f09SMasahiro Yamada do {
545f93d6bfbSMasahiro Yamada struct expr *l, *r;
546f93d6bfbSMasahiro Yamada
5471da177e4SLinus Torvalds trans_count = 0;
5481da177e4SLinus Torvalds switch (e->type) {
5491da177e4SLinus Torvalds case E_OR: case E_AND:
550f93d6bfbSMasahiro Yamada l = expr_eliminate_dups(e->left.expr);
551f93d6bfbSMasahiro Yamada r = expr_eliminate_dups(e->right.expr);
552f93d6bfbSMasahiro Yamada expr_eliminate_dups1(e->type, &l, &r);
553f93d6bfbSMasahiro Yamada e = expr_alloc_two(e->type, l, r);
5541da177e4SLinus Torvalds default:
5551da177e4SLinus Torvalds ;
5561da177e4SLinus Torvalds }
5571da177e4SLinus Torvalds e = expr_eliminate_yn(e);
5588bfd6f09SMasahiro Yamada } while (trans_count); /* repeat until we get no more simplifications */
5591da177e4SLinus Torvalds trans_count = oldcount;
5601da177e4SLinus Torvalds return e;
5611da177e4SLinus Torvalds }
5621da177e4SLinus Torvalds
5630735f7e5SUlf Magnusson /*
5640735f7e5SUlf Magnusson * Performs various simplifications involving logical operators and
5650735f7e5SUlf Magnusson * comparisons.
5660735f7e5SUlf Magnusson *
5674fa146eaSMasahiro Yamada * For bool type:
5684fa146eaSMasahiro Yamada * A=n -> !A
5694fa146eaSMasahiro Yamada * A=m -> n
5704fa146eaSMasahiro Yamada * A=y -> A
5714fa146eaSMasahiro Yamada * A!=n -> A
5724fa146eaSMasahiro Yamada * A!=m -> y
5734fa146eaSMasahiro Yamada * A!=y -> !A
5744fa146eaSMasahiro Yamada *
5754fa146eaSMasahiro Yamada * For any type:
5764fa146eaSMasahiro Yamada * !!A -> A
5774fa146eaSMasahiro Yamada * !(A=B) -> A!=B
5784fa146eaSMasahiro Yamada * !(A!=B) -> A=B
5794fa146eaSMasahiro Yamada * !(A<=B) -> A>B
5804fa146eaSMasahiro Yamada * !(A>=B) -> A<B
5814fa146eaSMasahiro Yamada * !(A<B) -> A>=B
5824fa146eaSMasahiro Yamada * !(A>B) -> A<=B
5834fa146eaSMasahiro Yamada * !(A || B) -> !A && !B
5844fa146eaSMasahiro Yamada * !(A && B) -> !A || !B
5854fa146eaSMasahiro Yamada *
5864fa146eaSMasahiro Yamada * For constant:
5874fa146eaSMasahiro Yamada * !y -> n
5884fa146eaSMasahiro Yamada * !m -> m
5894fa146eaSMasahiro Yamada * !n -> y
5904fa146eaSMasahiro Yamada *
5910735f7e5SUlf Magnusson * Allocates and returns a new expression.
5920735f7e5SUlf Magnusson */
expr_transform(struct expr * e)5931da177e4SLinus Torvalds struct expr *expr_transform(struct expr *e)
5941da177e4SLinus Torvalds {
5951da177e4SLinus Torvalds if (!e)
5961da177e4SLinus Torvalds return NULL;
5971da177e4SLinus Torvalds switch (e->type) {
5981da177e4SLinus Torvalds case E_EQUAL:
59931847b67SJan Beulich case E_GEQ:
60031847b67SJan Beulich case E_GTH:
60131847b67SJan Beulich case E_LEQ:
60231847b67SJan Beulich case E_LTH:
6031da177e4SLinus Torvalds case E_UNEQUAL:
6041da177e4SLinus Torvalds case E_SYMBOL:
6051da177e4SLinus Torvalds break;
6061da177e4SLinus Torvalds default:
607f93d6bfbSMasahiro Yamada e = expr_alloc_two(e->type,
608f93d6bfbSMasahiro Yamada expr_transform(e->left.expr),
609f93d6bfbSMasahiro Yamada expr_transform(e->right.expr));
6101da177e4SLinus Torvalds }
6111da177e4SLinus Torvalds
6121da177e4SLinus Torvalds switch (e->type) {
6131da177e4SLinus Torvalds case E_EQUAL:
6141da177e4SLinus Torvalds if (e->left.sym->type != S_BOOLEAN)
6151da177e4SLinus Torvalds break;
6161da177e4SLinus Torvalds if (e->right.sym == &symbol_no) {
6174fa146eaSMasahiro Yamada // A=n -> !A
618f93d6bfbSMasahiro Yamada e = expr_alloc_one(E_NOT, expr_alloc_symbol(e->left.sym));
6191da177e4SLinus Torvalds break;
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds if (e->right.sym == &symbol_mod) {
6224fa146eaSMasahiro Yamada // A=m -> n
6231da177e4SLinus Torvalds printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
624f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(&symbol_no);
6251da177e4SLinus Torvalds break;
6261da177e4SLinus Torvalds }
6271da177e4SLinus Torvalds if (e->right.sym == &symbol_yes) {
6284fa146eaSMasahiro Yamada // A=y -> A
629f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(e->left.sym);
6301da177e4SLinus Torvalds break;
6311da177e4SLinus Torvalds }
6321da177e4SLinus Torvalds break;
6331da177e4SLinus Torvalds case E_UNEQUAL:
6341da177e4SLinus Torvalds if (e->left.sym->type != S_BOOLEAN)
6351da177e4SLinus Torvalds break;
6361da177e4SLinus Torvalds if (e->right.sym == &symbol_no) {
6374fa146eaSMasahiro Yamada // A!=n -> A
638f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(e->left.sym);
6391da177e4SLinus Torvalds break;
6401da177e4SLinus Torvalds }
6411da177e4SLinus Torvalds if (e->right.sym == &symbol_mod) {
6424fa146eaSMasahiro Yamada // A!=m -> y
6431da177e4SLinus Torvalds printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
644f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(&symbol_yes);
6451da177e4SLinus Torvalds break;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds if (e->right.sym == &symbol_yes) {
6484fa146eaSMasahiro Yamada // A!=y -> !A
649f93d6bfbSMasahiro Yamada e = expr_alloc_one(E_NOT, e->left.expr);
6501da177e4SLinus Torvalds break;
6511da177e4SLinus Torvalds }
6521da177e4SLinus Torvalds break;
6531da177e4SLinus Torvalds case E_NOT:
6541da177e4SLinus Torvalds switch (e->left.expr->type) {
6551da177e4SLinus Torvalds case E_NOT:
6564fa146eaSMasahiro Yamada // !!A -> A
657f93d6bfbSMasahiro Yamada e = e->left.expr->left.expr;
6581da177e4SLinus Torvalds break;
6591da177e4SLinus Torvalds case E_EQUAL:
6601da177e4SLinus Torvalds case E_UNEQUAL:
6614fa146eaSMasahiro Yamada // !(A=B) -> A!=B
662f93d6bfbSMasahiro Yamada e = expr_alloc_comp(e->left.expr->type == E_EQUAL ? E_UNEQUAL : E_EQUAL,
663f93d6bfbSMasahiro Yamada e->left.expr->left.sym,
664f93d6bfbSMasahiro Yamada e->left.expr->right.sym);
6651da177e4SLinus Torvalds break;
66631847b67SJan Beulich case E_LEQ:
66731847b67SJan Beulich case E_GEQ:
6684fa146eaSMasahiro Yamada // !(A<=B) -> A>B
669f93d6bfbSMasahiro Yamada e = expr_alloc_comp(e->left.expr->type == E_LEQ ? E_GTH : E_LTH,
670f93d6bfbSMasahiro Yamada e->left.expr->left.sym,
671f93d6bfbSMasahiro Yamada e->left.expr->right.sym);
67231847b67SJan Beulich break;
67331847b67SJan Beulich case E_LTH:
67431847b67SJan Beulich case E_GTH:
6754fa146eaSMasahiro Yamada // !(A<B) -> A>=B
676f93d6bfbSMasahiro Yamada e = expr_alloc_comp(e->left.expr->type == E_LTH ? E_GEQ : E_LEQ,
677f93d6bfbSMasahiro Yamada e->left.expr->left.sym,
678f93d6bfbSMasahiro Yamada e->left.expr->right.sym);
67931847b67SJan Beulich break;
6801da177e4SLinus Torvalds case E_OR:
6814fa146eaSMasahiro Yamada // !(A || B) -> !A && !B
682f93d6bfbSMasahiro Yamada e = expr_alloc_and(expr_alloc_one(E_NOT, e->left.expr->left.expr),
683f93d6bfbSMasahiro Yamada expr_alloc_one(E_NOT, e->left.expr->right.expr));
6841da177e4SLinus Torvalds e = expr_transform(e);
6851da177e4SLinus Torvalds break;
6861da177e4SLinus Torvalds case E_AND:
6874fa146eaSMasahiro Yamada // !(A && B) -> !A || !B
688f93d6bfbSMasahiro Yamada e = expr_alloc_or(expr_alloc_one(E_NOT, e->left.expr->left.expr),
689f93d6bfbSMasahiro Yamada expr_alloc_one(E_NOT, e->left.expr->right.expr));
6901da177e4SLinus Torvalds e = expr_transform(e);
6911da177e4SLinus Torvalds break;
6921da177e4SLinus Torvalds case E_SYMBOL:
693f93d6bfbSMasahiro Yamada if (e->left.expr->left.sym == &symbol_yes)
6941da177e4SLinus Torvalds // !'y' -> 'n'
695f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(&symbol_no);
696f93d6bfbSMasahiro Yamada else if (e->left.expr->left.sym == &symbol_mod)
6971da177e4SLinus Torvalds // !'m' -> 'm'
698f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(&symbol_mod);
699f93d6bfbSMasahiro Yamada else if (e->left.expr->left.sym == &symbol_no)
7001da177e4SLinus Torvalds // !'n' -> 'y'
701f93d6bfbSMasahiro Yamada e = expr_alloc_symbol(&symbol_yes);
7021da177e4SLinus Torvalds break;
7031da177e4SLinus Torvalds default:
7041da177e4SLinus Torvalds ;
7051da177e4SLinus Torvalds }
7061da177e4SLinus Torvalds break;
7071da177e4SLinus Torvalds default:
7081da177e4SLinus Torvalds ;
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds return e;
7111da177e4SLinus Torvalds }
7121da177e4SLinus Torvalds
expr_contains_symbol(struct expr * dep,struct symbol * sym)713d607e0e7SMasahiro Yamada bool expr_contains_symbol(struct expr *dep, struct symbol *sym)
7141da177e4SLinus Torvalds {
7151da177e4SLinus Torvalds if (!dep)
716d607e0e7SMasahiro Yamada return false;
7171da177e4SLinus Torvalds
7181da177e4SLinus Torvalds switch (dep->type) {
7191da177e4SLinus Torvalds case E_AND:
7201da177e4SLinus Torvalds case E_OR:
7211da177e4SLinus Torvalds return expr_contains_symbol(dep->left.expr, sym) ||
7221da177e4SLinus Torvalds expr_contains_symbol(dep->right.expr, sym);
7231da177e4SLinus Torvalds case E_SYMBOL:
7241da177e4SLinus Torvalds return dep->left.sym == sym;
7251da177e4SLinus Torvalds case E_EQUAL:
72631847b67SJan Beulich case E_GEQ:
72731847b67SJan Beulich case E_GTH:
72831847b67SJan Beulich case E_LEQ:
72931847b67SJan Beulich case E_LTH:
7301da177e4SLinus Torvalds case E_UNEQUAL:
7311da177e4SLinus Torvalds return dep->left.sym == sym ||
7321da177e4SLinus Torvalds dep->right.sym == sym;
7331da177e4SLinus Torvalds case E_NOT:
7341da177e4SLinus Torvalds return expr_contains_symbol(dep->left.expr, sym);
7351da177e4SLinus Torvalds default:
7361da177e4SLinus Torvalds ;
7371da177e4SLinus Torvalds }
738d607e0e7SMasahiro Yamada return false;
7391da177e4SLinus Torvalds }
7401da177e4SLinus Torvalds
expr_depends_symbol(struct expr * dep,struct symbol * sym)7411da177e4SLinus Torvalds bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
7421da177e4SLinus Torvalds {
7431da177e4SLinus Torvalds if (!dep)
7441da177e4SLinus Torvalds return false;
7451da177e4SLinus Torvalds
7461da177e4SLinus Torvalds switch (dep->type) {
7471da177e4SLinus Torvalds case E_AND:
7481da177e4SLinus Torvalds return expr_depends_symbol(dep->left.expr, sym) ||
7491da177e4SLinus Torvalds expr_depends_symbol(dep->right.expr, sym);
7501da177e4SLinus Torvalds case E_SYMBOL:
7511da177e4SLinus Torvalds return dep->left.sym == sym;
7521da177e4SLinus Torvalds case E_EQUAL:
7531da177e4SLinus Torvalds if (dep->left.sym == sym) {
7541da177e4SLinus Torvalds if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
7551da177e4SLinus Torvalds return true;
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds break;
7581da177e4SLinus Torvalds case E_UNEQUAL:
7591da177e4SLinus Torvalds if (dep->left.sym == sym) {
7601da177e4SLinus Torvalds if (dep->right.sym == &symbol_no)
7611da177e4SLinus Torvalds return true;
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds break;
7641da177e4SLinus Torvalds default:
7651da177e4SLinus Torvalds ;
7661da177e4SLinus Torvalds }
7671da177e4SLinus Torvalds return false;
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds
7700735f7e5SUlf Magnusson /*
7710735f7e5SUlf Magnusson * Inserts explicit comparisons of type 'type' to symbol 'sym' into the
7720735f7e5SUlf Magnusson * expression 'e'.
7730735f7e5SUlf Magnusson *
7740735f7e5SUlf Magnusson * Examples transformations for type == E_UNEQUAL, sym == &symbol_no:
7750735f7e5SUlf Magnusson *
7760735f7e5SUlf Magnusson * A -> A!=n
7770735f7e5SUlf Magnusson * !A -> A=n
7780735f7e5SUlf Magnusson * A && B -> !(A=n || B=n)
7790735f7e5SUlf Magnusson * A || B -> !(A=n && B=n)
7800735f7e5SUlf Magnusson * A && (B || C) -> !(A=n || (B=n && C=n))
7810735f7e5SUlf Magnusson *
7820735f7e5SUlf Magnusson * Allocates and returns a new expression.
7830735f7e5SUlf Magnusson */
expr_trans_compare(struct expr * e,enum expr_type type,struct symbol * sym)7841da177e4SLinus Torvalds struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
7851da177e4SLinus Torvalds {
7861da177e4SLinus Torvalds struct expr *e1, *e2;
7871da177e4SLinus Torvalds
7881da177e4SLinus Torvalds if (!e) {
7891da177e4SLinus Torvalds e = expr_alloc_symbol(sym);
7901da177e4SLinus Torvalds if (type == E_UNEQUAL)
7911da177e4SLinus Torvalds e = expr_alloc_one(E_NOT, e);
7921da177e4SLinus Torvalds return e;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds switch (e->type) {
7951da177e4SLinus Torvalds case E_AND:
7961da177e4SLinus Torvalds e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
7971da177e4SLinus Torvalds e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
7981da177e4SLinus Torvalds if (sym == &symbol_yes)
7991da177e4SLinus Torvalds e = expr_alloc_two(E_AND, e1, e2);
8001da177e4SLinus Torvalds if (sym == &symbol_no)
8011da177e4SLinus Torvalds e = expr_alloc_two(E_OR, e1, e2);
8021da177e4SLinus Torvalds if (type == E_UNEQUAL)
8031da177e4SLinus Torvalds e = expr_alloc_one(E_NOT, e);
8041da177e4SLinus Torvalds return e;
8051da177e4SLinus Torvalds case E_OR:
8061da177e4SLinus Torvalds e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
8071da177e4SLinus Torvalds e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
8081da177e4SLinus Torvalds if (sym == &symbol_yes)
8091da177e4SLinus Torvalds e = expr_alloc_two(E_OR, e1, e2);
8101da177e4SLinus Torvalds if (sym == &symbol_no)
8111da177e4SLinus Torvalds e = expr_alloc_two(E_AND, e1, e2);
8121da177e4SLinus Torvalds if (type == E_UNEQUAL)
8131da177e4SLinus Torvalds e = expr_alloc_one(E_NOT, e);
8141da177e4SLinus Torvalds return e;
8151da177e4SLinus Torvalds case E_NOT:
8161da177e4SLinus Torvalds return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
8171da177e4SLinus Torvalds case E_UNEQUAL:
81831847b67SJan Beulich case E_LTH:
81931847b67SJan Beulich case E_LEQ:
82031847b67SJan Beulich case E_GTH:
82131847b67SJan Beulich case E_GEQ:
8221da177e4SLinus Torvalds case E_EQUAL:
8231da177e4SLinus Torvalds if (type == E_EQUAL) {
8241da177e4SLinus Torvalds if (sym == &symbol_yes)
825f93d6bfbSMasahiro Yamada return e;
8261da177e4SLinus Torvalds if (sym == &symbol_mod)
8271da177e4SLinus Torvalds return expr_alloc_symbol(&symbol_no);
8281da177e4SLinus Torvalds if (sym == &symbol_no)
829f93d6bfbSMasahiro Yamada return expr_alloc_one(E_NOT, e);
8301da177e4SLinus Torvalds } else {
8311da177e4SLinus Torvalds if (sym == &symbol_yes)
832f93d6bfbSMasahiro Yamada return expr_alloc_one(E_NOT, e);
8331da177e4SLinus Torvalds if (sym == &symbol_mod)
8341da177e4SLinus Torvalds return expr_alloc_symbol(&symbol_yes);
8351da177e4SLinus Torvalds if (sym == &symbol_no)
836f93d6bfbSMasahiro Yamada return e;
8371da177e4SLinus Torvalds }
8381da177e4SLinus Torvalds break;
8391da177e4SLinus Torvalds case E_SYMBOL:
8401da177e4SLinus Torvalds return expr_alloc_comp(type, e->left.sym, sym);
8411da177e4SLinus Torvalds case E_RANGE:
8421da177e4SLinus Torvalds case E_NONE:
8431da177e4SLinus Torvalds /* panic */;
8441da177e4SLinus Torvalds }
8451da177e4SLinus Torvalds return NULL;
8461da177e4SLinus Torvalds }
8471da177e4SLinus Torvalds
84831847b67SJan Beulich enum string_value_kind {
84931847b67SJan Beulich k_string,
85031847b67SJan Beulich k_signed,
85131847b67SJan Beulich k_unsigned,
85231847b67SJan Beulich };
85331847b67SJan Beulich
85431847b67SJan Beulich union string_value {
85531847b67SJan Beulich unsigned long long u;
85631847b67SJan Beulich signed long long s;
85731847b67SJan Beulich };
85831847b67SJan Beulich
expr_parse_string(const char * str,enum symbol_type type,union string_value * val)85931847b67SJan Beulich static enum string_value_kind expr_parse_string(const char *str,
86031847b67SJan Beulich enum symbol_type type,
86131847b67SJan Beulich union string_value *val)
86231847b67SJan Beulich {
86331847b67SJan Beulich char *tail;
86431847b67SJan Beulich enum string_value_kind kind;
86531847b67SJan Beulich
86631847b67SJan Beulich errno = 0;
86731847b67SJan Beulich switch (type) {
86831847b67SJan Beulich case S_BOOLEAN:
86931847b67SJan Beulich case S_TRISTATE:
8709059a349SNicolas Pitre val->s = !strcmp(str, "n") ? 0 :
8719059a349SNicolas Pitre !strcmp(str, "m") ? 1 :
8729059a349SNicolas Pitre !strcmp(str, "y") ? 2 : -1;
8739059a349SNicolas Pitre return k_signed;
87431847b67SJan Beulich case S_INT:
87531847b67SJan Beulich val->s = strtoll(str, &tail, 10);
87631847b67SJan Beulich kind = k_signed;
87731847b67SJan Beulich break;
87831847b67SJan Beulich case S_HEX:
87931847b67SJan Beulich val->u = strtoull(str, &tail, 16);
88031847b67SJan Beulich kind = k_unsigned;
88131847b67SJan Beulich break;
8820cbe3ac4SMasahiro Yamada default:
88331847b67SJan Beulich val->s = strtoll(str, &tail, 0);
88431847b67SJan Beulich kind = k_signed;
88531847b67SJan Beulich break;
88631847b67SJan Beulich }
88731847b67SJan Beulich return !errno && !*tail && tail > str && isxdigit(tail[-1])
88831847b67SJan Beulich ? kind : k_string;
88931847b67SJan Beulich }
89031847b67SJan Beulich
__expr_calc_value(struct expr * e)89195573cacSMasahiro Yamada static tristate __expr_calc_value(struct expr *e)
8921da177e4SLinus Torvalds {
8931da177e4SLinus Torvalds tristate val1, val2;
8941da177e4SLinus Torvalds const char *str1, *str2;
89531847b67SJan Beulich enum string_value_kind k1 = k_string, k2 = k_string;
89631847b67SJan Beulich union string_value lval = {}, rval = {};
89731847b67SJan Beulich int res;
8981da177e4SLinus Torvalds
8991da177e4SLinus Torvalds switch (e->type) {
9001da177e4SLinus Torvalds case E_SYMBOL:
9011da177e4SLinus Torvalds sym_calc_value(e->left.sym);
9021da177e4SLinus Torvalds return e->left.sym->curr.tri;
9031da177e4SLinus Torvalds case E_AND:
9041da177e4SLinus Torvalds val1 = expr_calc_value(e->left.expr);
9051da177e4SLinus Torvalds val2 = expr_calc_value(e->right.expr);
906d6ee3576SSam Ravnborg return EXPR_AND(val1, val2);
9071da177e4SLinus Torvalds case E_OR:
9081da177e4SLinus Torvalds val1 = expr_calc_value(e->left.expr);
9091da177e4SLinus Torvalds val2 = expr_calc_value(e->right.expr);
910d6ee3576SSam Ravnborg return EXPR_OR(val1, val2);
9111da177e4SLinus Torvalds case E_NOT:
9121da177e4SLinus Torvalds val1 = expr_calc_value(e->left.expr);
913d6ee3576SSam Ravnborg return EXPR_NOT(val1);
9141da177e4SLinus Torvalds case E_EQUAL:
91531847b67SJan Beulich case E_GEQ:
91631847b67SJan Beulich case E_GTH:
91731847b67SJan Beulich case E_LEQ:
91831847b67SJan Beulich case E_LTH:
9191da177e4SLinus Torvalds case E_UNEQUAL:
92031847b67SJan Beulich break;
9211da177e4SLinus Torvalds default:
9221da177e4SLinus Torvalds printf("expr_calc_value: %d?\n", e->type);
9231da177e4SLinus Torvalds return no;
9241da177e4SLinus Torvalds }
92531847b67SJan Beulich
92631847b67SJan Beulich sym_calc_value(e->left.sym);
92731847b67SJan Beulich sym_calc_value(e->right.sym);
92831847b67SJan Beulich str1 = sym_get_string_value(e->left.sym);
92931847b67SJan Beulich str2 = sym_get_string_value(e->right.sym);
93031847b67SJan Beulich
93131847b67SJan Beulich if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
93231847b67SJan Beulich k1 = expr_parse_string(str1, e->left.sym->type, &lval);
93331847b67SJan Beulich k2 = expr_parse_string(str2, e->right.sym->type, &rval);
93431847b67SJan Beulich }
93531847b67SJan Beulich
93631847b67SJan Beulich if (k1 == k_string || k2 == k_string)
93731847b67SJan Beulich res = strcmp(str1, str2);
9380cbe3ac4SMasahiro Yamada else if (k1 == k_unsigned || k2 == k_unsigned)
93931847b67SJan Beulich res = (lval.u > rval.u) - (lval.u < rval.u);
94031847b67SJan Beulich else /* if (k1 == k_signed && k2 == k_signed) */
94131847b67SJan Beulich res = (lval.s > rval.s) - (lval.s < rval.s);
94231847b67SJan Beulich
94331847b67SJan Beulich switch(e->type) {
94431847b67SJan Beulich case E_EQUAL:
94531847b67SJan Beulich return res ? no : yes;
94631847b67SJan Beulich case E_GEQ:
94731847b67SJan Beulich return res >= 0 ? yes : no;
94831847b67SJan Beulich case E_GTH:
94931847b67SJan Beulich return res > 0 ? yes : no;
95031847b67SJan Beulich case E_LEQ:
95131847b67SJan Beulich return res <= 0 ? yes : no;
95231847b67SJan Beulich case E_LTH:
95331847b67SJan Beulich return res < 0 ? yes : no;
95431847b67SJan Beulich case E_UNEQUAL:
95531847b67SJan Beulich return res ? yes : no;
95631847b67SJan Beulich default:
95731847b67SJan Beulich printf("expr_calc_value: relation %d?\n", e->type);
95831847b67SJan Beulich return no;
95931847b67SJan Beulich }
9601da177e4SLinus Torvalds }
9611da177e4SLinus Torvalds
96295573cacSMasahiro Yamada /**
96395573cacSMasahiro Yamada * expr_calc_value - return the tristate value of the given expression
96495573cacSMasahiro Yamada * @e: expression
96595573cacSMasahiro Yamada * return: tristate value of the expression
96695573cacSMasahiro Yamada */
expr_calc_value(struct expr * e)96795573cacSMasahiro Yamada tristate expr_calc_value(struct expr *e)
96895573cacSMasahiro Yamada {
96995573cacSMasahiro Yamada if (!e)
97095573cacSMasahiro Yamada return yes;
97195573cacSMasahiro Yamada
97295573cacSMasahiro Yamada if (!e->val_is_valid) {
97395573cacSMasahiro Yamada e->val = __expr_calc_value(e);
97495573cacSMasahiro Yamada e->val_is_valid = true;
97595573cacSMasahiro Yamada }
97695573cacSMasahiro Yamada
97795573cacSMasahiro Yamada return e->val;
97895573cacSMasahiro Yamada }
97995573cacSMasahiro Yamada
98095573cacSMasahiro Yamada /**
98195573cacSMasahiro Yamada * expr_invalidate_all - invalidate all cached expression values
98295573cacSMasahiro Yamada */
expr_invalidate_all(void)98395573cacSMasahiro Yamada void expr_invalidate_all(void)
98495573cacSMasahiro Yamada {
98595573cacSMasahiro Yamada struct expr *e;
98695573cacSMasahiro Yamada
98795573cacSMasahiro Yamada hash_for_each(expr_hashtable, e, node)
98895573cacSMasahiro Yamada e->val_is_valid = false;
98995573cacSMasahiro Yamada }
99095573cacSMasahiro Yamada
expr_compare_type(enum expr_type t1,enum expr_type t2)991ad8d40cdSMichal Marek static int expr_compare_type(enum expr_type t1, enum expr_type t2)
9921da177e4SLinus Torvalds {
9931da177e4SLinus Torvalds if (t1 == t2)
9941da177e4SLinus Torvalds return 0;
9951da177e4SLinus Torvalds switch (t1) {
99631847b67SJan Beulich case E_LEQ:
99731847b67SJan Beulich case E_LTH:
99831847b67SJan Beulich case E_GEQ:
99931847b67SJan Beulich case E_GTH:
100031847b67SJan Beulich if (t2 == E_EQUAL || t2 == E_UNEQUAL)
100131847b67SJan Beulich return 1;
1002dfe8e56fSMasahiro Yamada /* fallthrough */
10031da177e4SLinus Torvalds case E_EQUAL:
10041da177e4SLinus Torvalds case E_UNEQUAL:
10051da177e4SLinus Torvalds if (t2 == E_NOT)
10061da177e4SLinus Torvalds return 1;
1007dfe8e56fSMasahiro Yamada /* fallthrough */
10081da177e4SLinus Torvalds case E_NOT:
10091da177e4SLinus Torvalds if (t2 == E_AND)
10101da177e4SLinus Torvalds return 1;
1011dfe8e56fSMasahiro Yamada /* fallthrough */
10121da177e4SLinus Torvalds case E_AND:
10131da177e4SLinus Torvalds if (t2 == E_OR)
10141da177e4SLinus Torvalds return 1;
1015dfe8e56fSMasahiro Yamada /* fallthrough */
10161da177e4SLinus Torvalds default:
1017cd909521SMasahiro Yamada break;
10181da177e4SLinus Torvalds }
10191da177e4SLinus Torvalds return 0;
10201da177e4SLinus Torvalds }
10211da177e4SLinus Torvalds
expr_print(const struct expr * e,void (* fn)(void *,struct symbol *,const char *),void * data,int prevtoken)10226425e3b2SMasahiro Yamada void expr_print(const struct expr *e,
10239a47ceecSMasahiro Yamada void (*fn)(void *, struct symbol *, const char *),
10249a47ceecSMasahiro Yamada void *data, int prevtoken)
10251da177e4SLinus Torvalds {
10261da177e4SLinus Torvalds if (!e) {
1027ab45d190SRoman Zippel fn(data, NULL, "y");
10281da177e4SLinus Torvalds return;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds
10311da177e4SLinus Torvalds if (expr_compare_type(prevtoken, e->type) > 0)
1032ab45d190SRoman Zippel fn(data, NULL, "(");
10331da177e4SLinus Torvalds switch (e->type) {
10341da177e4SLinus Torvalds case E_SYMBOL:
10351da177e4SLinus Torvalds if (e->left.sym->name)
1036ab45d190SRoman Zippel fn(data, e->left.sym, e->left.sym->name);
10371da177e4SLinus Torvalds else
1038ab45d190SRoman Zippel fn(data, NULL, "<choice>");
10391da177e4SLinus Torvalds break;
10401da177e4SLinus Torvalds case E_NOT:
1041ab45d190SRoman Zippel fn(data, NULL, "!");
10421da177e4SLinus Torvalds expr_print(e->left.expr, fn, data, E_NOT);
10431da177e4SLinus Torvalds break;
10441da177e4SLinus Torvalds case E_EQUAL:
1045f5eaa323SJan Beulich if (e->left.sym->name)
1046ab45d190SRoman Zippel fn(data, e->left.sym, e->left.sym->name);
1047f5eaa323SJan Beulich else
1048f5eaa323SJan Beulich fn(data, NULL, "<choice>");
1049ab45d190SRoman Zippel fn(data, NULL, "=");
1050ab45d190SRoman Zippel fn(data, e->right.sym, e->right.sym->name);
10511da177e4SLinus Torvalds break;
105231847b67SJan Beulich case E_LEQ:
105331847b67SJan Beulich case E_LTH:
105431847b67SJan Beulich if (e->left.sym->name)
105531847b67SJan Beulich fn(data, e->left.sym, e->left.sym->name);
105631847b67SJan Beulich else
105731847b67SJan Beulich fn(data, NULL, "<choice>");
105831847b67SJan Beulich fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
105931847b67SJan Beulich fn(data, e->right.sym, e->right.sym->name);
106031847b67SJan Beulich break;
106131847b67SJan Beulich case E_GEQ:
106231847b67SJan Beulich case E_GTH:
106331847b67SJan Beulich if (e->left.sym->name)
106431847b67SJan Beulich fn(data, e->left.sym, e->left.sym->name);
106531847b67SJan Beulich else
106631847b67SJan Beulich fn(data, NULL, "<choice>");
1067f6aad261SMichal Sojka fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
106831847b67SJan Beulich fn(data, e->right.sym, e->right.sym->name);
106931847b67SJan Beulich break;
10701da177e4SLinus Torvalds case E_UNEQUAL:
1071f5eaa323SJan Beulich if (e->left.sym->name)
1072ab45d190SRoman Zippel fn(data, e->left.sym, e->left.sym->name);
1073f5eaa323SJan Beulich else
1074f5eaa323SJan Beulich fn(data, NULL, "<choice>");
1075ab45d190SRoman Zippel fn(data, NULL, "!=");
1076ab45d190SRoman Zippel fn(data, e->right.sym, e->right.sym->name);
10771da177e4SLinus Torvalds break;
10781da177e4SLinus Torvalds case E_OR:
10799a47ceecSMasahiro Yamada expr_print(e->left.expr, fn, data, E_OR);
1080ab45d190SRoman Zippel fn(data, NULL, " || ");
10819a47ceecSMasahiro Yamada expr_print(e->right.expr, fn, data, E_OR);
10821da177e4SLinus Torvalds break;
10831da177e4SLinus Torvalds case E_AND:
10841da177e4SLinus Torvalds expr_print(e->left.expr, fn, data, E_AND);
1085ab45d190SRoman Zippel fn(data, NULL, " && ");
10861da177e4SLinus Torvalds expr_print(e->right.expr, fn, data, E_AND);
10871da177e4SLinus Torvalds break;
10881da177e4SLinus Torvalds case E_RANGE:
1089ab45d190SRoman Zippel fn(data, NULL, "[");
1090ab45d190SRoman Zippel fn(data, e->left.sym, e->left.sym->name);
1091ab45d190SRoman Zippel fn(data, NULL, " ");
1092ab45d190SRoman Zippel fn(data, e->right.sym, e->right.sym->name);
1093ab45d190SRoman Zippel fn(data, NULL, "]");
10941da177e4SLinus Torvalds break;
10951da177e4SLinus Torvalds default:
10961da177e4SLinus Torvalds {
10971da177e4SLinus Torvalds char buf[32];
10981da177e4SLinus Torvalds sprintf(buf, "<unknown type %d>", e->type);
1099ab45d190SRoman Zippel fn(data, NULL, buf);
11001da177e4SLinus Torvalds break;
11011da177e4SLinus Torvalds }
11021da177e4SLinus Torvalds }
11031da177e4SLinus Torvalds if (expr_compare_type(prevtoken, e->type) > 0)
1104ab45d190SRoman Zippel fn(data, NULL, ")");
11051da177e4SLinus Torvalds }
11061da177e4SLinus Torvalds
expr_print_file_helper(void * data,struct symbol * sym,const char * str)1107ab45d190SRoman Zippel static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
11081da177e4SLinus Torvalds {
1109bf5e327aSJean Sacren xfwrite(str, strlen(str), 1, data);
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds
expr_fprint(struct expr * e,FILE * out)11121da177e4SLinus Torvalds void expr_fprint(struct expr *e, FILE *out)
11131da177e4SLinus Torvalds {
11141da177e4SLinus Torvalds expr_print(e, expr_print_file_helper, out, E_NONE);
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds
expr_print_gstr_helper(void * data,struct symbol * sym,const char * str)1117ab45d190SRoman Zippel static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
11181da177e4SLinus Torvalds {
1119da60fbbcSVadim Bendebury (вб) struct gstr *gs = (struct gstr*)data;
1120da60fbbcSVadim Bendebury (вб) const char *sym_str = NULL;
1121da60fbbcSVadim Bendebury (вб)
1122544e433aSCheng Renquan if (sym)
1123da60fbbcSVadim Bendebury (вб) sym_str = sym_get_string_value(sym);
1124da60fbbcSVadim Bendebury (вб)
1125da60fbbcSVadim Bendebury (вб) if (gs->max_width) {
1126da60fbbcSVadim Bendebury (вб) unsigned extra_length = strlen(str);
1127da60fbbcSVadim Bendebury (вб) const char *last_cr = strrchr(gs->s, '\n');
1128da60fbbcSVadim Bendebury (вб) unsigned last_line_length;
1129da60fbbcSVadim Bendebury (вб)
1130da60fbbcSVadim Bendebury (вб) if (sym_str)
1131da60fbbcSVadim Bendebury (вб) extra_length += 4 + strlen(sym_str);
1132da60fbbcSVadim Bendebury (вб)
1133da60fbbcSVadim Bendebury (вб) if (!last_cr)
1134da60fbbcSVadim Bendebury (вб) last_cr = gs->s;
1135da60fbbcSVadim Bendebury (вб)
1136da60fbbcSVadim Bendebury (вб) last_line_length = strlen(gs->s) - (last_cr - gs->s);
1137da60fbbcSVadim Bendebury (вб)
1138da60fbbcSVadim Bendebury (вб) if ((last_line_length + extra_length) > gs->max_width)
1139da60fbbcSVadim Bendebury (вб) str_append(gs, "\\\n");
1140da60fbbcSVadim Bendebury (вб) }
1141da60fbbcSVadim Bendebury (вб)
1142da60fbbcSVadim Bendebury (вб) str_append(gs, str);
114370ed0747SLi Zefan if (sym && sym->type != S_UNKNOWN)
1144da60fbbcSVadim Bendebury (вб) str_printf(gs, " [=%s]", sym_str);
11451da177e4SLinus Torvalds }
11461da177e4SLinus Torvalds
expr_gstr_print(const struct expr * e,struct gstr * gs)11476425e3b2SMasahiro Yamada void expr_gstr_print(const struct expr *e, struct gstr *gs)
11481da177e4SLinus Torvalds {
11491da177e4SLinus Torvalds expr_print(e, expr_print_gstr_helper, gs, E_NONE);
11501da177e4SLinus Torvalds }
11511ccb2714SPetr Vorel
11521ccb2714SPetr Vorel /*
11531ccb2714SPetr Vorel * Transform the top level "||" tokens into newlines and prepend each
11541ccb2714SPetr Vorel * line with a minus. This makes expressions much easier to read.
11551ccb2714SPetr Vorel * Suitable for reverse dependency expressions.
11561ccb2714SPetr Vorel */
expr_print_revdep(struct expr * e,void (* fn)(void *,struct symbol *,const char *),void * data,tristate pr_type,const char ** title)11579a47ceecSMasahiro Yamada static void expr_print_revdep(struct expr *e,
11589a47ceecSMasahiro Yamada void (*fn)(void *, struct symbol *, const char *),
1159d9119b59SEugeniu Rosca void *data, tristate pr_type, const char **title)
11609a47ceecSMasahiro Yamada {
11619a47ceecSMasahiro Yamada if (e->type == E_OR) {
1162d9119b59SEugeniu Rosca expr_print_revdep(e->left.expr, fn, data, pr_type, title);
1163d9119b59SEugeniu Rosca expr_print_revdep(e->right.expr, fn, data, pr_type, title);
1164d9119b59SEugeniu Rosca } else if (expr_calc_value(e) == pr_type) {
1165d9119b59SEugeniu Rosca if (*title) {
1166d9119b59SEugeniu Rosca fn(data, NULL, *title);
1167d9119b59SEugeniu Rosca *title = NULL;
1168d9119b59SEugeniu Rosca }
1169d9119b59SEugeniu Rosca
11709a47ceecSMasahiro Yamada fn(data, NULL, " - ");
11719a47ceecSMasahiro Yamada expr_print(e, fn, data, E_NONE);
11729a47ceecSMasahiro Yamada fn(data, NULL, "\n");
11739a47ceecSMasahiro Yamada }
11749a47ceecSMasahiro Yamada }
11759a47ceecSMasahiro Yamada
expr_gstr_print_revdep(struct expr * e,struct gstr * gs,tristate pr_type,const char * title)1176d9119b59SEugeniu Rosca void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
1177d9119b59SEugeniu Rosca tristate pr_type, const char *title)
11781ccb2714SPetr Vorel {
1179d9119b59SEugeniu Rosca expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
11801ccb2714SPetr Vorel }
1181