xref: /openbmc/linux/scripts/kconfig/expr.c (revision d6b6592ac6d11eab91e6758d224eac35f4122aca)
10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
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 
121da177e4SLinus Torvalds #include "lkc.h"
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #define DEBUG_EXPR	0
151da177e4SLinus Torvalds 
16ad8d40cdSMichal Marek static struct expr *expr_eliminate_yn(struct expr *e);
17ad8d40cdSMichal Marek 
expr_alloc_symbol(struct symbol * sym)181da177e4SLinus Torvalds struct expr *expr_alloc_symbol(struct symbol *sym)
191da177e4SLinus Torvalds {
20177acf78SAlan Cox 	struct expr *e = xcalloc(1, sizeof(*e));
211da177e4SLinus Torvalds 	e->type = E_SYMBOL;
221da177e4SLinus Torvalds 	e->left.sym = sym;
231da177e4SLinus Torvalds 	return e;
241da177e4SLinus Torvalds }
251da177e4SLinus Torvalds 
expr_alloc_one(enum expr_type type,struct expr * ce)261da177e4SLinus Torvalds struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
271da177e4SLinus Torvalds {
28177acf78SAlan Cox 	struct expr *e = xcalloc(1, sizeof(*e));
291da177e4SLinus Torvalds 	e->type = type;
301da177e4SLinus Torvalds 	e->left.expr = ce;
311da177e4SLinus Torvalds 	return e;
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds 
expr_alloc_two(enum expr_type type,struct expr * e1,struct expr * e2)341da177e4SLinus Torvalds struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
351da177e4SLinus Torvalds {
36177acf78SAlan Cox 	struct expr *e = xcalloc(1, sizeof(*e));
371da177e4SLinus Torvalds 	e->type = type;
381da177e4SLinus Torvalds 	e->left.expr = e1;
391da177e4SLinus Torvalds 	e->right.expr = e2;
401da177e4SLinus Torvalds 	return e;
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds 
expr_alloc_comp(enum expr_type type,struct symbol * s1,struct symbol * s2)431da177e4SLinus Torvalds struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
441da177e4SLinus Torvalds {
45177acf78SAlan Cox 	struct expr *e = xcalloc(1, sizeof(*e));
461da177e4SLinus Torvalds 	e->type = type;
471da177e4SLinus Torvalds 	e->left.sym = s1;
481da177e4SLinus Torvalds 	e->right.sym = s2;
491da177e4SLinus Torvalds 	return e;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds 
expr_alloc_and(struct expr * e1,struct expr * e2)521da177e4SLinus Torvalds struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	if (!e1)
551da177e4SLinus Torvalds 		return e2;
561da177e4SLinus Torvalds 	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds 
expr_alloc_or(struct expr * e1,struct expr * e2)591da177e4SLinus Torvalds struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	if (!e1)
621da177e4SLinus Torvalds 		return e2;
631da177e4SLinus Torvalds 	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds 
expr_copy(const struct expr * org)6617742dc7SMichal Marek struct expr *expr_copy(const struct expr *org)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	struct expr *e;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	if (!org)
711da177e4SLinus Torvalds 		return NULL;
721da177e4SLinus Torvalds 
73177acf78SAlan Cox 	e = xmalloc(sizeof(*org));
741da177e4SLinus Torvalds 	memcpy(e, org, sizeof(*org));
751da177e4SLinus Torvalds 	switch (org->type) {
761da177e4SLinus Torvalds 	case E_SYMBOL:
771da177e4SLinus Torvalds 		e->left = org->left;
781da177e4SLinus Torvalds 		break;
791da177e4SLinus Torvalds 	case E_NOT:
801da177e4SLinus Torvalds 		e->left.expr = expr_copy(org->left.expr);
811da177e4SLinus Torvalds 		break;
821da177e4SLinus Torvalds 	case E_EQUAL:
8331847b67SJan Beulich 	case E_GEQ:
8431847b67SJan Beulich 	case E_GTH:
8531847b67SJan Beulich 	case E_LEQ:
8631847b67SJan Beulich 	case E_LTH:
871da177e4SLinus Torvalds 	case E_UNEQUAL:
881da177e4SLinus Torvalds 		e->left.sym = org->left.sym;
891da177e4SLinus Torvalds 		e->right.sym = org->right.sym;
901da177e4SLinus Torvalds 		break;
911da177e4SLinus Torvalds 	case E_AND:
921da177e4SLinus Torvalds 	case E_OR:
937a962923SRoman Zippel 	case E_LIST:
941da177e4SLinus Torvalds 		e->left.expr = expr_copy(org->left.expr);
951da177e4SLinus Torvalds 		e->right.expr = expr_copy(org->right.expr);
961da177e4SLinus Torvalds 		break;
971da177e4SLinus Torvalds 	default:
989e3e10c7SMasahiro Yamada 		fprintf(stderr, "can't copy type %d\n", e->type);
991da177e4SLinus Torvalds 		free(e);
1001da177e4SLinus Torvalds 		e = NULL;
1011da177e4SLinus Torvalds 		break;
1021da177e4SLinus Torvalds 	}
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	return e;
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
expr_free(struct expr * e)1071da177e4SLinus Torvalds void expr_free(struct expr *e)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds 	if (!e)
1101da177e4SLinus Torvalds 		return;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	switch (e->type) {
1131da177e4SLinus Torvalds 	case E_SYMBOL:
1141da177e4SLinus Torvalds 		break;
1151da177e4SLinus Torvalds 	case E_NOT:
1161da177e4SLinus Torvalds 		expr_free(e->left.expr);
1175b1374b3SUlf Magnusson 		break;
1181da177e4SLinus Torvalds 	case E_EQUAL:
11931847b67SJan Beulich 	case E_GEQ:
12031847b67SJan Beulich 	case E_GTH:
12131847b67SJan Beulich 	case E_LEQ:
12231847b67SJan Beulich 	case E_LTH:
1231da177e4SLinus Torvalds 	case E_UNEQUAL:
1241da177e4SLinus Torvalds 		break;
1251da177e4SLinus Torvalds 	case E_OR:
1261da177e4SLinus Torvalds 	case E_AND:
1271da177e4SLinus Torvalds 		expr_free(e->left.expr);
1281da177e4SLinus Torvalds 		expr_free(e->right.expr);
1291da177e4SLinus Torvalds 		break;
1301da177e4SLinus Torvalds 	default:
1319e3e10c7SMasahiro Yamada 		fprintf(stderr, "how to free type %d?\n", e->type);
1321da177e4SLinus Torvalds 		break;
1331da177e4SLinus Torvalds 	}
1341da177e4SLinus Torvalds 	free(e);
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds static int trans_count;
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds #define e1 (*ep1)
1401da177e4SLinus Torvalds #define e2 (*ep2)
1411da177e4SLinus Torvalds 
1420735f7e5SUlf Magnusson /*
1430735f7e5SUlf Magnusson  * expr_eliminate_eq() helper.
1440735f7e5SUlf Magnusson  *
1450735f7e5SUlf Magnusson  * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
1460735f7e5SUlf Magnusson  * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
1470735f7e5SUlf Magnusson  * against all other leaves. Two equal leaves are both replaced with either 'y'
1480735f7e5SUlf Magnusson  * or 'n' as appropriate for 'type', to be eliminated later.
1490735f7e5SUlf Magnusson  */
__expr_eliminate_eq(enum expr_type type,struct expr ** ep1,struct expr ** ep2)1501da177e4SLinus Torvalds static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
1511da177e4SLinus Torvalds {
1520735f7e5SUlf Magnusson 	/* Recurse down to leaves */
1530735f7e5SUlf Magnusson 
1541da177e4SLinus Torvalds 	if (e1->type == type) {
1551da177e4SLinus Torvalds 		__expr_eliminate_eq(type, &e1->left.expr, &e2);
1561da177e4SLinus Torvalds 		__expr_eliminate_eq(type, &e1->right.expr, &e2);
1571da177e4SLinus Torvalds 		return;
1581da177e4SLinus Torvalds 	}
1591da177e4SLinus Torvalds 	if (e2->type == type) {
1601da177e4SLinus Torvalds 		__expr_eliminate_eq(type, &e1, &e2->left.expr);
1611da177e4SLinus Torvalds 		__expr_eliminate_eq(type, &e1, &e2->right.expr);
1621da177e4SLinus Torvalds 		return;
1631da177e4SLinus Torvalds 	}
1640735f7e5SUlf Magnusson 
1650735f7e5SUlf Magnusson 	/* e1 and e2 are leaves. Compare them. */
1660735f7e5SUlf Magnusson 
1671da177e4SLinus Torvalds 	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
168c0e150acSRoman Zippel 	    e1->left.sym == e2->left.sym &&
169c0e150acSRoman Zippel 	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
1701da177e4SLinus Torvalds 		return;
1711da177e4SLinus Torvalds 	if (!expr_eq(e1, e2))
1721da177e4SLinus Torvalds 		return;
1730735f7e5SUlf Magnusson 
1740735f7e5SUlf Magnusson 	/* e1 and e2 are equal leaves. Prepare them for elimination. */
1750735f7e5SUlf Magnusson 
1761da177e4SLinus Torvalds 	trans_count++;
1771da177e4SLinus Torvalds 	expr_free(e1); expr_free(e2);
1781da177e4SLinus Torvalds 	switch (type) {
1791da177e4SLinus Torvalds 	case E_OR:
1801da177e4SLinus Torvalds 		e1 = expr_alloc_symbol(&symbol_no);
1811da177e4SLinus Torvalds 		e2 = expr_alloc_symbol(&symbol_no);
1821da177e4SLinus Torvalds 		break;
1831da177e4SLinus Torvalds 	case E_AND:
1841da177e4SLinus Torvalds 		e1 = expr_alloc_symbol(&symbol_yes);
1851da177e4SLinus Torvalds 		e2 = expr_alloc_symbol(&symbol_yes);
1861da177e4SLinus Torvalds 		break;
1871da177e4SLinus Torvalds 	default:
1881da177e4SLinus Torvalds 		;
1891da177e4SLinus Torvalds 	}
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds 
1920735f7e5SUlf Magnusson /*
1930735f7e5SUlf Magnusson  * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both.
1940735f7e5SUlf Magnusson  * Example reductions:
1950735f7e5SUlf Magnusson  *
1960735f7e5SUlf Magnusson  *	ep1: A && B           ->  ep1: y
1970735f7e5SUlf Magnusson  *	ep2: A && B && C      ->  ep2: C
1980735f7e5SUlf Magnusson  *
1990735f7e5SUlf Magnusson  *	ep1: A || B           ->  ep1: n
2000735f7e5SUlf Magnusson  *	ep2: A || B || C      ->  ep2: C
2010735f7e5SUlf Magnusson  *
2020735f7e5SUlf Magnusson  *	ep1: A && (B && FOO)  ->  ep1: FOO
2030735f7e5SUlf Magnusson  *	ep2: (BAR && B) && A  ->  ep2: BAR
2040735f7e5SUlf Magnusson  *
2050735f7e5SUlf Magnusson  *	ep1: A && (B || C)    ->  ep1: y
2060735f7e5SUlf Magnusson  *	ep2: (C || B) && A    ->  ep2: y
2070735f7e5SUlf Magnusson  *
2080735f7e5SUlf Magnusson  * Comparisons are done between all operands at the same "level" of && or ||.
2090735f7e5SUlf Magnusson  * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the
2100735f7e5SUlf Magnusson  * following operands will be compared:
2110735f7e5SUlf Magnusson  *
2120735f7e5SUlf Magnusson  *	- 'e1', 'e2 || e3', and 'e4 || e5', against each other
2130735f7e5SUlf Magnusson  *	- e2 against e3
2140735f7e5SUlf Magnusson  *	- e4 against e5
2150735f7e5SUlf Magnusson  *
2160735f7e5SUlf Magnusson  * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and
2170735f7e5SUlf Magnusson  * '(e1 && e2) && e3' are both a single level.
2180735f7e5SUlf Magnusson  *
2190735f7e5SUlf Magnusson  * See __expr_eliminate_eq() as well.
2200735f7e5SUlf Magnusson  */
expr_eliminate_eq(struct expr ** ep1,struct expr ** ep2)2211da177e4SLinus Torvalds void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
2221da177e4SLinus Torvalds {
2231da177e4SLinus Torvalds 	if (!e1 || !e2)
2241da177e4SLinus Torvalds 		return;
2251da177e4SLinus Torvalds 	switch (e1->type) {
2261da177e4SLinus Torvalds 	case E_OR:
2271da177e4SLinus Torvalds 	case E_AND:
2281da177e4SLinus Torvalds 		__expr_eliminate_eq(e1->type, ep1, ep2);
2291da177e4SLinus Torvalds 	default:
2301da177e4SLinus Torvalds 		;
2311da177e4SLinus Torvalds 	}
2321da177e4SLinus Torvalds 	if (e1->type != e2->type) switch (e2->type) {
2331da177e4SLinus Torvalds 	case E_OR:
2341da177e4SLinus Torvalds 	case E_AND:
2351da177e4SLinus Torvalds 		__expr_eliminate_eq(e2->type, ep1, ep2);
2361da177e4SLinus Torvalds 	default:
2371da177e4SLinus Torvalds 		;
2381da177e4SLinus Torvalds 	}
2391da177e4SLinus Torvalds 	e1 = expr_eliminate_yn(e1);
2401da177e4SLinus Torvalds 	e2 = expr_eliminate_yn(e2);
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds #undef e1
2441da177e4SLinus Torvalds #undef e2
2451da177e4SLinus Torvalds 
2460735f7e5SUlf Magnusson /*
2470735f7e5SUlf Magnusson  * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
2480735f7e5SUlf Magnusson  * &&/|| expressions are considered equal if every operand in one expression
2490735f7e5SUlf Magnusson  * equals some operand in the other (operands do not need to appear in the same
2500735f7e5SUlf Magnusson  * order), recursively.
2510735f7e5SUlf Magnusson  */
expr_eq(struct expr * e1,struct expr * e2)252*3460d0bcSThomas Hebb int expr_eq(struct expr *e1, struct expr *e2)
2531da177e4SLinus Torvalds {
2541da177e4SLinus Torvalds 	int res, old_count;
2551da177e4SLinus Torvalds 
256272a7210SThomas Hebb 	/*
257272a7210SThomas Hebb 	 * A NULL expr is taken to be yes, but there's also a different way to
258272a7210SThomas Hebb 	 * represent yes. expr_is_yes() checks for either representation.
259272a7210SThomas Hebb 	 */
260272a7210SThomas Hebb 	if (!e1 || !e2)
261272a7210SThomas Hebb 		return expr_is_yes(e1) && expr_is_yes(e2);
262272a7210SThomas Hebb 
2631da177e4SLinus Torvalds 	if (e1->type != e2->type)
2641da177e4SLinus Torvalds 		return 0;
2651da177e4SLinus Torvalds 	switch (e1->type) {
2661da177e4SLinus Torvalds 	case E_EQUAL:
26731847b67SJan Beulich 	case E_GEQ:
26831847b67SJan Beulich 	case E_GTH:
26931847b67SJan Beulich 	case E_LEQ:
27031847b67SJan Beulich 	case E_LTH:
2711da177e4SLinus Torvalds 	case E_UNEQUAL:
2721da177e4SLinus Torvalds 		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
2731da177e4SLinus Torvalds 	case E_SYMBOL:
2741da177e4SLinus Torvalds 		return e1->left.sym == e2->left.sym;
2751da177e4SLinus Torvalds 	case E_NOT:
2761da177e4SLinus Torvalds 		return expr_eq(e1->left.expr, e2->left.expr);
2771da177e4SLinus Torvalds 	case E_AND:
2781da177e4SLinus Torvalds 	case E_OR:
2791da177e4SLinus Torvalds 		e1 = expr_copy(e1);
2801da177e4SLinus Torvalds 		e2 = expr_copy(e2);
2811da177e4SLinus Torvalds 		old_count = trans_count;
2821da177e4SLinus Torvalds 		expr_eliminate_eq(&e1, &e2);
2831da177e4SLinus Torvalds 		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
2841da177e4SLinus Torvalds 		       e1->left.sym == e2->left.sym);
2851da177e4SLinus Torvalds 		expr_free(e1);
2861da177e4SLinus Torvalds 		expr_free(e2);
2871da177e4SLinus Torvalds 		trans_count = old_count;
2881da177e4SLinus Torvalds 		return res;
2897a962923SRoman Zippel 	case E_LIST:
2901da177e4SLinus Torvalds 	case E_RANGE:
2911da177e4SLinus Torvalds 	case E_NONE:
2921da177e4SLinus Torvalds 		/* panic */;
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	if (DEBUG_EXPR) {
2961da177e4SLinus Torvalds 		expr_fprint(e1, stdout);
2971da177e4SLinus Torvalds 		printf(" = ");
2981da177e4SLinus Torvalds 		expr_fprint(e2, stdout);
2991da177e4SLinus Torvalds 		printf(" ?\n");
3001da177e4SLinus Torvalds 	}
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	return 0;
3031da177e4SLinus Torvalds }
3041da177e4SLinus Torvalds 
3050735f7e5SUlf Magnusson /*
3060735f7e5SUlf Magnusson  * Recursively performs the following simplifications in-place (as well as the
3070735f7e5SUlf Magnusson  * corresponding simplifications with swapped operands):
3080735f7e5SUlf Magnusson  *
3090735f7e5SUlf Magnusson  *	expr && n  ->  n
3100735f7e5SUlf Magnusson  *	expr && y  ->  expr
3110735f7e5SUlf Magnusson  *	expr || n  ->  expr
3120735f7e5SUlf Magnusson  *	expr || y  ->  y
3130735f7e5SUlf Magnusson  *
3140735f7e5SUlf Magnusson  * Returns the optimized expression.
3150735f7e5SUlf Magnusson  */
expr_eliminate_yn(struct expr * e)316ad8d40cdSMichal Marek static struct expr *expr_eliminate_yn(struct expr *e)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	struct expr *tmp;
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	if (e) switch (e->type) {
3211da177e4SLinus Torvalds 	case E_AND:
3221da177e4SLinus Torvalds 		e->left.expr = expr_eliminate_yn(e->left.expr);
3231da177e4SLinus Torvalds 		e->right.expr = expr_eliminate_yn(e->right.expr);
3241da177e4SLinus Torvalds 		if (e->left.expr->type == E_SYMBOL) {
3251da177e4SLinus Torvalds 			if (e->left.expr->left.sym == &symbol_no) {
3261da177e4SLinus Torvalds 				expr_free(e->left.expr);
3271da177e4SLinus Torvalds 				expr_free(e->right.expr);
3281da177e4SLinus Torvalds 				e->type = E_SYMBOL;
3291da177e4SLinus Torvalds 				e->left.sym = &symbol_no;
3301da177e4SLinus Torvalds 				e->right.expr = NULL;
3311da177e4SLinus Torvalds 				return e;
3321da177e4SLinus Torvalds 			} else if (e->left.expr->left.sym == &symbol_yes) {
3331da177e4SLinus Torvalds 				free(e->left.expr);
3341da177e4SLinus Torvalds 				tmp = e->right.expr;
3351da177e4SLinus Torvalds 				*e = *(e->right.expr);
3361da177e4SLinus Torvalds 				free(tmp);
3371da177e4SLinus Torvalds 				return e;
3381da177e4SLinus Torvalds 			}
3391da177e4SLinus Torvalds 		}
3401da177e4SLinus Torvalds 		if (e->right.expr->type == E_SYMBOL) {
3411da177e4SLinus Torvalds 			if (e->right.expr->left.sym == &symbol_no) {
3421da177e4SLinus Torvalds 				expr_free(e->left.expr);
3431da177e4SLinus Torvalds 				expr_free(e->right.expr);
3441da177e4SLinus Torvalds 				e->type = E_SYMBOL;
3451da177e4SLinus Torvalds 				e->left.sym = &symbol_no;
3461da177e4SLinus Torvalds 				e->right.expr = NULL;
3471da177e4SLinus Torvalds 				return e;
3481da177e4SLinus Torvalds 			} else if (e->right.expr->left.sym == &symbol_yes) {
3491da177e4SLinus Torvalds 				free(e->right.expr);
3501da177e4SLinus Torvalds 				tmp = e->left.expr;
3511da177e4SLinus Torvalds 				*e = *(e->left.expr);
3521da177e4SLinus Torvalds 				free(tmp);
3531da177e4SLinus Torvalds 				return e;
3541da177e4SLinus Torvalds 			}
3551da177e4SLinus Torvalds 		}
3561da177e4SLinus Torvalds 		break;
3571da177e4SLinus Torvalds 	case E_OR:
3581da177e4SLinus Torvalds 		e->left.expr = expr_eliminate_yn(e->left.expr);
3591da177e4SLinus Torvalds 		e->right.expr = expr_eliminate_yn(e->right.expr);
3601da177e4SLinus Torvalds 		if (e->left.expr->type == E_SYMBOL) {
3611da177e4SLinus Torvalds 			if (e->left.expr->left.sym == &symbol_no) {
3621da177e4SLinus Torvalds 				free(e->left.expr);
3631da177e4SLinus Torvalds 				tmp = e->right.expr;
3641da177e4SLinus Torvalds 				*e = *(e->right.expr);
3651da177e4SLinus Torvalds 				free(tmp);
3661da177e4SLinus Torvalds 				return e;
3671da177e4SLinus Torvalds 			} else if (e->left.expr->left.sym == &symbol_yes) {
3681da177e4SLinus Torvalds 				expr_free(e->left.expr);
3691da177e4SLinus Torvalds 				expr_free(e->right.expr);
3701da177e4SLinus Torvalds 				e->type = E_SYMBOL;
3711da177e4SLinus Torvalds 				e->left.sym = &symbol_yes;
3721da177e4SLinus Torvalds 				e->right.expr = NULL;
3731da177e4SLinus Torvalds 				return e;
3741da177e4SLinus Torvalds 			}
3751da177e4SLinus Torvalds 		}
3761da177e4SLinus Torvalds 		if (e->right.expr->type == E_SYMBOL) {
3771da177e4SLinus Torvalds 			if (e->right.expr->left.sym == &symbol_no) {
3781da177e4SLinus Torvalds 				free(e->right.expr);
3791da177e4SLinus Torvalds 				tmp = e->left.expr;
3801da177e4SLinus Torvalds 				*e = *(e->left.expr);
3811da177e4SLinus Torvalds 				free(tmp);
3821da177e4SLinus Torvalds 				return e;
3831da177e4SLinus Torvalds 			} else if (e->right.expr->left.sym == &symbol_yes) {
3841da177e4SLinus Torvalds 				expr_free(e->left.expr);
3851da177e4SLinus Torvalds 				expr_free(e->right.expr);
3861da177e4SLinus Torvalds 				e->type = E_SYMBOL;
3871da177e4SLinus Torvalds 				e->left.sym = &symbol_yes;
3881da177e4SLinus Torvalds 				e->right.expr = NULL;
3891da177e4SLinus Torvalds 				return e;
3901da177e4SLinus Torvalds 			}
3911da177e4SLinus Torvalds 		}
3921da177e4SLinus Torvalds 		break;
3931da177e4SLinus Torvalds 	default:
3941da177e4SLinus Torvalds 		;
3951da177e4SLinus Torvalds 	}
3961da177e4SLinus Torvalds 	return e;
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds /*
4001da177e4SLinus Torvalds  * e1 || e2 -> ?
4011da177e4SLinus Torvalds  */
expr_join_or(struct expr * e1,struct expr * e2)4024356f489STrevor Keith static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds 	struct expr *tmp;
4051da177e4SLinus Torvalds 	struct symbol *sym1, *sym2;
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	if (expr_eq(e1, e2))
4081da177e4SLinus Torvalds 		return expr_copy(e1);
4091da177e4SLinus Torvalds 	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
4101da177e4SLinus Torvalds 		return NULL;
4111da177e4SLinus Torvalds 	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
4121da177e4SLinus Torvalds 		return NULL;
4131da177e4SLinus Torvalds 	if (e1->type == E_NOT) {
4141da177e4SLinus Torvalds 		tmp = e1->left.expr;
4151da177e4SLinus Torvalds 		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
4161da177e4SLinus Torvalds 			return NULL;
4171da177e4SLinus Torvalds 		sym1 = tmp->left.sym;
4181da177e4SLinus Torvalds 	} else
4191da177e4SLinus Torvalds 		sym1 = e1->left.sym;
4201da177e4SLinus Torvalds 	if (e2->type == E_NOT) {
4211da177e4SLinus Torvalds 		if (e2->left.expr->type != E_SYMBOL)
4221da177e4SLinus Torvalds 			return NULL;
4231da177e4SLinus Torvalds 		sym2 = e2->left.expr->left.sym;
4241da177e4SLinus Torvalds 	} else
4251da177e4SLinus Torvalds 		sym2 = e2->left.sym;
4261da177e4SLinus Torvalds 	if (sym1 != sym2)
4271da177e4SLinus Torvalds 		return NULL;
4281da177e4SLinus Torvalds 	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
4291da177e4SLinus Torvalds 		return NULL;
4301da177e4SLinus Torvalds 	if (sym1->type == S_TRISTATE) {
4311da177e4SLinus Torvalds 		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
4321da177e4SLinus Torvalds 		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
4331da177e4SLinus Torvalds 		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
4341da177e4SLinus Torvalds 			// (a='y') || (a='m') -> (a!='n')
4351da177e4SLinus Torvalds 			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
4361da177e4SLinus Torvalds 		}
4371da177e4SLinus Torvalds 		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
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_UNEQUAL, sym1, &symbol_mod);
4421da177e4SLinus Torvalds 		}
4431da177e4SLinus Torvalds 		if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
4441da177e4SLinus Torvalds 		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
4451da177e4SLinus Torvalds 		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
4461da177e4SLinus Torvalds 			// (a='m') || (a='n') -> (a!='y')
4471da177e4SLinus Torvalds 			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
4481da177e4SLinus Torvalds 		}
4491da177e4SLinus Torvalds 	}
4501da177e4SLinus Torvalds 	if (sym1->type == S_BOOLEAN && sym1 == sym2) {
4511da177e4SLinus Torvalds 		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
4521da177e4SLinus Torvalds 		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
4531da177e4SLinus Torvalds 			return expr_alloc_symbol(&symbol_yes);
4541da177e4SLinus Torvalds 	}
4551da177e4SLinus Torvalds 
4561da177e4SLinus Torvalds 	if (DEBUG_EXPR) {
4571da177e4SLinus Torvalds 		printf("optimize (");
4581da177e4SLinus Torvalds 		expr_fprint(e1, stdout);
4591da177e4SLinus Torvalds 		printf(") || (");
4601da177e4SLinus Torvalds 		expr_fprint(e2, stdout);
4611da177e4SLinus Torvalds 		printf(")?\n");
4621da177e4SLinus Torvalds 	}
4631da177e4SLinus Torvalds 	return NULL;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
expr_join_and(struct expr * e1,struct expr * e2)4664356f489STrevor Keith static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
4671da177e4SLinus Torvalds {
4681da177e4SLinus Torvalds 	struct expr *tmp;
4691da177e4SLinus Torvalds 	struct symbol *sym1, *sym2;
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	if (expr_eq(e1, e2))
4721da177e4SLinus Torvalds 		return expr_copy(e1);
4731da177e4SLinus Torvalds 	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
4741da177e4SLinus Torvalds 		return NULL;
4751da177e4SLinus Torvalds 	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
4761da177e4SLinus Torvalds 		return NULL;
4771da177e4SLinus Torvalds 	if (e1->type == E_NOT) {
4781da177e4SLinus Torvalds 		tmp = e1->left.expr;
4791da177e4SLinus Torvalds 		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
4801da177e4SLinus Torvalds 			return NULL;
4811da177e4SLinus Torvalds 		sym1 = tmp->left.sym;
4821da177e4SLinus Torvalds 	} else
4831da177e4SLinus Torvalds 		sym1 = e1->left.sym;
4841da177e4SLinus Torvalds 	if (e2->type == E_NOT) {
4851da177e4SLinus Torvalds 		if (e2->left.expr->type != E_SYMBOL)
4861da177e4SLinus Torvalds 			return NULL;
4871da177e4SLinus Torvalds 		sym2 = e2->left.expr->left.sym;
4881da177e4SLinus Torvalds 	} else
4891da177e4SLinus Torvalds 		sym2 = e2->left.sym;
4901da177e4SLinus Torvalds 	if (sym1 != sym2)
4911da177e4SLinus Torvalds 		return NULL;
4921da177e4SLinus Torvalds 	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
4931da177e4SLinus Torvalds 		return NULL;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
4961da177e4SLinus Torvalds 	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
4971da177e4SLinus Torvalds 		// (a) && (a='y') -> (a='y')
4981da177e4SLinus Torvalds 		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
5011da177e4SLinus Torvalds 	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
5021da177e4SLinus Torvalds 		// (a) && (a!='n') -> (a)
5031da177e4SLinus Torvalds 		return expr_alloc_symbol(sym1);
5041da177e4SLinus Torvalds 
5051da177e4SLinus Torvalds 	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
5061da177e4SLinus Torvalds 	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
5071da177e4SLinus Torvalds 		// (a) && (a!='m') -> (a='y')
5081da177e4SLinus Torvalds 		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
5091da177e4SLinus Torvalds 
5101da177e4SLinus Torvalds 	if (sym1->type == S_TRISTATE) {
5111da177e4SLinus Torvalds 		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
5121da177e4SLinus Torvalds 			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
5131da177e4SLinus Torvalds 			sym2 = e1->right.sym;
5141da177e4SLinus Torvalds 			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
5151da177e4SLinus Torvalds 				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
5161da177e4SLinus Torvalds 							     : expr_alloc_symbol(&symbol_no);
5171da177e4SLinus Torvalds 		}
5181da177e4SLinus Torvalds 		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
5191da177e4SLinus Torvalds 			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
5201da177e4SLinus Torvalds 			sym2 = e2->right.sym;
5211da177e4SLinus Torvalds 			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
5221da177e4SLinus Torvalds 				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
5231da177e4SLinus Torvalds 							     : expr_alloc_symbol(&symbol_no);
5241da177e4SLinus Torvalds 		}
5251da177e4SLinus Torvalds 		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
5261da177e4SLinus Torvalds 			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
5271da177e4SLinus Torvalds 			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
5281da177e4SLinus Torvalds 			// (a!='y') && (a!='n') -> (a='m')
5291da177e4SLinus Torvalds 			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
5321da177e4SLinus Torvalds 			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
5331da177e4SLinus Torvalds 			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
5341da177e4SLinus Torvalds 			// (a!='y') && (a!='m') -> (a='n')
5351da177e4SLinus Torvalds 			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
5381da177e4SLinus Torvalds 			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
5391da177e4SLinus Torvalds 			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
5401da177e4SLinus Torvalds 			// (a!='m') && (a!='n') -> (a='m')
5411da177e4SLinus Torvalds 			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
5441da177e4SLinus Torvalds 		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
5451da177e4SLinus Torvalds 		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
5461da177e4SLinus Torvalds 		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
5471da177e4SLinus Torvalds 			return NULL;
5481da177e4SLinus Torvalds 	}
5491da177e4SLinus Torvalds 
5501da177e4SLinus Torvalds 	if (DEBUG_EXPR) {
5511da177e4SLinus Torvalds 		printf("optimize (");
5521da177e4SLinus Torvalds 		expr_fprint(e1, stdout);
5531da177e4SLinus Torvalds 		printf(") && (");
5541da177e4SLinus Torvalds 		expr_fprint(e2, stdout);
5551da177e4SLinus Torvalds 		printf(")?\n");
5561da177e4SLinus Torvalds 	}
5571da177e4SLinus Torvalds 	return NULL;
5581da177e4SLinus Torvalds }
5591da177e4SLinus Torvalds 
5600735f7e5SUlf Magnusson /*
5610735f7e5SUlf Magnusson  * expr_eliminate_dups() helper.
5620735f7e5SUlf Magnusson  *
5630735f7e5SUlf Magnusson  * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
5640735f7e5SUlf Magnusson  * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
5650735f7e5SUlf Magnusson  * against all other leaves to look for simplifications.
5660735f7e5SUlf Magnusson  */
expr_eliminate_dups1(enum expr_type type,struct expr ** ep1,struct expr ** ep2)5671da177e4SLinus Torvalds static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
5681da177e4SLinus Torvalds {
5691da177e4SLinus Torvalds #define e1 (*ep1)
5701da177e4SLinus Torvalds #define e2 (*ep2)
5711da177e4SLinus Torvalds 	struct expr *tmp;
5721da177e4SLinus Torvalds 
5730735f7e5SUlf Magnusson 	/* Recurse down to leaves */
5740735f7e5SUlf Magnusson 
5751da177e4SLinus Torvalds 	if (e1->type == type) {
5761da177e4SLinus Torvalds 		expr_eliminate_dups1(type, &e1->left.expr, &e2);
5771da177e4SLinus Torvalds 		expr_eliminate_dups1(type, &e1->right.expr, &e2);
5781da177e4SLinus Torvalds 		return;
5791da177e4SLinus Torvalds 	}
5801da177e4SLinus Torvalds 	if (e2->type == type) {
5811da177e4SLinus Torvalds 		expr_eliminate_dups1(type, &e1, &e2->left.expr);
5821da177e4SLinus Torvalds 		expr_eliminate_dups1(type, &e1, &e2->right.expr);
5831da177e4SLinus Torvalds 		return;
5841da177e4SLinus Torvalds 	}
5850735f7e5SUlf Magnusson 
5860735f7e5SUlf Magnusson 	/* e1 and e2 are leaves. Compare and process them. */
5870735f7e5SUlf Magnusson 
5881da177e4SLinus Torvalds 	if (e1 == e2)
5891da177e4SLinus Torvalds 		return;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	switch (e1->type) {
5921da177e4SLinus Torvalds 	case E_OR: case E_AND:
5931da177e4SLinus Torvalds 		expr_eliminate_dups1(e1->type, &e1, &e1);
5941da177e4SLinus Torvalds 	default:
5951da177e4SLinus Torvalds 		;
5961da177e4SLinus Torvalds 	}
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds 	switch (type) {
5991da177e4SLinus Torvalds 	case E_OR:
6001da177e4SLinus Torvalds 		tmp = expr_join_or(e1, e2);
6011da177e4SLinus Torvalds 		if (tmp) {
6021da177e4SLinus Torvalds 			expr_free(e1); expr_free(e2);
6031da177e4SLinus Torvalds 			e1 = expr_alloc_symbol(&symbol_no);
6041da177e4SLinus Torvalds 			e2 = tmp;
6051da177e4SLinus Torvalds 			trans_count++;
6061da177e4SLinus Torvalds 		}
6071da177e4SLinus Torvalds 		break;
6081da177e4SLinus Torvalds 	case E_AND:
6091da177e4SLinus Torvalds 		tmp = expr_join_and(e1, e2);
6101da177e4SLinus Torvalds 		if (tmp) {
6111da177e4SLinus Torvalds 			expr_free(e1); expr_free(e2);
6121da177e4SLinus Torvalds 			e1 = expr_alloc_symbol(&symbol_yes);
6131da177e4SLinus Torvalds 			e2 = tmp;
6141da177e4SLinus Torvalds 			trans_count++;
6151da177e4SLinus Torvalds 		}
6161da177e4SLinus Torvalds 		break;
6171da177e4SLinus Torvalds 	default:
6181da177e4SLinus Torvalds 		;
6191da177e4SLinus Torvalds 	}
6201da177e4SLinus Torvalds #undef e1
6211da177e4SLinus Torvalds #undef e2
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds 
6240735f7e5SUlf Magnusson /*
6250735f7e5SUlf Magnusson  * Rewrites 'e' in-place to remove ("join") duplicate and other redundant
6260735f7e5SUlf Magnusson  * operands.
6270735f7e5SUlf Magnusson  *
6280735f7e5SUlf Magnusson  * Example simplifications:
6290735f7e5SUlf Magnusson  *
6300735f7e5SUlf Magnusson  *	A || B || A    ->  A || B
6310735f7e5SUlf Magnusson  *	A && B && A=y  ->  A=y && B
6320735f7e5SUlf Magnusson  *
6330735f7e5SUlf Magnusson  * Returns the deduplicated expression.
6340735f7e5SUlf Magnusson  */
expr_eliminate_dups(struct expr * e)6351da177e4SLinus Torvalds struct expr *expr_eliminate_dups(struct expr *e)
6361da177e4SLinus Torvalds {
6371da177e4SLinus Torvalds 	int oldcount;
6381da177e4SLinus Torvalds 	if (!e)
6391da177e4SLinus Torvalds 		return e;
6401da177e4SLinus Torvalds 
6411da177e4SLinus Torvalds 	oldcount = trans_count;
6421da177e4SLinus Torvalds 	while (1) {
6431da177e4SLinus Torvalds 		trans_count = 0;
6441da177e4SLinus Torvalds 		switch (e->type) {
6451da177e4SLinus Torvalds 		case E_OR: case E_AND:
6461da177e4SLinus Torvalds 			expr_eliminate_dups1(e->type, &e, &e);
6471da177e4SLinus Torvalds 		default:
6481da177e4SLinus Torvalds 			;
6491da177e4SLinus Torvalds 		}
6501da177e4SLinus Torvalds 		if (!trans_count)
6510735f7e5SUlf Magnusson 			/* No simplifications done in this pass. We're done */
6521da177e4SLinus Torvalds 			break;
6531da177e4SLinus Torvalds 		e = expr_eliminate_yn(e);
6541da177e4SLinus Torvalds 	}
6551da177e4SLinus Torvalds 	trans_count = oldcount;
6561da177e4SLinus Torvalds 	return e;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds 
6590735f7e5SUlf Magnusson /*
6600735f7e5SUlf Magnusson  * Performs various simplifications involving logical operators and
6610735f7e5SUlf Magnusson  * comparisons.
6620735f7e5SUlf Magnusson  *
6630735f7e5SUlf Magnusson  * Allocates and returns a new expression.
6640735f7e5SUlf Magnusson  */
expr_transform(struct expr * e)6651da177e4SLinus Torvalds struct expr *expr_transform(struct expr *e)
6661da177e4SLinus Torvalds {
6671da177e4SLinus Torvalds 	struct expr *tmp;
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	if (!e)
6701da177e4SLinus Torvalds 		return NULL;
6711da177e4SLinus Torvalds 	switch (e->type) {
6721da177e4SLinus Torvalds 	case E_EQUAL:
67331847b67SJan Beulich 	case E_GEQ:
67431847b67SJan Beulich 	case E_GTH:
67531847b67SJan Beulich 	case E_LEQ:
67631847b67SJan Beulich 	case E_LTH:
6771da177e4SLinus Torvalds 	case E_UNEQUAL:
6781da177e4SLinus Torvalds 	case E_SYMBOL:
6797a962923SRoman Zippel 	case E_LIST:
6801da177e4SLinus Torvalds 		break;
6811da177e4SLinus Torvalds 	default:
6821da177e4SLinus Torvalds 		e->left.expr = expr_transform(e->left.expr);
6831da177e4SLinus Torvalds 		e->right.expr = expr_transform(e->right.expr);
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	switch (e->type) {
6871da177e4SLinus Torvalds 	case E_EQUAL:
6881da177e4SLinus Torvalds 		if (e->left.sym->type != S_BOOLEAN)
6891da177e4SLinus Torvalds 			break;
6901da177e4SLinus Torvalds 		if (e->right.sym == &symbol_no) {
6911da177e4SLinus Torvalds 			e->type = E_NOT;
6921da177e4SLinus Torvalds 			e->left.expr = expr_alloc_symbol(e->left.sym);
6931da177e4SLinus Torvalds 			e->right.sym = NULL;
6941da177e4SLinus Torvalds 			break;
6951da177e4SLinus Torvalds 		}
6961da177e4SLinus Torvalds 		if (e->right.sym == &symbol_mod) {
6971da177e4SLinus Torvalds 			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
6981da177e4SLinus Torvalds 			e->type = E_SYMBOL;
6991da177e4SLinus Torvalds 			e->left.sym = &symbol_no;
7001da177e4SLinus Torvalds 			e->right.sym = NULL;
7011da177e4SLinus Torvalds 			break;
7021da177e4SLinus Torvalds 		}
7031da177e4SLinus Torvalds 		if (e->right.sym == &symbol_yes) {
7041da177e4SLinus Torvalds 			e->type = E_SYMBOL;
7051da177e4SLinus Torvalds 			e->right.sym = NULL;
7061da177e4SLinus Torvalds 			break;
7071da177e4SLinus Torvalds 		}
7081da177e4SLinus Torvalds 		break;
7091da177e4SLinus Torvalds 	case E_UNEQUAL:
7101da177e4SLinus Torvalds 		if (e->left.sym->type != S_BOOLEAN)
7111da177e4SLinus Torvalds 			break;
7121da177e4SLinus Torvalds 		if (e->right.sym == &symbol_no) {
7131da177e4SLinus Torvalds 			e->type = E_SYMBOL;
7141da177e4SLinus Torvalds 			e->right.sym = NULL;
7151da177e4SLinus Torvalds 			break;
7161da177e4SLinus Torvalds 		}
7171da177e4SLinus Torvalds 		if (e->right.sym == &symbol_mod) {
7181da177e4SLinus Torvalds 			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
7191da177e4SLinus Torvalds 			e->type = E_SYMBOL;
7201da177e4SLinus Torvalds 			e->left.sym = &symbol_yes;
7211da177e4SLinus Torvalds 			e->right.sym = NULL;
7221da177e4SLinus Torvalds 			break;
7231da177e4SLinus Torvalds 		}
7241da177e4SLinus Torvalds 		if (e->right.sym == &symbol_yes) {
7251da177e4SLinus Torvalds 			e->type = E_NOT;
7261da177e4SLinus Torvalds 			e->left.expr = expr_alloc_symbol(e->left.sym);
7271da177e4SLinus Torvalds 			e->right.sym = NULL;
7281da177e4SLinus Torvalds 			break;
7291da177e4SLinus Torvalds 		}
7301da177e4SLinus Torvalds 		break;
7311da177e4SLinus Torvalds 	case E_NOT:
7321da177e4SLinus Torvalds 		switch (e->left.expr->type) {
7331da177e4SLinus Torvalds 		case E_NOT:
7341da177e4SLinus Torvalds 			// !!a -> a
7351da177e4SLinus Torvalds 			tmp = e->left.expr->left.expr;
7361da177e4SLinus Torvalds 			free(e->left.expr);
7371da177e4SLinus Torvalds 			free(e);
7381da177e4SLinus Torvalds 			e = tmp;
7391da177e4SLinus Torvalds 			e = expr_transform(e);
7401da177e4SLinus Torvalds 			break;
7411da177e4SLinus Torvalds 		case E_EQUAL:
7421da177e4SLinus Torvalds 		case E_UNEQUAL:
7431da177e4SLinus Torvalds 			// !a='x' -> a!='x'
7441da177e4SLinus Torvalds 			tmp = e->left.expr;
7451da177e4SLinus Torvalds 			free(e);
7461da177e4SLinus Torvalds 			e = tmp;
7471da177e4SLinus Torvalds 			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
7481da177e4SLinus Torvalds 			break;
74931847b67SJan Beulich 		case E_LEQ:
75031847b67SJan Beulich 		case E_GEQ:
75131847b67SJan Beulich 			// !a<='x' -> a>'x'
75231847b67SJan Beulich 			tmp = e->left.expr;
75331847b67SJan Beulich 			free(e);
75431847b67SJan Beulich 			e = tmp;
75531847b67SJan Beulich 			e->type = e->type == E_LEQ ? E_GTH : E_LTH;
75631847b67SJan Beulich 			break;
75731847b67SJan Beulich 		case E_LTH:
75831847b67SJan Beulich 		case E_GTH:
75931847b67SJan Beulich 			// !a<'x' -> a>='x'
76031847b67SJan Beulich 			tmp = e->left.expr;
76131847b67SJan Beulich 			free(e);
76231847b67SJan Beulich 			e = tmp;
76331847b67SJan Beulich 			e->type = e->type == E_LTH ? E_GEQ : E_LEQ;
76431847b67SJan Beulich 			break;
7651da177e4SLinus Torvalds 		case E_OR:
7661da177e4SLinus Torvalds 			// !(a || b) -> !a && !b
7671da177e4SLinus Torvalds 			tmp = e->left.expr;
7681da177e4SLinus Torvalds 			e->type = E_AND;
7691da177e4SLinus Torvalds 			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
7701da177e4SLinus Torvalds 			tmp->type = E_NOT;
7711da177e4SLinus Torvalds 			tmp->right.expr = NULL;
7721da177e4SLinus Torvalds 			e = expr_transform(e);
7731da177e4SLinus Torvalds 			break;
7741da177e4SLinus Torvalds 		case E_AND:
7751da177e4SLinus Torvalds 			// !(a && b) -> !a || !b
7761da177e4SLinus Torvalds 			tmp = e->left.expr;
7771da177e4SLinus Torvalds 			e->type = E_OR;
7781da177e4SLinus Torvalds 			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
7791da177e4SLinus Torvalds 			tmp->type = E_NOT;
7801da177e4SLinus Torvalds 			tmp->right.expr = NULL;
7811da177e4SLinus Torvalds 			e = expr_transform(e);
7821da177e4SLinus Torvalds 			break;
7831da177e4SLinus Torvalds 		case E_SYMBOL:
7841da177e4SLinus Torvalds 			if (e->left.expr->left.sym == &symbol_yes) {
7851da177e4SLinus Torvalds 				// !'y' -> 'n'
7861da177e4SLinus Torvalds 				tmp = e->left.expr;
7871da177e4SLinus Torvalds 				free(e);
7881da177e4SLinus Torvalds 				e = tmp;
7891da177e4SLinus Torvalds 				e->type = E_SYMBOL;
7901da177e4SLinus Torvalds 				e->left.sym = &symbol_no;
7911da177e4SLinus Torvalds 				break;
7921da177e4SLinus Torvalds 			}
7931da177e4SLinus Torvalds 			if (e->left.expr->left.sym == &symbol_mod) {
7941da177e4SLinus Torvalds 				// !'m' -> 'm'
7951da177e4SLinus Torvalds 				tmp = e->left.expr;
7961da177e4SLinus Torvalds 				free(e);
7971da177e4SLinus Torvalds 				e = tmp;
7981da177e4SLinus Torvalds 				e->type = E_SYMBOL;
7991da177e4SLinus Torvalds 				e->left.sym = &symbol_mod;
8001da177e4SLinus Torvalds 				break;
8011da177e4SLinus Torvalds 			}
8021da177e4SLinus Torvalds 			if (e->left.expr->left.sym == &symbol_no) {
8031da177e4SLinus Torvalds 				// !'n' -> 'y'
8041da177e4SLinus Torvalds 				tmp = e->left.expr;
8051da177e4SLinus Torvalds 				free(e);
8061da177e4SLinus Torvalds 				e = tmp;
8071da177e4SLinus Torvalds 				e->type = E_SYMBOL;
8081da177e4SLinus Torvalds 				e->left.sym = &symbol_yes;
8091da177e4SLinus Torvalds 				break;
8101da177e4SLinus Torvalds 			}
8111da177e4SLinus Torvalds 			break;
8121da177e4SLinus Torvalds 		default:
8131da177e4SLinus Torvalds 			;
8141da177e4SLinus Torvalds 		}
8151da177e4SLinus Torvalds 		break;
8161da177e4SLinus Torvalds 	default:
8171da177e4SLinus Torvalds 		;
8181da177e4SLinus Torvalds 	}
8191da177e4SLinus Torvalds 	return e;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds 
expr_contains_symbol(struct expr * dep,struct symbol * sym)8221da177e4SLinus Torvalds int expr_contains_symbol(struct expr *dep, struct symbol *sym)
8231da177e4SLinus Torvalds {
8241da177e4SLinus Torvalds 	if (!dep)
8251da177e4SLinus Torvalds 		return 0;
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 	switch (dep->type) {
8281da177e4SLinus Torvalds 	case E_AND:
8291da177e4SLinus Torvalds 	case E_OR:
8301da177e4SLinus Torvalds 		return expr_contains_symbol(dep->left.expr, sym) ||
8311da177e4SLinus Torvalds 		       expr_contains_symbol(dep->right.expr, sym);
8321da177e4SLinus Torvalds 	case E_SYMBOL:
8331da177e4SLinus Torvalds 		return dep->left.sym == sym;
8341da177e4SLinus Torvalds 	case E_EQUAL:
83531847b67SJan Beulich 	case E_GEQ:
83631847b67SJan Beulich 	case E_GTH:
83731847b67SJan Beulich 	case E_LEQ:
83831847b67SJan Beulich 	case E_LTH:
8391da177e4SLinus Torvalds 	case E_UNEQUAL:
8401da177e4SLinus Torvalds 		return dep->left.sym == sym ||
8411da177e4SLinus Torvalds 		       dep->right.sym == sym;
8421da177e4SLinus Torvalds 	case E_NOT:
8431da177e4SLinus Torvalds 		return expr_contains_symbol(dep->left.expr, sym);
8441da177e4SLinus Torvalds 	default:
8451da177e4SLinus Torvalds 		;
8461da177e4SLinus Torvalds 	}
8471da177e4SLinus Torvalds 	return 0;
8481da177e4SLinus Torvalds }
8491da177e4SLinus Torvalds 
expr_depends_symbol(struct expr * dep,struct symbol * sym)8501da177e4SLinus Torvalds bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
8511da177e4SLinus Torvalds {
8521da177e4SLinus Torvalds 	if (!dep)
8531da177e4SLinus Torvalds 		return false;
8541da177e4SLinus Torvalds 
8551da177e4SLinus Torvalds 	switch (dep->type) {
8561da177e4SLinus Torvalds 	case E_AND:
8571da177e4SLinus Torvalds 		return expr_depends_symbol(dep->left.expr, sym) ||
8581da177e4SLinus Torvalds 		       expr_depends_symbol(dep->right.expr, sym);
8591da177e4SLinus Torvalds 	case E_SYMBOL:
8601da177e4SLinus Torvalds 		return dep->left.sym == sym;
8611da177e4SLinus Torvalds 	case E_EQUAL:
8621da177e4SLinus Torvalds 		if (dep->left.sym == sym) {
8631da177e4SLinus Torvalds 			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
8641da177e4SLinus Torvalds 				return true;
8651da177e4SLinus Torvalds 		}
8661da177e4SLinus Torvalds 		break;
8671da177e4SLinus Torvalds 	case E_UNEQUAL:
8681da177e4SLinus Torvalds 		if (dep->left.sym == sym) {
8691da177e4SLinus Torvalds 			if (dep->right.sym == &symbol_no)
8701da177e4SLinus Torvalds 				return true;
8711da177e4SLinus Torvalds 		}
8721da177e4SLinus Torvalds 		break;
8731da177e4SLinus Torvalds 	default:
8741da177e4SLinus Torvalds 		;
8751da177e4SLinus Torvalds 	}
8761da177e4SLinus Torvalds  	return false;
8771da177e4SLinus Torvalds }
8781da177e4SLinus Torvalds 
8790735f7e5SUlf Magnusson /*
8800735f7e5SUlf Magnusson  * Inserts explicit comparisons of type 'type' to symbol 'sym' into the
8810735f7e5SUlf Magnusson  * expression 'e'.
8820735f7e5SUlf Magnusson  *
8830735f7e5SUlf Magnusson  * Examples transformations for type == E_UNEQUAL, sym == &symbol_no:
8840735f7e5SUlf Magnusson  *
8850735f7e5SUlf Magnusson  *	A              ->  A!=n
8860735f7e5SUlf Magnusson  *	!A             ->  A=n
8870735f7e5SUlf Magnusson  *	A && B         ->  !(A=n || B=n)
8880735f7e5SUlf Magnusson  *	A || B         ->  !(A=n && B=n)
8890735f7e5SUlf Magnusson  *	A && (B || C)  ->  !(A=n || (B=n && C=n))
8900735f7e5SUlf Magnusson  *
8910735f7e5SUlf Magnusson  * Allocates and returns a new expression.
8920735f7e5SUlf Magnusson  */
expr_trans_compare(struct expr * e,enum expr_type type,struct symbol * sym)8931da177e4SLinus Torvalds struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
8941da177e4SLinus Torvalds {
8951da177e4SLinus Torvalds 	struct expr *e1, *e2;
8961da177e4SLinus Torvalds 
8971da177e4SLinus Torvalds 	if (!e) {
8981da177e4SLinus Torvalds 		e = expr_alloc_symbol(sym);
8991da177e4SLinus Torvalds 		if (type == E_UNEQUAL)
9001da177e4SLinus Torvalds 			e = expr_alloc_one(E_NOT, e);
9011da177e4SLinus Torvalds 		return e;
9021da177e4SLinus Torvalds 	}
9031da177e4SLinus Torvalds 	switch (e->type) {
9041da177e4SLinus Torvalds 	case E_AND:
9051da177e4SLinus Torvalds 		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
9061da177e4SLinus Torvalds 		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
9071da177e4SLinus Torvalds 		if (sym == &symbol_yes)
9081da177e4SLinus Torvalds 			e = expr_alloc_two(E_AND, e1, e2);
9091da177e4SLinus Torvalds 		if (sym == &symbol_no)
9101da177e4SLinus Torvalds 			e = expr_alloc_two(E_OR, e1, e2);
9111da177e4SLinus Torvalds 		if (type == E_UNEQUAL)
9121da177e4SLinus Torvalds 			e = expr_alloc_one(E_NOT, e);
9131da177e4SLinus Torvalds 		return e;
9141da177e4SLinus Torvalds 	case E_OR:
9151da177e4SLinus Torvalds 		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
9161da177e4SLinus Torvalds 		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
9171da177e4SLinus Torvalds 		if (sym == &symbol_yes)
9181da177e4SLinus Torvalds 			e = expr_alloc_two(E_OR, e1, e2);
9191da177e4SLinus Torvalds 		if (sym == &symbol_no)
9201da177e4SLinus Torvalds 			e = expr_alloc_two(E_AND, e1, e2);
9211da177e4SLinus Torvalds 		if (type == E_UNEQUAL)
9221da177e4SLinus Torvalds 			e = expr_alloc_one(E_NOT, e);
9231da177e4SLinus Torvalds 		return e;
9241da177e4SLinus Torvalds 	case E_NOT:
9251da177e4SLinus Torvalds 		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
9261da177e4SLinus Torvalds 	case E_UNEQUAL:
92731847b67SJan Beulich 	case E_LTH:
92831847b67SJan Beulich 	case E_LEQ:
92931847b67SJan Beulich 	case E_GTH:
93031847b67SJan Beulich 	case E_GEQ:
9311da177e4SLinus Torvalds 	case E_EQUAL:
9321da177e4SLinus Torvalds 		if (type == E_EQUAL) {
9331da177e4SLinus Torvalds 			if (sym == &symbol_yes)
9341da177e4SLinus Torvalds 				return expr_copy(e);
9351da177e4SLinus Torvalds 			if (sym == &symbol_mod)
9361da177e4SLinus Torvalds 				return expr_alloc_symbol(&symbol_no);
9371da177e4SLinus Torvalds 			if (sym == &symbol_no)
9381da177e4SLinus Torvalds 				return expr_alloc_one(E_NOT, expr_copy(e));
9391da177e4SLinus Torvalds 		} else {
9401da177e4SLinus Torvalds 			if (sym == &symbol_yes)
9411da177e4SLinus Torvalds 				return expr_alloc_one(E_NOT, expr_copy(e));
9421da177e4SLinus Torvalds 			if (sym == &symbol_mod)
9431da177e4SLinus Torvalds 				return expr_alloc_symbol(&symbol_yes);
9441da177e4SLinus Torvalds 			if (sym == &symbol_no)
9451da177e4SLinus Torvalds 				return expr_copy(e);
9461da177e4SLinus Torvalds 		}
9471da177e4SLinus Torvalds 		break;
9481da177e4SLinus Torvalds 	case E_SYMBOL:
9491da177e4SLinus Torvalds 		return expr_alloc_comp(type, e->left.sym, sym);
9507a962923SRoman Zippel 	case E_LIST:
9511da177e4SLinus Torvalds 	case E_RANGE:
9521da177e4SLinus Torvalds 	case E_NONE:
9531da177e4SLinus Torvalds 		/* panic */;
9541da177e4SLinus Torvalds 	}
9551da177e4SLinus Torvalds 	return NULL;
9561da177e4SLinus Torvalds }
9571da177e4SLinus Torvalds 
95831847b67SJan Beulich enum string_value_kind {
95931847b67SJan Beulich 	k_string,
96031847b67SJan Beulich 	k_signed,
96131847b67SJan Beulich 	k_unsigned,
96231847b67SJan Beulich };
96331847b67SJan Beulich 
96431847b67SJan Beulich union string_value {
96531847b67SJan Beulich 	unsigned long long u;
96631847b67SJan Beulich 	signed long long s;
96731847b67SJan Beulich };
96831847b67SJan Beulich 
expr_parse_string(const char * str,enum symbol_type type,union string_value * val)96931847b67SJan Beulich static enum string_value_kind expr_parse_string(const char *str,
97031847b67SJan Beulich 						enum symbol_type type,
97131847b67SJan Beulich 						union string_value *val)
97231847b67SJan Beulich {
97331847b67SJan Beulich 	char *tail;
97431847b67SJan Beulich 	enum string_value_kind kind;
97531847b67SJan Beulich 
97631847b67SJan Beulich 	errno = 0;
97731847b67SJan Beulich 	switch (type) {
97831847b67SJan Beulich 	case S_BOOLEAN:
97931847b67SJan Beulich 	case S_TRISTATE:
9809059a349SNicolas Pitre 		val->s = !strcmp(str, "n") ? 0 :
9819059a349SNicolas Pitre 			 !strcmp(str, "m") ? 1 :
9829059a349SNicolas Pitre 			 !strcmp(str, "y") ? 2 : -1;
9839059a349SNicolas Pitre 		return k_signed;
98431847b67SJan Beulich 	case S_INT:
98531847b67SJan Beulich 		val->s = strtoll(str, &tail, 10);
98631847b67SJan Beulich 		kind = k_signed;
98731847b67SJan Beulich 		break;
98831847b67SJan Beulich 	case S_HEX:
98931847b67SJan Beulich 		val->u = strtoull(str, &tail, 16);
99031847b67SJan Beulich 		kind = k_unsigned;
99131847b67SJan Beulich 		break;
9920cbe3ac4SMasahiro Yamada 	default:
99331847b67SJan Beulich 		val->s = strtoll(str, &tail, 0);
99431847b67SJan Beulich 		kind = k_signed;
99531847b67SJan Beulich 		break;
99631847b67SJan Beulich 	}
99731847b67SJan Beulich 	return !errno && !*tail && tail > str && isxdigit(tail[-1])
99831847b67SJan Beulich 	       ? kind : k_string;
99931847b67SJan Beulich }
100031847b67SJan Beulich 
expr_calc_value(struct expr * e)10011da177e4SLinus Torvalds tristate expr_calc_value(struct expr *e)
10021da177e4SLinus Torvalds {
10031da177e4SLinus Torvalds 	tristate val1, val2;
10041da177e4SLinus Torvalds 	const char *str1, *str2;
100531847b67SJan Beulich 	enum string_value_kind k1 = k_string, k2 = k_string;
100631847b67SJan Beulich 	union string_value lval = {}, rval = {};
100731847b67SJan Beulich 	int res;
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	if (!e)
10101da177e4SLinus Torvalds 		return yes;
10111da177e4SLinus Torvalds 
10121da177e4SLinus Torvalds 	switch (e->type) {
10131da177e4SLinus Torvalds 	case E_SYMBOL:
10141da177e4SLinus Torvalds 		sym_calc_value(e->left.sym);
10151da177e4SLinus Torvalds 		return e->left.sym->curr.tri;
10161da177e4SLinus Torvalds 	case E_AND:
10171da177e4SLinus Torvalds 		val1 = expr_calc_value(e->left.expr);
10181da177e4SLinus Torvalds 		val2 = expr_calc_value(e->right.expr);
1019d6ee3576SSam Ravnborg 		return EXPR_AND(val1, val2);
10201da177e4SLinus Torvalds 	case E_OR:
10211da177e4SLinus Torvalds 		val1 = expr_calc_value(e->left.expr);
10221da177e4SLinus Torvalds 		val2 = expr_calc_value(e->right.expr);
1023d6ee3576SSam Ravnborg 		return EXPR_OR(val1, val2);
10241da177e4SLinus Torvalds 	case E_NOT:
10251da177e4SLinus Torvalds 		val1 = expr_calc_value(e->left.expr);
1026d6ee3576SSam Ravnborg 		return EXPR_NOT(val1);
10271da177e4SLinus Torvalds 	case E_EQUAL:
102831847b67SJan Beulich 	case E_GEQ:
102931847b67SJan Beulich 	case E_GTH:
103031847b67SJan Beulich 	case E_LEQ:
103131847b67SJan Beulich 	case E_LTH:
10321da177e4SLinus Torvalds 	case E_UNEQUAL:
103331847b67SJan Beulich 		break;
10341da177e4SLinus Torvalds 	default:
10351da177e4SLinus Torvalds 		printf("expr_calc_value: %d?\n", e->type);
10361da177e4SLinus Torvalds 		return no;
10371da177e4SLinus Torvalds 	}
103831847b67SJan Beulich 
103931847b67SJan Beulich 	sym_calc_value(e->left.sym);
104031847b67SJan Beulich 	sym_calc_value(e->right.sym);
104131847b67SJan Beulich 	str1 = sym_get_string_value(e->left.sym);
104231847b67SJan Beulich 	str2 = sym_get_string_value(e->right.sym);
104331847b67SJan Beulich 
104431847b67SJan Beulich 	if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
104531847b67SJan Beulich 		k1 = expr_parse_string(str1, e->left.sym->type, &lval);
104631847b67SJan Beulich 		k2 = expr_parse_string(str2, e->right.sym->type, &rval);
104731847b67SJan Beulich 	}
104831847b67SJan Beulich 
104931847b67SJan Beulich 	if (k1 == k_string || k2 == k_string)
105031847b67SJan Beulich 		res = strcmp(str1, str2);
10510cbe3ac4SMasahiro Yamada 	else if (k1 == k_unsigned || k2 == k_unsigned)
105231847b67SJan Beulich 		res = (lval.u > rval.u) - (lval.u < rval.u);
105331847b67SJan Beulich 	else /* if (k1 == k_signed && k2 == k_signed) */
105431847b67SJan Beulich 		res = (lval.s > rval.s) - (lval.s < rval.s);
105531847b67SJan Beulich 
105631847b67SJan Beulich 	switch(e->type) {
105731847b67SJan Beulich 	case E_EQUAL:
105831847b67SJan Beulich 		return res ? no : yes;
105931847b67SJan Beulich 	case E_GEQ:
106031847b67SJan Beulich 		return res >= 0 ? yes : no;
106131847b67SJan Beulich 	case E_GTH:
106231847b67SJan Beulich 		return res > 0 ? yes : no;
106331847b67SJan Beulich 	case E_LEQ:
106431847b67SJan Beulich 		return res <= 0 ? yes : no;
106531847b67SJan Beulich 	case E_LTH:
106631847b67SJan Beulich 		return res < 0 ? yes : no;
106731847b67SJan Beulich 	case E_UNEQUAL:
106831847b67SJan Beulich 		return res ? yes : no;
106931847b67SJan Beulich 	default:
107031847b67SJan Beulich 		printf("expr_calc_value: relation %d?\n", e->type);
107131847b67SJan Beulich 		return no;
107231847b67SJan Beulich 	}
10731da177e4SLinus Torvalds }
10741da177e4SLinus Torvalds 
expr_compare_type(enum expr_type t1,enum expr_type t2)1075ad8d40cdSMichal Marek static int expr_compare_type(enum expr_type t1, enum expr_type t2)
10761da177e4SLinus Torvalds {
10771da177e4SLinus Torvalds 	if (t1 == t2)
10781da177e4SLinus Torvalds 		return 0;
10791da177e4SLinus Torvalds 	switch (t1) {
108031847b67SJan Beulich 	case E_LEQ:
108131847b67SJan Beulich 	case E_LTH:
108231847b67SJan Beulich 	case E_GEQ:
108331847b67SJan Beulich 	case E_GTH:
108431847b67SJan Beulich 		if (t2 == E_EQUAL || t2 == E_UNEQUAL)
108531847b67SJan Beulich 			return 1;
10861da177e4SLinus Torvalds 	case E_EQUAL:
10871da177e4SLinus Torvalds 	case E_UNEQUAL:
10881da177e4SLinus Torvalds 		if (t2 == E_NOT)
10891da177e4SLinus Torvalds 			return 1;
10901da177e4SLinus Torvalds 	case E_NOT:
10911da177e4SLinus Torvalds 		if (t2 == E_AND)
10921da177e4SLinus Torvalds 			return 1;
10931da177e4SLinus Torvalds 	case E_AND:
10941da177e4SLinus Torvalds 		if (t2 == E_OR)
10951da177e4SLinus Torvalds 			return 1;
10961da177e4SLinus Torvalds 	case E_OR:
10977a962923SRoman Zippel 		if (t2 == E_LIST)
10981da177e4SLinus Torvalds 			return 1;
10997a962923SRoman Zippel 	case E_LIST:
11001da177e4SLinus Torvalds 		if (t2 == 0)
11011da177e4SLinus Torvalds 			return 1;
11021da177e4SLinus Torvalds 	default:
11031da177e4SLinus Torvalds 		return -1;
11041da177e4SLinus Torvalds 	}
11051da177e4SLinus Torvalds 	printf("[%dgt%d?]", t1, t2);
11061da177e4SLinus Torvalds 	return 0;
11071da177e4SLinus Torvalds }
11081da177e4SLinus Torvalds 
expr_print(struct expr * e,void (* fn)(void *,struct symbol *,const char *),void * data,int prevtoken)11099a47ceecSMasahiro Yamada void expr_print(struct expr *e,
11109a47ceecSMasahiro Yamada 		void (*fn)(void *, struct symbol *, const char *),
11119a47ceecSMasahiro Yamada 		void *data, int prevtoken)
11121da177e4SLinus Torvalds {
11131da177e4SLinus Torvalds 	if (!e) {
1114ab45d190SRoman Zippel 		fn(data, NULL, "y");
11151da177e4SLinus Torvalds 		return;
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	if (expr_compare_type(prevtoken, e->type) > 0)
1119ab45d190SRoman Zippel 		fn(data, NULL, "(");
11201da177e4SLinus Torvalds 	switch (e->type) {
11211da177e4SLinus Torvalds 	case E_SYMBOL:
11221da177e4SLinus Torvalds 		if (e->left.sym->name)
1123ab45d190SRoman Zippel 			fn(data, e->left.sym, e->left.sym->name);
11241da177e4SLinus Torvalds 		else
1125ab45d190SRoman Zippel 			fn(data, NULL, "<choice>");
11261da177e4SLinus Torvalds 		break;
11271da177e4SLinus Torvalds 	case E_NOT:
1128ab45d190SRoman Zippel 		fn(data, NULL, "!");
11291da177e4SLinus Torvalds 		expr_print(e->left.expr, fn, data, E_NOT);
11301da177e4SLinus Torvalds 		break;
11311da177e4SLinus Torvalds 	case E_EQUAL:
1132f5eaa323SJan Beulich 		if (e->left.sym->name)
1133ab45d190SRoman Zippel 			fn(data, e->left.sym, e->left.sym->name);
1134f5eaa323SJan Beulich 		else
1135f5eaa323SJan Beulich 			fn(data, NULL, "<choice>");
1136ab45d190SRoman Zippel 		fn(data, NULL, "=");
1137ab45d190SRoman Zippel 		fn(data, e->right.sym, e->right.sym->name);
11381da177e4SLinus Torvalds 		break;
113931847b67SJan Beulich 	case E_LEQ:
114031847b67SJan Beulich 	case E_LTH:
114131847b67SJan Beulich 		if (e->left.sym->name)
114231847b67SJan Beulich 			fn(data, e->left.sym, e->left.sym->name);
114331847b67SJan Beulich 		else
114431847b67SJan Beulich 			fn(data, NULL, "<choice>");
114531847b67SJan Beulich 		fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
114631847b67SJan Beulich 		fn(data, e->right.sym, e->right.sym->name);
114731847b67SJan Beulich 		break;
114831847b67SJan Beulich 	case E_GEQ:
114931847b67SJan Beulich 	case E_GTH:
115031847b67SJan Beulich 		if (e->left.sym->name)
115131847b67SJan Beulich 			fn(data, e->left.sym, e->left.sym->name);
115231847b67SJan Beulich 		else
115331847b67SJan Beulich 			fn(data, NULL, "<choice>");
1154f6aad261SMichal Sojka 		fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
115531847b67SJan Beulich 		fn(data, e->right.sym, e->right.sym->name);
115631847b67SJan Beulich 		break;
11571da177e4SLinus Torvalds 	case E_UNEQUAL:
1158f5eaa323SJan Beulich 		if (e->left.sym->name)
1159ab45d190SRoman Zippel 			fn(data, e->left.sym, e->left.sym->name);
1160f5eaa323SJan Beulich 		else
1161f5eaa323SJan Beulich 			fn(data, NULL, "<choice>");
1162ab45d190SRoman Zippel 		fn(data, NULL, "!=");
1163ab45d190SRoman Zippel 		fn(data, e->right.sym, e->right.sym->name);
11641da177e4SLinus Torvalds 		break;
11651da177e4SLinus Torvalds 	case E_OR:
11669a47ceecSMasahiro Yamada 		expr_print(e->left.expr, fn, data, E_OR);
1167ab45d190SRoman Zippel 		fn(data, NULL, " || ");
11689a47ceecSMasahiro Yamada 		expr_print(e->right.expr, fn, data, E_OR);
11691da177e4SLinus Torvalds 		break;
11701da177e4SLinus Torvalds 	case E_AND:
11711da177e4SLinus Torvalds 		expr_print(e->left.expr, fn, data, E_AND);
1172ab45d190SRoman Zippel 		fn(data, NULL, " && ");
11731da177e4SLinus Torvalds 		expr_print(e->right.expr, fn, data, E_AND);
11741da177e4SLinus Torvalds 		break;
11757a962923SRoman Zippel 	case E_LIST:
1176ab45d190SRoman Zippel 		fn(data, e->right.sym, e->right.sym->name);
11771da177e4SLinus Torvalds 		if (e->left.expr) {
1178ab45d190SRoman Zippel 			fn(data, NULL, " ^ ");
11797a962923SRoman Zippel 			expr_print(e->left.expr, fn, data, E_LIST);
11801da177e4SLinus Torvalds 		}
11811da177e4SLinus Torvalds 		break;
11821da177e4SLinus Torvalds 	case E_RANGE:
1183ab45d190SRoman Zippel 		fn(data, NULL, "[");
1184ab45d190SRoman Zippel 		fn(data, e->left.sym, e->left.sym->name);
1185ab45d190SRoman Zippel 		fn(data, NULL, " ");
1186ab45d190SRoman Zippel 		fn(data, e->right.sym, e->right.sym->name);
1187ab45d190SRoman Zippel 		fn(data, NULL, "]");
11881da177e4SLinus Torvalds 		break;
11891da177e4SLinus Torvalds 	default:
11901da177e4SLinus Torvalds 	  {
11911da177e4SLinus Torvalds 		char buf[32];
11921da177e4SLinus Torvalds 		sprintf(buf, "<unknown type %d>", e->type);
1193ab45d190SRoman Zippel 		fn(data, NULL, buf);
11941da177e4SLinus Torvalds 		break;
11951da177e4SLinus Torvalds 	  }
11961da177e4SLinus Torvalds 	}
11971da177e4SLinus Torvalds 	if (expr_compare_type(prevtoken, e->type) > 0)
1198ab45d190SRoman Zippel 		fn(data, NULL, ")");
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds 
expr_print_file_helper(void * data,struct symbol * sym,const char * str)1201ab45d190SRoman Zippel static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
12021da177e4SLinus Torvalds {
1203bf5e327aSJean Sacren 	xfwrite(str, strlen(str), 1, data);
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds 
expr_fprint(struct expr * e,FILE * out)12061da177e4SLinus Torvalds void expr_fprint(struct expr *e, FILE *out)
12071da177e4SLinus Torvalds {
12081da177e4SLinus Torvalds 	expr_print(e, expr_print_file_helper, out, E_NONE);
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
expr_print_gstr_helper(void * data,struct symbol * sym,const char * str)1211ab45d190SRoman Zippel static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
12121da177e4SLinus Torvalds {
1213da60fbbcSVadim Bendebury (вб) 	struct gstr *gs = (struct gstr*)data;
1214da60fbbcSVadim Bendebury (вб) 	const char *sym_str = NULL;
1215da60fbbcSVadim Bendebury (вб) 
1216544e433aSCheng Renquan 	if (sym)
1217da60fbbcSVadim Bendebury (вб) 		sym_str = sym_get_string_value(sym);
1218da60fbbcSVadim Bendebury (вб) 
1219da60fbbcSVadim Bendebury (вб) 	if (gs->max_width) {
1220da60fbbcSVadim Bendebury (вб) 		unsigned extra_length = strlen(str);
1221da60fbbcSVadim Bendebury (вб) 		const char *last_cr = strrchr(gs->s, '\n');
1222da60fbbcSVadim Bendebury (вб) 		unsigned last_line_length;
1223da60fbbcSVadim Bendebury (вб) 
1224da60fbbcSVadim Bendebury (вб) 		if (sym_str)
1225da60fbbcSVadim Bendebury (вб) 			extra_length += 4 + strlen(sym_str);
1226da60fbbcSVadim Bendebury (вб) 
1227da60fbbcSVadim Bendebury (вб) 		if (!last_cr)
1228da60fbbcSVadim Bendebury (вб) 			last_cr = gs->s;
1229da60fbbcSVadim Bendebury (вб) 
1230da60fbbcSVadim Bendebury (вб) 		last_line_length = strlen(gs->s) - (last_cr - gs->s);
1231da60fbbcSVadim Bendebury (вб) 
1232da60fbbcSVadim Bendebury (вб) 		if ((last_line_length + extra_length) > gs->max_width)
1233da60fbbcSVadim Bendebury (вб) 			str_append(gs, "\\\n");
1234da60fbbcSVadim Bendebury (вб) 	}
1235da60fbbcSVadim Bendebury (вб) 
1236da60fbbcSVadim Bendebury (вб) 	str_append(gs, str);
123770ed0747SLi Zefan 	if (sym && sym->type != S_UNKNOWN)
1238da60fbbcSVadim Bendebury (вб) 		str_printf(gs, " [=%s]", sym_str);
12391da177e4SLinus Torvalds }
12401da177e4SLinus Torvalds 
expr_gstr_print(struct expr * e,struct gstr * gs)12411da177e4SLinus Torvalds void expr_gstr_print(struct expr *e, struct gstr *gs)
12421da177e4SLinus Torvalds {
12431da177e4SLinus Torvalds 	expr_print(e, expr_print_gstr_helper, gs, E_NONE);
12441da177e4SLinus Torvalds }
12451ccb2714SPetr Vorel 
12461ccb2714SPetr Vorel /*
12471ccb2714SPetr Vorel  * Transform the top level "||" tokens into newlines and prepend each
12481ccb2714SPetr Vorel  * line with a minus. This makes expressions much easier to read.
12491ccb2714SPetr Vorel  * Suitable for reverse dependency expressions.
12501ccb2714SPetr Vorel  */
expr_print_revdep(struct expr * e,void (* fn)(void *,struct symbol *,const char *),void * data,tristate pr_type,const char ** title)12519a47ceecSMasahiro Yamada static void expr_print_revdep(struct expr *e,
12529a47ceecSMasahiro Yamada 			      void (*fn)(void *, struct symbol *, const char *),
1253d9119b59SEugeniu Rosca 			      void *data, tristate pr_type, const char **title)
12549a47ceecSMasahiro Yamada {
12559a47ceecSMasahiro Yamada 	if (e->type == E_OR) {
1256d9119b59SEugeniu Rosca 		expr_print_revdep(e->left.expr, fn, data, pr_type, title);
1257d9119b59SEugeniu Rosca 		expr_print_revdep(e->right.expr, fn, data, pr_type, title);
1258d9119b59SEugeniu Rosca 	} else if (expr_calc_value(e) == pr_type) {
1259d9119b59SEugeniu Rosca 		if (*title) {
1260d9119b59SEugeniu Rosca 			fn(data, NULL, *title);
1261d9119b59SEugeniu Rosca 			*title = NULL;
1262d9119b59SEugeniu Rosca 		}
1263d9119b59SEugeniu Rosca 
12649a47ceecSMasahiro Yamada 		fn(data, NULL, "  - ");
12659a47ceecSMasahiro Yamada 		expr_print(e, fn, data, E_NONE);
12669a47ceecSMasahiro Yamada 		fn(data, NULL, "\n");
12679a47ceecSMasahiro Yamada 	}
12689a47ceecSMasahiro Yamada }
12699a47ceecSMasahiro Yamada 
expr_gstr_print_revdep(struct expr * e,struct gstr * gs,tristate pr_type,const char * title)1270d9119b59SEugeniu Rosca void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
1271d9119b59SEugeniu Rosca 			    tristate pr_type, const char *title)
12721ccb2714SPetr Vorel {
1273d9119b59SEugeniu Rosca 	expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
12741ccb2714SPetr Vorel }
1275