summaryrefslogtreecommitdiffstats
path: root/scripts/config/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/config/expr.c')
-rw-r--r--scripts/config/expr.c216
1 files changed, 61 insertions, 155 deletions
diff --git a/scripts/config/expr.c b/scripts/config/expr.c
index 81ebf8108c..8cee597d33 100644
--- a/scripts/config/expr.c
+++ b/scripts/config/expr.c
@@ -1,10 +1,8 @@
-// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
*/
-#include <ctype.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -13,6 +11,7 @@
#define DEBUG_EXPR 0
+static int expr_eq(struct expr *e1, struct expr *e2);
static struct expr *expr_eliminate_yn(struct expr *e);
struct expr *expr_alloc_symbol(struct symbol *sym)
@@ -95,7 +94,7 @@ struct expr *expr_copy(const struct expr *org)
e->right.expr = expr_copy(org->right.expr);
break;
default:
- fprintf(stderr, "can't copy type %d\n", e->type);
+ printf("can't copy type %d\n", e->type);
free(e);
e = NULL;
break;
@@ -114,7 +113,7 @@ void expr_free(struct expr *e)
break;
case E_NOT:
expr_free(e->left.expr);
- break;
+ return;
case E_EQUAL:
case E_GEQ:
case E_GTH:
@@ -128,7 +127,7 @@ void expr_free(struct expr *e)
expr_free(e->right.expr);
break;
default:
- fprintf(stderr, "how to free type %d?\n", e->type);
+ printf("how to free type %d?\n", e->type);
break;
}
free(e);
@@ -139,18 +138,8 @@ static int trans_count;
#define e1 (*ep1)
#define e2 (*ep2)
-/*
- * expr_eliminate_eq() helper.
- *
- * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
- * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
- * against all other leaves. Two equal leaves are both replaced with either 'y'
- * or 'n' as appropriate for 'type', to be eliminated later.
- */
static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
{
- /* Recurse down to leaves */
-
if (e1->type == type) {
__expr_eliminate_eq(type, &e1->left.expr, &e2);
__expr_eliminate_eq(type, &e1->right.expr, &e2);
@@ -161,18 +150,12 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
__expr_eliminate_eq(type, &e1, &e2->right.expr);
return;
}
-
- /* e1 and e2 are leaves. Compare them. */
-
if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
e1->left.sym == e2->left.sym &&
(e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
return;
if (!expr_eq(e1, e2))
return;
-
- /* e1 and e2 are equal leaves. Prepare them for elimination. */
-
trans_count++;
expr_free(e1); expr_free(e2);
switch (type) {
@@ -189,35 +172,6 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
}
}
-/*
- * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to both.
- * Example reductions:
- *
- * ep1: A && B -> ep1: y
- * ep2: A && B && C -> ep2: C
- *
- * ep1: A || B -> ep1: n
- * ep2: A || B || C -> ep2: C
- *
- * ep1: A && (B && FOO) -> ep1: FOO
- * ep2: (BAR && B) && A -> ep2: BAR
- *
- * ep1: A && (B || C) -> ep1: y
- * ep2: (C || B) && A -> ep2: y
- *
- * Comparisons are done between all operands at the same "level" of && or ||.
- * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the
- * following operands will be compared:
- *
- * - 'e1', 'e2 || e3', and 'e4 || e5', against each other
- * - e2 against e3
- * - e4 against e5
- *
- * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and
- * '(e1 && e2) && e3' are both a single level.
- *
- * See __expr_eliminate_eq() as well.
- */
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{
if (!e1 || !e2)
@@ -243,23 +197,10 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
#undef e1
#undef e2
-/*
- * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
- * &&/|| expressions are considered equal if every operand in one expression
- * equals some operand in the other (operands do not need to appear in the same
- * order), recursively.
- */
-int expr_eq(struct expr *e1, struct expr *e2)
+static int expr_eq(struct expr *e1, struct expr *e2)
{
int res, old_count;
- /*
- * A NULL expr is taken to be yes, but there's also a different way to
- * represent yes. expr_is_yes() checks for either representation.
- */
- if (!e1 || !e2)
- return expr_is_yes(e1) && expr_is_yes(e2);
-
if (e1->type != e2->type)
return 0;
switch (e1->type) {
@@ -302,17 +243,6 @@ int expr_eq(struct expr *e1, struct expr *e2)
return 0;
}
-/*
- * Recursively performs the following simplifications in-place (as well as the
- * corresponding simplifications with swapped operands):
- *
- * expr && n -> n
- * expr && y -> expr
- * expr || n -> expr
- * expr || y -> y
- *
- * Returns the optimized expression.
- */
static struct expr *expr_eliminate_yn(struct expr *e)
{
struct expr *tmp;
@@ -586,21 +516,12 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
return NULL;
}
-/*
- * expr_eliminate_dups() helper.
- *
- * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that does
- * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
- * against all other leaves to look for simplifications.
- */
static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
{
#define e1 (*ep1)
#define e2 (*ep2)
struct expr *tmp;
- /* Recurse down to leaves */
-
if (e1->type == type) {
expr_eliminate_dups1(type, &e1->left.expr, &e2);
expr_eliminate_dups1(type, &e1->right.expr, &e2);
@@ -611,9 +532,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct
expr_eliminate_dups1(type, &e1, &e2->right.expr);
return;
}
-
- /* e1 and e2 are leaves. Compare and process them. */
-
if (e1 == e2)
return;
@@ -650,17 +568,6 @@ static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct
#undef e2
}
-/*
- * Rewrites 'e' in-place to remove ("join") duplicate and other redundant
- * operands.
- *
- * Example simplifications:
- *
- * A || B || A -> A || B
- * A && B && A=y -> A=y && B
- *
- * Returns the deduplicated expression.
- */
struct expr *expr_eliminate_dups(struct expr *e)
{
int oldcount;
@@ -677,7 +584,6 @@ struct expr *expr_eliminate_dups(struct expr *e)
;
}
if (!trans_count)
- /* No simplifications done in this pass. We're done */
break;
e = expr_eliminate_yn(e);
}
@@ -685,12 +591,6 @@ struct expr *expr_eliminate_dups(struct expr *e)
return e;
}
-/*
- * Performs various simplifications involving logical operators and
- * comparisons.
- *
- * Allocates and returns a new expression.
- */
struct expr *expr_transform(struct expr *e)
{
struct expr *tmp;
@@ -905,20 +805,6 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
return false;
}
-/*
- * Inserts explicit comparisons of type 'type' to symbol 'sym' into the
- * expression 'e'.
- *
- * Examples transformations for type == E_UNEQUAL, sym == &symbol_no:
- *
- * A -> A!=n
- * !A -> A=n
- * A && B -> !(A=n || B=n)
- * A || B -> !(A=n && B=n)
- * A && (B || C) -> !(A=n || (B=n && C=n))
- *
- * Allocates and returns a new expression.
- */
struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
{
struct expr *e1, *e2;
@@ -988,6 +874,7 @@ enum string_value_kind {
k_string,
k_signed,
k_unsigned,
+ k_invalid
};
union string_value {
@@ -1018,10 +905,13 @@ static enum string_value_kind expr_parse_string(const char *str,
val->u = strtoull(str, &tail, 16);
kind = k_unsigned;
break;
- default:
+ case S_STRING:
+ case S_UNKNOWN:
val->s = strtoll(str, &tail, 0);
kind = k_signed;
break;
+ default:
+ return k_invalid;
}
return !errno && !*tail && tail > str && isxdigit(tail[-1])
? kind : k_string;
@@ -1077,7 +967,13 @@ tristate expr_calc_value(struct expr *e)
if (k1 == k_string || k2 == k_string)
res = strcmp(str1, str2);
- else if (k1 == k_unsigned || k2 == k_unsigned)
+ else if (k1 == k_invalid || k2 == k_invalid) {
+ if (e->type != E_EQUAL && e->type != E_UNEQUAL) {
+ printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2);
+ return no;
+ }
+ res = strcmp(str1, str2);
+ } else if (k1 == k_unsigned || k2 == k_unsigned)
res = (lval.u > rval.u) - (lval.u < rval.u);
else /* if (k1 == k_signed && k2 == k_signed) */
res = (lval.s > rval.s) - (lval.s < rval.s);
@@ -1135,9 +1031,49 @@ static int expr_compare_type(enum expr_type t1, enum expr_type t2)
return 0;
}
-void expr_print(struct expr *e,
- void (*fn)(void *, struct symbol *, const char *),
- void *data, int prevtoken)
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+ if (e == NULL)
+ return NULL;
+
+ while (e->type != E_SYMBOL)
+ e = e->left.expr;
+
+ return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+ struct expr *ret;
+
+ switch (e1->type) {
+ case E_OR:
+ return expr_alloc_and(
+ expr_simplify_unmet_dep(e1->left.expr, e2),
+ expr_simplify_unmet_dep(e1->right.expr, e2));
+ case E_AND: {
+ struct expr *e;
+ e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+ e = expr_eliminate_dups(e);
+ ret = (!expr_eq(e, e1)) ? e1 : NULL;
+ expr_free(e);
+ break;
+ }
+ default:
+ ret = e1;
+ break;
+ }
+
+ return expr_get_leftmost_symbol(ret);
+}
+
+void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
{
if (!e) {
fn(data, NULL, "y");
@@ -1271,33 +1207,3 @@ void expr_gstr_print(struct expr *e, struct gstr *gs)
{
expr_print(e, expr_print_gstr_helper, gs, E_NONE);
}
-
-/*
- * Transform the top level "||" tokens into newlines and prepend each
- * line with a minus. This makes expressions much easier to read.
- * Suitable for reverse dependency expressions.
- */
-static void expr_print_revdep(struct expr *e,
- void (*fn)(void *, struct symbol *, const char *),
- void *data, tristate pr_type, const char **title)
-{
- if (e->type == E_OR) {
- expr_print_revdep(e->left.expr, fn, data, pr_type, title);
- expr_print_revdep(e->right.expr, fn, data, pr_type, title);
- } else if (expr_calc_value(e) == pr_type) {
- if (*title) {
- fn(data, NULL, *title);
- *title = NULL;
- }
-
- fn(data, NULL, " - ");
- expr_print(e, fn, data, E_NONE);
- fn(data, NULL, "\n");
- }
-}
-
-void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
- tristate pr_type, const char *title)
-{
- expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
-}