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