500 lines
13 KiB
C
500 lines
13 KiB
C
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
#include <defines.h>
|
|
|
|
#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;
|
|
}
|
|
|