diff --git a/b2/chr.c b/b2/chr.c index fdad4a0..1b68572 100644 --- a/b2/chr.c +++ b/b2/chr.c @@ -77,10 +77,26 @@ struct condition *new_condition(enum relop relop, const char *word) } +static int comp(const void *a, enum relop op, const void *b, const void *user) +{ + return compare(user, a, op, b); +} + + +static void check_redundant(const struct field *f, + const struct condition *c1, const struct condition *c2) +{ + if (relop_implies(c1->relop, c2->relop, &c1->value, &c2->value, + comp, f->fmt)) + yywarn("redundant condition"); +} + + void field_finalize(struct field *field) { - const struct selector *sel; + const struct selector *sel, *s2; struct condition *cond; + const struct condition *c2; for (sel = field->sel; sel; sel = sel->next) for (cond = sel->cond; cond; cond = cond->next) @@ -88,6 +104,14 @@ void field_finalize(struct field *field) &cond->value)) yyerrorf("invalid value in selection"); /* @@@ indicate exact location */ + for (sel = field->sel; sel; sel = sel->next) + for (cond = sel->cond; cond; cond = cond->next) { + for (c2 = cond->next; c2; c2 = c2->next) + check_redundant(field, cond, c2); + for (s2 = sel->next; s2; s2 = s2->next) + for (c2 = s2->cond; c2; c2 = c2->next) + check_redundant(field, cond, c2); + } } diff --git a/b2/relop.c b/b2/relop.c index e186c2f..ff9411b 100644 --- a/b2/relop.c +++ b/b2/relop.c @@ -16,6 +16,78 @@ #include "relop.h" +/* + * Operator to use for + * + * forall X: (A op B) == ((X opa A) -> (X opb B)) + * + * For unlimited sets of values: + * + * opa -> < <= == >= > + * opb + * < >= >= 0 0 0 + * <= > >= 0 0 0 + * == > >= == <= < + * >= 0 0 0 <= < + * > 0 0 0 <= <= + * + * For limited sets of values, we could decide also in some edge cases, + * but let's save such sophistication for later. + */ + + +static const enum relop implies_op[idx_n][idx_n] = { + [idx_lt][idx_lt] = rel_ge, + [idx_lt][idx_le] = rel_ge, + + [idx_le][idx_lt] = rel_gt, + [idx_le][idx_le] = rel_ge, + + [idx_eq][idx_lt] = rel_gt, + [idx_eq][idx_le] = rel_ge, + [idx_eq][idx_eq] = rel_eq, +}; + + +static int relop2index(enum relop op) +{ + switch (op) { + case rel_lt: + return idx_lt; + case rel_le: + return idx_le; + case rel_eq: + return idx_eq; + case rel_ge: + return idx_ge; + case rel_gt: + return idx_gt; + default: + abort(); + } +} + + +static enum relop swap_op(enum relop op) +{ + return idx_n-1-relop2index(op); +} + + +int relop_implies(enum relop opa, enum relop opb, const void *a, const void *b, + int (*cmp)(const void *a, enum relop op, const void *b, const void *user), + const void *user) +{ + if (opa <= opb) + return cmp(a, + implies_op[relop2index(opa)][relop2index(opb)], b, user); + else + return cmp(b, + swap_op(implies_op[relop2index(opb)][relop2index(opa)]), + a, user); +} + + void dump_relop(FILE *file, enum relop op) { switch (op) { diff --git a/b2/relop.h b/b2/relop.h index 69facc6..adb2f50 100644 --- a/b2/relop.h +++ b/b2/relop.h @@ -16,15 +16,31 @@ #include +enum relop_idx { + idx_lt = 0, + idx_le = 1, + idx_eq = 2, + idx_ge = 3, + idx_gt = 4, + idx_n = 5 +}; + enum relop { - rel_lt = 1 << 0, - rel_le = 1 << 1, - rel_eq = 1 << 2, - rel_ge = 1 << 3, - rel_gt = 1 << 4, + rel_lt = 1 << idx_lt, + rel_le = 1 << idx_le, + rel_eq = 1 << idx_eq, + rel_ge = 1 << idx_ge, + rel_gt = 1 << idx_gt, }; +/* + * relop_implies checks whether, for all X: (X opb A) -> (X opa B) + */ + +int relop_implies(enum relop opa, enum relop opb, const void *a, const void *b, + int (*cmp)(const void *a, enum relop op, const void *b, const void *user), + const void *user); void dump_relop(FILE *file, enum relop op); #endif /* !RELOP_H */