4-variable-simplifier/main.c

1627 lines
40 KiB
C

#include <math.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <limits.h>
#include <readline/readline.h>
#include <readline/history.h>
#define argv0 program_invocation_name
#ifdef ZDEBUG
#define zprintf(fmt, ...) \
printf(fmt, ## __VA_ARGS__);
#else
#define zprintf(...);
#endif
bool print_all_and_quit = false;
const char* command = NULL;
struct {
bool not;
bool or, orn, nor;
bool and, andn, nand;
bool xor, nxor;
bool lt, lte, gt, gte;
bool ternary;
} use_operators;
bool assume_yes = false;
bool verbose = false;
bool print_with_color = false;
bool print_stats = false;
bool force_rebuild = false;
bool quiet = false;
static void parse_args(int argc, char* const* argv)
{
bool unset_operators = true;
print_with_color = isatty(1);
for (int opt; (opt = getopt(argc, argv, "pyqmvc:eEo:C:B")) != -1; ) switch (opt)
{
case 'p':
print_all_and_quit = true;
break;
case 'y':
assume_yes = true;
break;
case 'q':
quiet = true;
break;
case 'm':
print_stats = true;
break;
case 'v':
verbose = true;
break;
case 'c':
command = optarg;
break;
case 'E':
use_operators.ternary = true;
// fallthrough
case 'e':
{
use_operators.not = true;
use_operators.or = true;
use_operators.and = true;
use_operators.orn = true;
use_operators.nor = true;
use_operators.andn = true;
use_operators.nand = true;
use_operators. xor = true;
use_operators.nxor = true;
unset_operators = false;
break;
}
case 'o':
{
unset_operators = false;
for (char* moving; (moving = strtok_r(NULL, ",", &optarg)); )
{
if (!strcmp(moving, "not") || !strcmp(moving, "!"))
use_operators.not = true;
else if (!strcmp(moving, "or") || !strcmp(moving, "||"))
use_operators.or = true;
else if (!strcmp(moving, "orn") || !strcmp(moving, "|!"))
use_operators.orn = true;
else if (!strcmp(moving, "nor") || !strcmp(moving, "!|"))
use_operators.nor = true;
else if (!strcmp(moving, "and") || !strcmp(moving, "&&"))
use_operators.and = true;
else if (!strcmp(moving, "andn") || !strcmp(moving, "&!"))
use_operators.andn = true;
else if (!strcmp(moving, "nand") || !strcmp(moving, "!&"))
use_operators.nand = true;
else if (!strcmp(moving, "xor") || !strcmp(moving, "!="))
use_operators.xor = true;
else if (!strcmp(moving, "nxor") || !strcmp(moving, "=="))
use_operators.nxor = true;
else if (!strcmp(moving, "lt") || !strcmp(moving, "<"))
use_operators.lt = true;
else if (!strcmp(moving, "lte") || !strcmp(moving, "<="))
use_operators.lte = true;
else if (!strcmp(moving, "gt") || !strcmp(moving, ">"))
use_operators.gt = true;
else if (!strcmp(moving, "gte") || !strcmp(moving, ">="))
use_operators.gte = true;
else if (!strcmp(moving, "ternary") || !strcmp(moving, "?:"))
use_operators.ternary = true;
else
{
assert(!"TODO");
}
}
break;
}
case 'C':
{
if (!strcmp(optarg, "yes") || !strcmp(optarg, "on"))
print_with_color = true;
else if (!strcmp(optarg, "no") || !strcmp(optarg, "off"))
print_with_color = false;
else if (!strcmp(optarg, "auto"))
print_with_color = isatty(1);
else
{
assert(!"TODO");
}
break;
}
case 'B':
{
force_rebuild = true;
break;
}
default:
{
printf("Unknown option '%c'!" "\n", opt);
exit(1);
break;
}
}
if (unset_operators)
{
use_operators.not = true;
use_operators.or = true;
use_operators.and = true;
}
}
#define V 0b01010101010101010101010101010101
#define W 0b00110011001100110011001100110011
#define X 0b00001111000011110000111100001111
#define Y 0b00000000111111110000000011111111
#define Z 0b00000000000000001111111111111111
#define M 0b11111111111111111111111111111111
#define N (1UL << (1UL << 5UL))
#define NN (65536)
enum kind {
ek_unreachable,
ek_0,
ek_1,
ek_V,
ek_W,
ek_X,
ek_Y,
ek_Z,
ek_not,
ek_or,
ek_and,
ek_orn,
ek_nor,
ek_andn,
ek_nand,
ek_xor,
ek_nxor,
ek_lt,
ek_lte,
ek_gt,
ek_gte,
ek_ternary,
};
struct expr {
enum kind kind;
uint32_t cond, left, right;
int cost;
} lookup[N];
static void print(uint32_t truthtable, int depth)
{
assert(!"TODO");
#if 0
#define LITERAL_ESCAPE "\e[38;2;200;200;100m"
#define VARIABLE_ESCAPE "\e[38;2;100;100;200m"
#define RESET_ESCAPE "\e[0m"
static const char* const operator_colors[10] = {
"\e[38;2;204;0;0m",
"\e[38;2;204;122;0m",
"\e[38;2;163;204;0m",
"\e[38;2;40;204;0m",
"\e[38;2;0;204;81m",
"\e[38;2;0;204;204m",
"\e[38;2;0;81;204m",
"\e[38;2;40;0;204m",
"\e[38;2;163;0;204m",
"\e[38;2;204;0;122m",
};
const struct expr* e = &lookup[truthtable];
switch (e->kind)
{
case ek_unreachable:
{
assert(!"NOPE");
break;
}
case ek_0:
{
printf(print_with_color ? LITERAL_ESCAPE "0" RESET_ESCAPE : "0");
break;
}
case ek_1:
{
printf(print_with_color ? LITERAL_ESCAPE "1" RESET_ESCAPE : "1");
break;
}
case ek_W:
{
printf(print_with_color ? VARIABLE_ESCAPE "w" RESET_ESCAPE : "w");
break;
}
case ek_X:
{
printf(print_with_color ? VARIABLE_ESCAPE "x" RESET_ESCAPE : "x");
break;
}
case ek_Y:
{
printf(print_with_color ? VARIABLE_ESCAPE "y" RESET_ESCAPE : "y");
break;
}
case ek_Z:
{
printf(print_with_color ? VARIABLE_ESCAPE "z" RESET_ESCAPE : "z");
break;
}
case ek_not:
{
const char* start = print_with_color ? operator_colors[depth % 10] : "";
const char* end = print_with_color ? RESET_ESCAPE : "";
printf("%s(!%s", start, end);
print(e->left, depth + 1);
printf("%s)%s", start, end);
break;
}
#define BINARY_OPERATOR(kind, operatorstring) \
case kind: \
{ \
const char *start = "", *end = ""; \
\
if (print_with_color) \
{ \
start = operator_colors[depth % 10]; \
\
end = RESET_ESCAPE; \
} \
\
printf("%s(%s", start, end); \
\
print(e->left, depth + 1); \
\
printf("%s%s%s", start, operatorstring, end); \
\
print(e->right, depth + 1); \
\
printf("%s)%s", start, end); \
break; \
}
BINARY_OPERATOR(ek_or, " || ");
BINARY_OPERATOR(ek_orn, " |! ");
BINARY_OPERATOR(ek_nor, " !| ");
BINARY_OPERATOR(ek_and, " && ");
BINARY_OPERATOR(ek_andn, " &! ");
BINARY_OPERATOR(ek_nand, " !& ");
BINARY_OPERATOR(ek_xor, " != ");
BINARY_OPERATOR(ek_nxor, " == ");
BINARY_OPERATOR(ek_lt, " < ");
BINARY_OPERATOR(ek_lte, " <= ");
BINARY_OPERATOR(ek_gt, " > ");
BINARY_OPERATOR(ek_gte, " >= ");
#undef BINARY_OPERATOR
case ek_ternary:
{
const char *start = "", *end = "";
if (print_with_color)
{
start = operator_colors[depth % 10];
end = RESET_ESCAPE;
}
printf("%s(%s", start, end);
print(e->cond, depth + 1);
printf(" %s?%s ", start, end);
print(e->left, depth + 1);
printf(" %s:%s ", start, end);
print(e->right, depth + 1);
printf("%s)%s", start, end);
break;
}
}
#endif
}
// heap of truthtables; key = cost
struct todo {
uint32_t data[N];
uint32_t n;
// truthtable -> index in 'todo'
uint32_t reverse[N];
} *todo;
// create a list of the "done" truthtables
struct done {
uint64_t headtails[N], next[N], head;
} *done;
void calculate_simplifications(void)
{
// init 'lookup':
for (uint64_t i = 0; i < N; i++)
{
if (i % 42949672 == 0)
{
printf("init lookup: %.2f%%\n", (double) i * 100 / N);
}
lookup[i].kind = ek_unreachable;
lookup[i].cost = INT_MAX;
}
// init 'todo':
{
todo->n = 0;
for (uint64_t i = 0; i < N; i++)
{
if (i % 42949672 == 0)
{
printf("init todo: %.2f%%\n", (double) i * 100 / N);
}
todo->reverse[i] = (uint32_t) -1;
}
}
uint32_t pop(void)
{
printf(" pop()\n");
assert(todo->n > 0);
uint32_t retval = todo->data[0];
todo->reverse[retval] = (uint32_t) -1;
uint32_t moving = todo->data[todo->n-- - 1];
int cost = lookup[moving].cost;
uint64_t index = 0;
again:
{
printf(" index = %lu\n", index);
uint64_t left = index * 2 + 1;
uint64_t right = index * 2 + 2;
uint32_t smallest = moving;
if (left < todo->n && lookup[todo->data[left]].cost < cost)
smallest = todo->data[left];
if (right < todo->n && lookup[todo->data[right]].cost < lookup[smallest].cost)
smallest = todo->data[right];
if (smallest == moving)
{
todo->data[index] = moving;
assert(index < 4294967296);
todo->reverse[moving] = (uint32_t) index;
}
else
{
uint32_t new = todo->reverse[smallest];
todo->data[index] = smallest;
assert(index < 4294967296);
todo->reverse[smallest] = (uint32_t) index;
index = new;
goto again;
}
}
printf(" return 0b%032b\n", retval);
return retval;
}
void append(uint32_t truthtable, int cost)
{
printf("append(truthtable = 0b%032b, cost = %i)\n", truthtable, cost);
assert(todo->reverse[truthtable] == (uint32_t) -1);
assert(todo->n < N);
uint32_t index = (uint32_t) todo->n++, new_index;
printf(" index = %i\n", index);
while (index > 0 && lookup[todo->data[new_index = (index - 1) / 2]].cost > cost)
{
todo->data[index] = todo->data[new_index];
todo->reverse[todo->data[new_index]] = index;
index = new_index;
printf(" index = %i\n", index);
}
todo->data[index] = truthtable;
todo->reverse[truthtable] = index;
lookup[truthtable].cost = cost;
}
void update(uint16_t truthtable, int cost)
{
assert(!"TODO");
#if 0
assert(todo->reverse[truthtable] != -1);
assert(cost < lookup[truthtable].cost);
int index =todo-> reverse[truthtable], new_index;
while (index > 0 && lookup[todo->data[new_index = (index - 1) / 2]].cost > cost)
{
todo->data[index] = todo->data[new_index];
todo->reverse[todo->data[new_index]] = index;
index = new_index;
}
todo->data[index] = truthtable;
todo->reverse[truthtable] = index;
lookup[truthtable].cost = cost;
#endif
}
// init 'done':
{
done->head = (uint64_t) -1;
for (uint64_t i = 0; i < N; i++)
{
done->headtails[i] = (uint64_t) -1;
if (i % 42949672 == 0)
{
printf("init done: %.2f%%\n", (double) i * 100 / N);
}
}
}
void insert(uint32_t index)
{
printf(" insert(0b%032b)\n", index);
assert(!"TODO");
#if 0
uint32_t head = index & 1 ? index & ~(index & -index) : index;
uint32_t prevhead = (uint32_t) -1;
while (false
|| done->headtails[head] == (uint32_t) -1
|| index < done->headtails[head])
{
done->headtails[head] = index;
prevhead = head, head = head & ~(head & -head);
}
printf(" head = %lu\n", head);
if (done->headtails[head] < index)
{
if (prevhead == (uint32_t) -1)
{
assert(done->headtails[head] == head);
done->next[head] = index;
}
else
{
uint32_t tophalftail = done->headtails[prevhead - 1];
assert(tophalftail != (uint32_t) -1);
done->next[tophalftail] = index;
}
}
else
{
done->head = index;
}
uint32_t n = ~index & M;
uint32_t tail = index & 1 ? index : index | (n & -n);
uint32_t prevtail = (uint32_t) -1;
while (false
|| done->headtails[tail] == (uint32_t) -1
|| done->headtails[tail] < index)
{
done->headtails[tail] = index;
prevtail = tail, tail = tail | (n = ~tail & M, n & -n);
}
printf(" tail = %lu\n", tail);
if (index < done->headtails[tail])
{
if (prevtail == (uint32_t) -1)
{
assert(done->headtails[tail] == tail);
done->next[index] = tail;
}
else
{
int bottomhalfhead = done->headtails[prevtail + 1];
assert(bottomhalfhead != (uint32_t) -1);
done->next[index] = bottomhalfhead;
}
}
else
{
done->next[index] = (uint32_t) -1;
}
#endif
}
append(V, 0), lookup[V].kind = ek_V;
append(W, 0), lookup[W].kind = ek_W;
append(X, 0), lookup[X].kind = ek_X;
append(Y, 0), lookup[Y].kind = ek_Y;
append(Z, 0), lookup[Z].kind = ek_Z;
append(0, 1), lookup[0].kind = ek_0;
append(M, 1), lookup[M].kind = ek_1;
for (uint64_t iterations = 1; iterations <= N; iterations++)
{
printf("iterations = %lu\n", iterations);
assert(todo->n);
uint32_t truthtable = pop();
insert(truthtable);
int cost = lookup[truthtable].cost;
printf("%lu of %lu (%.2f%%): [%i] ",
iterations, N, (100.0 * (double) iterations / N), cost);
print(truthtable, 0), puts("");
assert(!"TODO");
#if 0
// consider NOT:
if (use_operators.not)
{
uint16_t not_truthtable = ~truthtable & M;
int not_cost = cost + 1;
if (not_cost < lookup[not_truthtable].cost)
{
if (todo->reverse[not_truthtable] == -1)
{
append(not_truthtable, not_cost);
}
else
{
update(not_truthtable, not_cost);
}
lookup[not_truthtable].kind = ek_not;
lookup[not_truthtable].left = truthtable;
}
}
#define BINARY_OPERATOR(ekind, function) \
{ \
for (int i = done->head; i != -1; i = done->next[i]) \
{ \
{ \
uint16_t bin_truthtable = function(truthtable, i) & M; \
\
int bin_cost = 1 + cost + lookup[i].cost; \
\
if (bin_cost < lookup[bin_truthtable].cost) \
{ \
if (todo->reverse[bin_truthtable] == -1) \
append(bin_truthtable, bin_cost); \
else \
update(bin_truthtable, bin_cost); \
\
lookup[bin_truthtable].kind = ekind; \
lookup[bin_truthtable].left = truthtable; \
lookup[bin_truthtable].right = i; \
} \
} \
\
{ \
uint16_t bin_truthtable = function(i, truthtable) & M; \
\
int bin_cost = 1 + cost + lookup[i].cost; \
\
if (bin_cost < lookup[bin_truthtable].cost) \
{ \
if (todo->reverse[bin_truthtable] == -1) \
append(bin_truthtable, bin_cost); \
else \
update(bin_truthtable, bin_cost); \
\
lookup[bin_truthtable].kind = ekind; \
lookup[bin_truthtable].left = i; \
lookup[bin_truthtable].right = truthtable; \
} \
} \
} \
}
#define OR(a, b) ((a) | (b))
#define AND(a, b) ((a) & (b))
#define ORN(a, b) (~(a) | (b))
#define NOR(a, b) ~( (a) | (b))
#define ANDN(a, b) (~(a) & (b))
#define NAND(a, b) ~( (a) & (b))
#define XOR(a, b) (( a) ^ (b))
#define NXOR(a, b) ~( (a) ^ (b))
#define LT(a, b) ((~a) & (b))
#define LTE(a, b) ((~a) | (b))
#define GT(a, b) (( a) & ~(b))
#define GTE(a, b) (( a) | ~(b))
if (use_operators.or)
{
BINARY_OPERATOR(ek_or, OR);
}
if (use_operators.and)
{
BINARY_OPERATOR(ek_and, AND);
}
if (use_operators.orn)
{
BINARY_OPERATOR(ek_orn, ORN);
}
if (use_operators.nor)
{
BINARY_OPERATOR(ek_nor, NOR);
}
if (use_operators.andn)
{
BINARY_OPERATOR(ek_andn, ANDN);
}
if (use_operators.nand)
{
BINARY_OPERATOR(ek_nand, NAND);
}
if (use_operators.xor)
{
BINARY_OPERATOR(ek_xor, XOR);
}
if (use_operators.nxor)
{
BINARY_OPERATOR(ek_nxor, NXOR);
}
if (use_operators.lt)
{
BINARY_OPERATOR(ek_lt, LT);
}
if (use_operators.lte)
{
BINARY_OPERATOR(ek_lte, LTE);
}
if (use_operators.gt)
{
BINARY_OPERATOR(ek_gt, GT);
}
if (use_operators.gte)
{
BINARY_OPERATOR(ek_gte, GTE);
}
if (use_operators.ternary)
{
for (int i = done->head; i != -1; i = done->next[i])
{
for (int j = done->head; j != -1; j = done->next[j])
{
int ternary_cost = 1 + cost + lookup[i].cost + lookup[j].cost;
#define TERNARY(C, T, F) \
{ \
uint16_t ternary_truthtable = \
((C) & (T)) | (~(C) & (F)); \
\
if (ternary_cost < lookup[ternary_truthtable].cost) \
{ \
if (todo->reverse[ternary_truthtable] == -1) \
{ \
append(ternary_truthtable, ternary_cost); \
} \
else \
{ \
update(ternary_truthtable, ternary_cost); \
} \
\
lookup[ternary_truthtable].kind = ek_ternary; \
lookup[ternary_truthtable].cond = (C); \
lookup[ternary_truthtable].left = (T); \
lookup[ternary_truthtable].right = (F); \
} \
} \
TERNARY(truthtable, i, j);
TERNARY(i, truthtable, j);
TERNARY(i, j, truthtable);
}
}
}
#endif
}
}
void get_simplifications(void)
{
char path[PATH_MAX] = ".simplifier-cache-5-var";
if (use_operators.not)
strcat(path, "-not");
if (use_operators.or)
strcat(path, "-or");
if (use_operators.orn)
strcat(path, "-orn");
if (use_operators.nor)
strcat(path, "-nor");
if (use_operators.and)
strcat(path, "-and");
if (use_operators.andn)
strcat(path, "-andn");
if (use_operators.nand)
strcat(path, "-nand");
if (use_operators.xor)
strcat(path, "-xor");
if (use_operators.nxor)
strcat(path, "-nxor");
if (use_operators.lt)
strcat(path, "-lt");
if (use_operators.lte)
strcat(path, "-lte");
if (use_operators.gt)
strcat(path, "-gt");
if (use_operators.gte)
strcat(path, "-gte");
if (use_operators.ternary)
strcat(path, "-ternary");
strcat(path, ".bin");
int fd = -1;
if (force_rebuild)
{
goto rebuild;
}
else if ((fd = open(path, O_RDONLY)) > 0)
{
// great, just read it into memory
if (read(fd, lookup, sizeof(lookup)) < (ssize_t) sizeof(lookup))
{
printf("%s: read() to cache failed: %m\n", argv0);
exit(1);
}
}
else if (fd < 0 && errno == ENOENT)
{
if (!quiet)
{
puts(""
"Oh! looks like you're running this for the first time" "\n"
"I'll have to build up my cache of simplifications" "\n"
"I'll only have to do this once." "\n"
"\n"
"This may take a while." "\n"
"");
}
rebuild: {};
if (!quiet && !verbose)
{
puts("re-run with '-v' to watch progress");
}
if (!quiet && !assume_yes)
{
puts("");
puts("any input to start:"), getchar();
puts("");
}
calculate_simplifications();
fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, 0664);
if (write(fd, lookup, sizeof(lookup)) < (ssize_t) sizeof(lookup))
{
printf("%s: write() to cache failed: %m\n", argv0);
exit(1);
}
}
else
{
// something else
assert(!"TODO");
}
if (fd > 0)
{
close(fd);
}
}
uint16_t evaluate(const char* text)
{
assert(!"TODO");
#if 0
enum {
tk_uninitialized,
tk_0,
tk_1,
tk_w,
tk_x,
tk_y,
tk_z,
tk_oparen,
tk_cparen,
tk_emark,
tk_emarkequals,
tk_emarkvbar,
tk_emarkampersand,
tk_equalsequals,
tk_vbarvbar,
tk_vbaremark,
tk_qmark,
tk_less_than,
tk_less_than_eq,
tk_greater_than,
tk_greater_than_eq,
tk_ampersandemark,
tk_ampersandampersand,
tk_colon,
tk_EOF,
} tokenkind = tk_uninitialized;
const char* moving = text;
void next_token(void)
{
while (*moving && *moving == ' ')
moving++;
switch (*moving)
{
case 0:
tokenkind = tk_EOF;
break;
case '0':
tokenkind = tk_0, moving++;
break;
case '1':
tokenkind = tk_1, moving++;
break;
case 'w':
tokenkind = tk_w, moving++;
break;
case 'x':
tokenkind = tk_x, moving++;
break;
case 'y':
tokenkind = tk_y, moving++;
break;
case 'z':
tokenkind = tk_z, moving++;
break;
case '(':
tokenkind = tk_oparen, moving++;
break;
case ')':
tokenkind = tk_cparen, moving++;
break;
case '?':
tokenkind = tk_qmark, moving++;
break;
case ':':
tokenkind = tk_colon, moving++;
break;
// either '||' or '|!':
case '|':
{
moving++;
switch (*moving)
{
case '|':
tokenkind = tk_vbarvbar, moving++;
break;
case '!':
tokenkind = tk_vbaremark, moving++;
break;
default:
{
puts("syntax error");
exit(1);
break;
}
}
break;
}
// either '&&' or '&!':
case '&':
{
moving++;
switch (*moving)
{
case '&':
tokenkind = tk_ampersandampersand, moving++;
break;
case '!':
tokenkind = tk_ampersandemark, moving++;
break;
default:
{
puts("syntax error");
exit(1);
break;
}
}
break;
}
// either '!' or '!=' or '!&' or '!|'
case '!':
{
moving++;
switch (*moving)
{
case '=':
tokenkind = tk_emarkequals, moving++;
break;
case '|':
tokenkind = tk_emarkvbar, moving++;
break;
case '&':
tokenkind = tk_emarkampersand, moving++;
break;
default:
tokenkind = tk_emark;
break;
}
break;
}
case '<':
{
moving++;
switch (*moving)
{
case '=':
tokenkind = tk_less_than_eq, moving++;
break;
default:
{
tokenkind = tk_less_than;
break;
}
}
break;
}
case '>':
{
moving++;
switch (*moving)
{
case '=':
tokenkind = tk_greater_than_eq, moving++;
break;
default:
{
tokenkind = tk_greater_than;
break;
}
}
break;
}
// could only be '==':
case '=':
{
moving++;
switch (*moving)
{
case '=':
tokenkind = tk_equalsequals, moving++;
break;
default:
{
puts("syntax error");
exit(1);
break;
}
}
break;
}
default:
assert(!"TODO");
break;
}
}
next_token();
uint16_t parse_root(void)
{
uint16_t parse_ternary(void)
{
uint16_t parse_ors(void)
{
uint16_t parse_ands(void)
{
uint16_t parse_equals(void)
{
uint16_t parse_compares(void)
{
uint16_t parse_prefix(void)
{
uint16_t parse_primary(void)
{
uint16_t retval;
switch (tokenkind)
{
case tk_0:
retval = 0, next_token();
break;
case tk_1:
retval = M, next_token();
break;
case tk_w:
retval = W, next_token();
break;
case tk_x:
retval = X, next_token();
break;
case tk_y:
retval = Y, next_token();
break;
case tk_z:
retval = Z, next_token();
break;
case tk_oparen:
{
next_token();
retval = parse_root();
if (tokenkind != tk_cparen)
{
assert(!"NOPE");
}
next_token();
break;
}
default:
assert(!"TODO");
break;
}
return retval;
}
if (tokenkind == tk_emark)
{
next_token();
return ~parse_prefix();
}
else
{
return parse_primary();
}
}
uint16_t left = parse_prefix();
again: switch (tokenkind)
{
case tk_less_than:
{
next_token();
left = (~left & parse_equals()) & M;
goto again;
}
case tk_less_than_eq:
{
next_token();
left = (~left | parse_equals()) & M;
goto again;
}
case tk_greater_than_eq:
{
next_token();
left = ( left | ~parse_equals()) & M;
goto again;
}
case tk_greater_than:
{
next_token();
left = ( left & ~parse_equals()) & M;
goto again;
}
default:
break;
}
return left;
}
uint16_t left = parse_compares();
again: switch (tokenkind)
{
case tk_equalsequals:
{
next_token();
left = ~(left ^ parse_equals()) & M;
goto again;
}
case tk_emarkequals:
{
next_token();
left = left ^ parse_equals();
goto again;
}
default:
break;
}
return left;
}
uint16_t left = parse_equals();
again: switch (tokenkind)
{
case tk_ampersandampersand:
{
next_token();
left = left & parse_equals();
goto again;
}
case tk_ampersandemark:
{
next_token();
left = ~left & parse_equals();
goto again;
}
case tk_emarkampersand:
{
next_token();
left = ~(left & parse_equals());
goto again;
}
default:
break;
}
return left;
}
uint16_t left = parse_ands();
again: switch (tokenkind)
{
case tk_vbarvbar:
{
next_token();
left = left | parse_ands();
goto again;
}
case tk_vbaremark:
{
next_token();
left = (~left | parse_ands()) & M;
goto again;
}
case tk_emarkvbar:
{
next_token();
left = ~(left | parse_ands()) & M;
goto again;
}
default:
break;
}
return left;
}
uint16_t cond = parse_ors();
if (tokenkind == tk_qmark)
{
next_token();
uint16_t left = parse_ors();
if (tokenkind != tk_colon)
{
puts("syntax error!");
exit(1);
}
next_token();
uint16_t right = parse_ternary();
return (cond & left) | (~cond & right);
}
else
{
return cond;
}
}
return parse_ternary();
}
uint16_t truthtable = parse_root();
if (tokenkind != tk_EOF)
{
puts("syntax error!");
exit(1);
}
return truthtable;
#endif
}
int main(int argc, char* const* argv)
{
parse_args(argc, argv);
todo = malloc(sizeof(*todo));
done = malloc(sizeof(*done));
get_simplifications();
if (print_all_and_quit)
{
assert(!"TODO");
#if 0
for (int i = 0; i < N; i++)
{
int cost = lookup[i].cost;
if (cost != INT_MAX)
{
printf("0b%016b: [%2i]: ", i, cost), print(i, 0), puts("");
}
}
#endif
}
else if (print_stats)
{
assert(!"TODO");
#if 0
printf("statistics:" "\n");
uintmax_t total_cost = 0;
int n = 0;
int max_cost = 0;
for (int i = 0; i < N; i++)
{
int cost = lookup[i].cost;
if (cost != INT_MAX)
{
if (max_cost < cost)
{
max_cost = cost;
}
total_cost += cost;
n += 1;
}
}
if (n)
{
printf("minimum operators needed: 1" "\n");
printf("maximum operators needed: %i" "\n", max_cost);
double average = (double) total_cost / n;
printf("average operators needed: %g" "\n", average);
double working = 0.0;
for (int i = 0; i < N; i++)
{
int cost = lookup[i].cost;
if (cost != INT_MAX)
{
working += pow(cost - average, 2);
}
}
double stddev = sqrt(working / (n - 1));
printf("standard deviation: %g" "\n", stddev);
}
else
{
puts("everything unreachable: no statistics to give");
}
#endif
}
else if (command)
{
assert(!"TODO");
#if 0
uint16_t truthtable = evaluate(command);
// printf("truthtable = 0b%016b\n", truthtable);
if (lookup[truthtable].kind == ek_unreachable)
{
puts("unreachable");
}
else
{
printf("%2i: ", lookup[truthtable].cost), print(truthtable, 0), puts("");
}
#endif
}
else
{
assert(!"TODO");
#if 0
if (!quiet)
{
puts("Use C-style syntax for boolean operators and expressions.");
puts("Available variables: 'w', 'x', 'y' and 'z'.");
puts("Extended operators: nor is '!|', orn is '|!', nand is '!&', andn is '&!'.");
puts("Comparison operators are also suppported.");
}
for (char* line; (line = readline(">>> ")); free(line))
{
if (!*line) continue;
add_history(line);
uint16_t truthtable = evaluate(line);
// printf("truthtable = 0b%016b\n", truthtable);
if (lookup[truthtable].kind == ek_unreachable)
{
puts("unreachable");
}
else
{
printf("%2i: ", lookup[truthtable].cost),
print(truthtable, 0), puts("");
}
}
#endif
}
return 0;
}