From 453cd8af9cee081f1c786e8133324b839c4b637d Mon Sep 17 00:00:00 2001 From: Zander Thannhauser Date: Tue, 10 Jun 2025 20:51:47 -0500 Subject: [PATCH] added c implementation, which is MUCH faster! --- .gitignore | 2 + main.c | 1190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 46 +- makefile | 20 + 4 files changed, 1241 insertions(+), 17 deletions(-) create mode 100644 main.c create mode 100644 makefile diff --git a/.gitignore b/.gitignore index a07cda8..bfe84f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ simplifications.bin +.simplifier-*.bin + diff --git a/main.c b/main.c new file mode 100644 index 0000000..8984604 --- /dev/null +++ b/main.c @@ -0,0 +1,1190 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define argv0 program_invocation_name + +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 ternary; +} use_operators; + +bool assume_yes = false; + +bool verbose = false; + +static void parse_args(int argc, char* const* argv) +{ + bool unset_operators = true; + + for (int opt; (opt = getopt(argc, argv, "pyvc:eEo:")) != -1; ) switch (opt) + { + case 'p': + print_all_and_quit = true; + break; + + case 'y': + assume_yes = true; + break; + + case 'v': + verbose = true; + break; + + case 'c': + command = optarg; + break; + + case 'E': + use_operators.ternary = true; + // fallthrough + + case 'e': + 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")) + use_operators.not = true; + else if (!strcmp(moving, "or")) + use_operators.or = true; + else if (!strcmp(moving, "orn")) + use_operators.orn = true; + else if (!strcmp(moving, "nor")) + use_operators.nor = true; + else if (!strcmp(moving, "and")) + use_operators.and = true; + else if (!strcmp(moving, "andn")) + use_operators.andn = true; + else if (!strcmp(moving, "nand")) + use_operators.nand = true; + else if (!strcmp(moving, "xor")) + use_operators.xor = true; + else if (!strcmp(moving, "nxor")) + use_operators.nxor = true; + else + { + assert(!"TODO"); + } + } + break; + } + + default: + assert(!"TODO"); + break; + } + + if (unset_operators) + { + use_operators.not = true; + use_operators.or = true; + use_operators.and = true; + } +} + +#define W 0b0101010101010101 +#define X 0b0011001100110011 +#define Y 0b0000111100001111 +#define Z 0b0000000011111111 +#define M 0b1111111111111111 + +#define N (65536) + +enum kind { + ek_undef, + ek_0, + ek_1, + 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_ternary, +}; + +struct expr { + enum kind kind; + + uint16_t cond, left, right; +} lookup[N]; + +// truthtable -> cost +int costs[N] = {}; + +static void print(uint16_t truthtable) +{ + const struct expr* e = &lookup[truthtable]; + + switch (e->kind) + { + case ek_undef: + assert(!"NOPE"); + break; + + case ek_0: printf("0"); break; + case ek_1: printf("1"); break; + + case ek_W: printf("w"); break; + case ek_X: printf("x"); break; + case ek_Y: printf("y"); break; + case ek_Z: printf("z"); break; + + case ek_not: + printf("(!"), print(e->left), printf(")"); + break; + + case ek_or: + printf("("), print(e->left), printf(" || "), print(e->right), printf(")"); + break; + + case ek_orn: + printf("("), print(e->left), printf(" |! "), print(e->right), printf(")"); + break; + + case ek_nor: + printf("("), print(e->left), printf(" !| "), print(e->right), printf(")"); + break; + + case ek_and: + printf("("), print(e->left), printf(" && "), print(e->right), printf(")"); + break; + + case ek_andn: + printf("("), print(e->left), printf(" &! "), print(e->right), printf(")"); + break; + + case ek_nand: + printf("("), print(e->left), printf(" !& "), print(e->right), printf(")"); + break; + + case ek_xor: + printf("("), print(e->left), printf(" != "), print(e->right), printf(")"); + break; + + case ek_nxor: + printf("("), print(e->left), printf(" == "), print(e->right), printf(")"); + break; + + case ek_ternary: + printf("("), print(e->cond), printf(" ? "), + print(e->left), printf(" : "), print(e->right), printf(")"); + break; + } +} + +void calculate_simplifications(void) +{ + // heap of truthtables; key = cost + uint16_t todo[N]; + int todo_n = 0; + + // truthtable -> index in 'todo' + int reverse[N]; + + // init: + for (int i = 0; i < N; i++) + { + lookup[i].kind = ek_undef; + + reverse[i] = -1; + + costs[i] = INT_MAX; + } + + uint16_t pop(void) + { + assert(todo_n > 0); + + uint16_t retval = todo[0]; + + reverse[retval] = -1; + + uint16_t moving = todo[todo_n-- - 1]; + + int cost = costs[moving]; + + int index = 0; + + again: + { + int left = index * 2 + 1; + int right = index * 2 + 2; + + uint16_t smallest = moving; + + if (left < todo_n && costs[todo[left]] < cost) + smallest = todo[left]; + + if (right < todo_n && costs[todo[right]] < costs[smallest]) + smallest = todo[right]; + + if (smallest == moving) + { + todo[index] = moving; + + reverse[moving] = index; + } + else + { + int new = reverse[smallest]; + + todo[index] = smallest; + + reverse[smallest] = index; + + index = new; + + goto again; + } + } + + return retval; + } + + void append(uint16_t truthtable, int cost) + { + assert(reverse[truthtable] == -1); + + int index = todo_n++, new_index; + + while (index > 0 && costs[todo[new_index = (index - 1) / 2]] > cost) + { + todo[index] = todo[new_index]; + + reverse[todo[new_index]] = index; + + index = new_index; + } + + todo[index] = truthtable; + + reverse[truthtable] = index; + + costs[truthtable] = cost; + } + + void update(uint16_t truthtable, int cost) + { + assert(reverse[truthtable] != -1); + + assert(cost < costs[truthtable]); + + int index = reverse[truthtable], new_index; + + while (index > 0 && costs[todo[new_index = (index - 1) / 2]] > cost) + { + todo[index] = todo[new_index]; + + reverse[todo[new_index]] = index; + + index = new_index; + } + + todo[index] = truthtable; + reverse[truthtable] = index; + + costs[truthtable] = cost; + } + + 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; + + while (todo_n) + { + uint16_t truthtable = pop(); + + int cost = costs[truthtable]; + + if (verbose) + { + int left = N - todo_n; + + printf("%i of %i (%.2f%%): [%i] ", left, N, (100.0 * left / N), cost); + + print(truthtable), puts(""); + } + + // consider NOT: + if (use_operators.not) + { + uint16_t not_truthtable = ~truthtable & M; + + int not_cost = cost + 1; + + if (not_cost < costs[not_truthtable]) + { + if (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 = 0; i < N; i++) \ + { \ + if (costs[i] != INT_MAX) \ + { \ + { \ + uint16_t bin_truthtable = function(truthtable, i) & M; \ + \ + int bin_cost = 1 + cost + costs[i]; \ + \ + if (bin_cost < costs[bin_truthtable]) \ + { \ + if (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 + costs[i]; \ + \ + if (bin_cost < costs[bin_truthtable]) \ + { \ + if (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)) + + 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.ternary) + { + assert(!"TODO"); + } + + // consider ternary: + #if 0 + { + for (int i = 0; i < N; i++) + { + if (costs[i] != INT_MAX) + { + for (int j = 0; j < N; j++) + { + if (costs[j] != INT_MAX) + { + uint16_t ternary_truthtable = + (truthtable & i) | (~truthtable & j); + + int ternary_cost = 1 + cost + costs[i] + costs[j]; + + if (ternary_cost < costs[ternary_truthtable]) + { + if (reverse[ternary_truthtable] == -1) + { + // add it: + append(ternary_truthtable, ternary_cost); + } + else + { + // update it: + update(ternary_truthtable, ternary_cost); + } + + lookup[ternary_truthtable].kind = ek_ternary; + lookup[ternary_truthtable].cond = truthtable; + lookup[ternary_truthtable].left = i; + lookup[ternary_truthtable].right = j; + } + } + } + } + } + } + #endif + } +} + +void get_simplifications(void) +{ + char path[PATH_MAX] = ".simplifier-cache"; + + 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.ternary) + strcat(path, "-ternary"); + + strcat(path, ".bin"); + + int fd = open(path, O_RDONLY); + + if (fd > 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); + } + + if (read(fd, costs, sizeof(costs)) < (ssize_t) sizeof(costs)) + { + printf("%s: read() to cache failed: %m\n", argv0); + exit(1); + } + } + else if (fd < 0 && errno == ENOENT) + { + 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" + ""); + + if (!verbose) + { + puts("re-run with '-v' to watch progress"); + } + + if (!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); + } + + if (write(fd, costs, sizeof(costs)) < (ssize_t) sizeof(costs)) + { + 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) +{ + 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: + assert(!"TODO"); + 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; +} + +int main(int argc, char* const* argv) +{ + parse_args(argc, argv); + + get_simplifications(); + + if (print_all_and_quit) + { + for (int i = 0; i < N; i++) + { + int cost = costs[i]; + + if (cost != INT_MAX) + { + printf("0b%016b: [%2i]: ", i, cost), print(i), puts(""); + } + } + } + else if (command) + { + uint16_t truthtable = evaluate(command); + + // printf("truthtable = 0b%016b\n", truthtable); + + if (costs[truthtable] == INT_MAX) + { + puts("unreachable"); + } + else + { + printf("%2i: ", costs[truthtable]), print(truthtable), puts(""); + } + } + else for (char* line; (line = readline(">>> ")); free(line)) + { + uint16_t truthtable = evaluate(line); + + // printf("truthtable = 0b%016b\n", truthtable); + + if (costs[truthtable] == INT_MAX) + { + puts("unreachable"); + } + else + { + printf("%2i: ", costs[truthtable]), print(truthtable), puts(""); + } + } + + return 0; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main.py b/main.py index 3b2f3bc..050824f 100755 --- a/main.py +++ b/main.py @@ -21,6 +21,13 @@ def parse_args(argv): This options allows use of: nor, nand, xor, nxor, andn, orn. ''') + parser.add_argument('-E', '--extra-extended-operators', action='store_true', help=''' + In addition to the operators of '--extended-operators' introduce + the ternary ('?:') operator. + This operator is very powerful but dramatically increases + simplification time by an nth degree. + ''') + parser.add_argument('-o', '--custom-operators', help=''' Pick and choose which operators the simplifier can use. Comma seperated. You can refer to them using their names or their symbols. @@ -91,6 +98,8 @@ def determine_available_operators(args): raise BaseException(f"not an operator: '{o}'"); return available_operators; + elif args.extra_extended_operators: + return set(standard + extended + ("?:", )); else: return set(standard); @@ -305,9 +314,10 @@ def calculate_simplifications(args, available_operators): # consider unary operators: for name, function in sorted(unary_operators.items()): if name in available_operators: + unary_cost = my_cost + 1; + unary_truthtable = function(my_truthtable) & M; unary_expression = (name, my_expression); - unary_cost = my_cost + 1; consider(unary_truthtable, unary_expression, unary_cost); @@ -315,11 +325,12 @@ def calculate_simplifications(args, available_operators): for name, function in sorted(binary_operators.items()): if name in available_operators: for other_truthtable, other_expression in sorted(lookup.items()): + binary_cost = my_cost + 1 + costs[other_truthtable]; + # x + y binary_truthtable = function(my_truthtable, other_truthtable); binary_truthtable = binary_truthtable & M binary_expression = (name, my_expression, other_expression); - binary_cost = my_cost + 1 + costs[other_truthtable]; consider(binary_truthtable, binary_expression, binary_cost); @@ -327,7 +338,6 @@ def calculate_simplifications(args, available_operators): binary_truthtable = function(other_truthtable, my_truthtable); binary_truthtable = binary_truthtable & M binary_expression = (name, other_expression, my_expression); - binary_cost = my_cost + 1 + costs[other_truthtable]; consider(binary_truthtable, binary_expression, binary_cost); @@ -335,25 +345,27 @@ def calculate_simplifications(args, available_operators): for name, function in sorted(ternary_operators.items()): if name in available_operators: s = sorted(lookup.items()); - for i, (a_truthtable, a_expression) in enumerate(s): - # print(f'i = {i}'); + for a_truthtable, a_expression in s: for b_truthtable, b_expression in s: - # x ? y : z - ternary_truthtable = function( - my_truthtable, a_truthtable, b_truthtable) & M; - ternary_expression = (name, - my_expression, a_expression, b_expression); - ternary_cost = 1 + my_cost + \ - costs[a_truthtable] + costs[b_truthtable]; + ternary_cost = 1 + my_cost + costs[a_truthtable] + costs[b_truthtable]; - consider(ternary_truthtable, ternary_expression, \ - ternary_cost); + # x ? y : z + ternary_truthtable = function(my_truthtable, a_truthtable, b_truthtable) & M; + ternary_expression = (name, my_expression, a_expression, b_expression); + + consider(ternary_truthtable, ternary_expression, ternary_cost); # y ? x : z - # assert(not "TODO"); + ternary_truthtable = function(a_truthtable, my_truthtable, b_truthtable) & M; + ternary_expression = (name, a_expression, my_expression, b_expression); - # z ? y : z - # assert(not "TODO"); + consider(ternary_truthtable, ternary_expression, ternary_cost); + + # y ? z : x + ternary_truthtable = function(a_truthtable, b_truthtable, my_truthtable) & M; + ternary_expression = (name, a_expression, b_expression, my_expression); + + consider(ternary_truthtable, ternary_expression, ternary_cost); return costs, lookup diff --git a/makefile b/makefile new file mode 100644 index 0000000..c98ace4 --- /dev/null +++ b/makefile @@ -0,0 +1,20 @@ + +# vim: noexpandtab tabstop=4 : + +args = + +cc = gcc + +cppflags = -D _GNU_SOURCE + +cflags = -Werror -Wall -Wextra -Wstrict-prototypes + +cflags += -Wno-unused + +ldflags += -lreadline + +/tmp/4-variable-simplifier: main.c + $(cc) $(cppflags) $(cflags) $< -o $@ $(ldflags) + +run: /tmp/4-variable-simplifier + $< $(args)