Skip to content

Instantly share code, notes, and snippets.

@kragen
Forked from gian/kindrules.c
Created December 14, 2009 23:39
Show Gist options
  • Save kragen/256555 to your computer and use it in GitHub Desktop.
Save kragen/256555 to your computer and use it in GitHub Desktop.
#include <stdio.h>
typedef int bool;
enum { true = 1, false = 0 };
/* dummy definitions to make it compile */
enum symbol { SYM_DONTCARE, SYM_ANY, SYM_OTHER };
enum kind { KIND_DONTCARE, KIND_NODE, KIND_OTHER };
struct thing { enum symbol type; enum kind kind; };
int is_kind(enum symbol type, enum kind kind) {
return true;
}
#define DEBUGMSG(x) printf x
/* end of dummy definitions */
#ifndef DEBUGMSG
#define DEBUGMSG(x) 0
#endif
struct Case {
enum symbol s1_type;
enum kind s1_kind;
enum symbol s2_type;
enum kind s2_kind;
bool kinds_equal;
bool types_equal;
bool s1_type_is_s2_kind;
bool s2_type_is_s1_kind;
} table[] = {
/* This is a straightforward transliteration of Gian's code from <http://gist.github.com/255934>. */
/* It contains redundant tests. */
{ .s1_type = SYM_ANY, .s1_kind = KIND_NODE, .s2_type = SYM_ANY, .s2_kind = KIND_NODE }, /* 1 */
{ .s1_type = SYM_ANY, .s1_kind = KIND_NODE, .s2_type = SYM_ANY, .s2_kind = KIND_OTHER, .kinds_equal = true }, /* this is a bug; it is in the original code */
{ .s1_type = SYM_ANY, .s1_kind = KIND_NODE, .s2_type = SYM_OTHER },
{ .s1_type = SYM_ANY, .s1_kind = KIND_OTHER, .s2_type = SYM_ANY, .kinds_equal = true },
{ .s1_type = SYM_ANY, .s1_kind = KIND_OTHER, .s2_type = SYM_OTHER, .s2_type_is_s1_kind = true },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_NODE, .s2_type = SYM_ANY, .s2_kind = KIND_NODE }, /* 6 */
{ .s1_type = SYM_OTHER, .s1_kind = KIND_NODE, .s2_type = SYM_ANY, .s2_kind = KIND_OTHER, .s1_type_is_s2_kind = true },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_NODE, .s2_type = SYM_OTHER, .s2_kind = KIND_NODE, .types_equal = true },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_NODE, .s2_type = SYM_OTHER, .s2_kind = KIND_OTHER, .types_equal = true, .s1_type_is_s2_kind = true },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_OTHER, .s2_type = SYM_ANY, .s2_kind = KIND_NODE },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_OTHER, .s2_type = SYM_ANY, .s1_type_is_s2_kind = true }, /* 11 */
{ .s1_type = SYM_OTHER, .s1_kind = KIND_OTHER, .s2_type = SYM_OTHER, .s2_kind = KIND_NODE, .types_equal = true, .s2_type_is_s1_kind = true },
{ .s1_type = SYM_OTHER, .s1_kind = KIND_OTHER, .s2_type = SYM_OTHER, .s2_kind = KIND_OTHER, .types_equal = true, .s1_type_is_s2_kind = true, .s2_type_is_s1_kind = true }, /* 13 */
};
/* The SYM_ANY in the first case is redundant, and I suspect that a
lot of the SYM_OTHER and KIND_OTHER items are redundant too --- in
the sense that in no case they cover would changing a type from
something to SYM_ANY, or changing a kind from something to
KIND_NODE, would cause the code to return FALSE where it had
previously returned TRUE. I suspect that removing the redundancy
would make the table considerably more compact and readable.
*/
int matches(struct Case *c, struct thing s1, struct thing s2) {
DEBUGMSG(("%d %d %d %d %d %d %d %d\n",
c->s1_type,
c->s1_kind,
c->s2_type,
c->s2_kind,
c->kinds_equal,
c->types_equal,
c->s1_type_is_s2_kind,
c->s2_type_is_s1_kind));
if ((c->s1_type == SYM_ANY ) && (s1.type != SYM_ANY)) return false;
if ((c->s1_type == SYM_OTHER) && (s1.type == SYM_ANY)) return false;
if ((c->s1_kind == KIND_NODE ) && (s1.kind != KIND_NODE)) return false;
if ((c->s1_kind == KIND_OTHER) && (s1.kind == KIND_NODE)) return false;
if ((c->s2_type == SYM_ANY ) && (s2.type != SYM_ANY)) return false;
if ((c->s2_type == SYM_OTHER) && (s2.type == SYM_ANY)) return false;
if ((c->s2_kind == KIND_NODE ) && (s2.kind != KIND_NODE)) return false;
if ((c->s2_kind == KIND_OTHER) && (s2.kind == KIND_NODE)) return false;
if (c->kinds_equal && (s1.kind != s2.kind)) return false;
if (c->types_equal && (s1.type != s2.type)) return false;
if (c->s1_type_is_s2_kind && !is_kind(s1.type, s2.kind)) return false;
if (c->s2_type_is_s1_kind && !is_kind(s2.type, s1.kind)) return false;
return true;
}
int determine(struct thing s1, struct thing s2) {
for (int ii = 0; ii < sizeof(table)/sizeof(table[0]); ii++) {
if (matches(&table[ii], s1, s2)) return true;
}
return false;
}
int main() {
struct thing x;
return determine(x, x);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment