#include #include #include #include #include "evaluate.h" 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: { 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; }