removed experimental stuff, since it was not any better than the classic 9 operators. switch from py-parsing to handrolled recursive descent
This commit is contained in:
parent
e3b0af2f12
commit
2499db7c7d
1 changed files with 338 additions and 162 deletions
498
main.py
498
main.py
|
|
@ -6,6 +6,8 @@ import argparse
|
||||||
import pickle;
|
import pickle;
|
||||||
import sys;
|
import sys;
|
||||||
|
|
||||||
|
from colorsys import hsv_to_rgb;
|
||||||
|
|
||||||
def parse_args(argv):
|
def parse_args(argv):
|
||||||
parser = argparse.ArgumentParser(prog = '4-variable-simplifier');
|
parser = argparse.ArgumentParser(prog = '4-variable-simplifier');
|
||||||
|
|
||||||
|
|
@ -24,24 +26,6 @@ def parse_args(argv):
|
||||||
You can refer to them using their names or their symbols.
|
You can refer to them using their names or their symbols.
|
||||||
''')
|
''')
|
||||||
|
|
||||||
parser.add_argument('-E', '--experimental-operators', action='store_true', \
|
|
||||||
help='''
|
|
||||||
For two boolean variables, there are four possible inputs into a
|
|
||||||
binary operator. For each of those four an operator could return true
|
|
||||||
or false. That would mean in theory there could exist up to 16
|
|
||||||
theoretical operators with different behaviours. Even with the
|
|
||||||
'extended operators' option, we're only introducing 9 possible
|
|
||||||
operators, that's less that 60% of the possibilities!
|
|
||||||
Some of these would of course be useless, like a binary operator that
|
|
||||||
always produces 'false' regardless of the input, for instance, but
|
|
||||||
other may be extremely useful for acting in place of much more complex
|
|
||||||
trees of operators. In theory, the simplifier would produce the
|
|
||||||
smallest most compact expression trees possible.
|
|
||||||
|
|
||||||
Of course, no one would implement something like this and dare
|
|
||||||
to anger the logic gods...
|
|
||||||
''')
|
|
||||||
|
|
||||||
parser.add_argument("-n", '--use-names', help='''
|
parser.add_argument("-n", '--use-names', help='''
|
||||||
Print the operator's names in the expression tree, rather than the
|
Print the operator's names in the expression tree, rather than the
|
||||||
symbols.
|
symbols.
|
||||||
|
|
@ -90,29 +74,6 @@ def determine_available_operators(args):
|
||||||
|
|
||||||
extended = ("!|", "!&", "!=", "==", "|!", "&!");
|
extended = ("!|", "!&", "!=", "==", "|!", "&!");
|
||||||
|
|
||||||
experimental = (
|
|
||||||
"<00>",
|
|
||||||
"<01>",
|
|
||||||
"<10>",
|
|
||||||
"<11>",
|
|
||||||
|
|
||||||
"<0000>",
|
|
||||||
"<0001>",
|
|
||||||
"<0010>",
|
|
||||||
"<0011>",
|
|
||||||
"<0100>",
|
|
||||||
"<0101>",
|
|
||||||
"<0110>",
|
|
||||||
"<0111>",
|
|
||||||
"<1000>",
|
|
||||||
"<1001>",
|
|
||||||
"<1010>",
|
|
||||||
"<1011>",
|
|
||||||
"<1100>",
|
|
||||||
"<1101>",
|
|
||||||
"<1110>",
|
|
||||||
"<1111>");
|
|
||||||
|
|
||||||
if args.extended_operators:
|
if args.extended_operators:
|
||||||
return set(standard + extended);
|
return set(standard + extended);
|
||||||
elif args.custom_operators:
|
elif args.custom_operators:
|
||||||
|
|
@ -129,29 +90,72 @@ def determine_available_operators(args):
|
||||||
raise BaseException(f"not an operator: '{o}'");
|
raise BaseException(f"not an operator: '{o}'");
|
||||||
|
|
||||||
return available_operators;
|
return available_operators;
|
||||||
elif args.experimental_operators:
|
|
||||||
return set(experimental);
|
|
||||||
else:
|
else:
|
||||||
return set(standard);
|
return set(standard);
|
||||||
|
|
||||||
def pretty(exp):
|
LITERAL_ESCAPE = "\033[38;2;200;200;100m";
|
||||||
|
VARIABLE_ESCAPE = "\033[38;2;100;100;200m";
|
||||||
|
|
||||||
|
operator_colors = [];
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
r, g, b = hsv_to_rgb(i / 10, 1.0, 0.8);
|
||||||
|
r, g, b = [int(255 * x) for x in (r, g, b)];
|
||||||
|
operator_colors.append(f"\033[38;2;{r};{g};{b}m");
|
||||||
|
|
||||||
|
RESET_ESCAPE = "\033[0m";
|
||||||
|
|
||||||
|
def pretty(exp, in_color = False, depth = 0):
|
||||||
|
|
||||||
|
start_color, end_color = "", "";
|
||||||
|
|
||||||
|
if in_color:
|
||||||
|
start_color = operator_colors[depth % len(operator_colors)];
|
||||||
|
|
||||||
|
end_color = RESET_ESCAPE;
|
||||||
|
|
||||||
|
retval = "";
|
||||||
|
|
||||||
match exp:
|
match exp:
|
||||||
case ("literal", x):
|
case ("literal", x):
|
||||||
return str(x);
|
retval = str(x);
|
||||||
|
|
||||||
|
if in_color:
|
||||||
|
retval = LITERAL_ESCAPE + retval + RESET_ESCAPE;
|
||||||
|
|
||||||
case ("variable", x):
|
case ("variable", x):
|
||||||
return x
|
retval = x
|
||||||
|
|
||||||
|
if in_color:
|
||||||
|
retval = VARIABLE_ESCAPE + retval + RESET_ESCAPE;
|
||||||
|
|
||||||
case (op, inner):
|
case (op, inner):
|
||||||
return f"({op}{pretty(inner)})"
|
retval += start_color + "(" + end_color;
|
||||||
|
|
||||||
|
retval += start_color + op + end_color;
|
||||||
|
|
||||||
|
retval += pretty(inner, in_color, depth + 1);
|
||||||
|
|
||||||
|
retval += start_color + ")" + end_color;
|
||||||
|
|
||||||
case (op, left, right):
|
case (op, left, right):
|
||||||
return f"({pretty(left)} {op} {pretty(right)})"
|
retval += start_color + "(" + end_color;
|
||||||
|
|
||||||
|
retval += pretty(left, in_color, depth + 1);
|
||||||
|
|
||||||
|
retval += " " + start_color + op + end_color + " ";
|
||||||
|
|
||||||
|
retval += pretty(right, in_color, depth + 1);
|
||||||
|
|
||||||
|
retval += start_color + ")" + end_color;
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
print(exp);
|
print(exp);
|
||||||
assert(not "TODO");
|
assert(not "TODO");
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
|
||||||
W = 0b0101_0101_0101_0101
|
W = 0b0101_0101_0101_0101
|
||||||
X = 0b0011_0011_0011_0011
|
X = 0b0011_0011_0011_0011
|
||||||
Y = 0b0000_1111_0000_1111
|
Y = 0b0000_1111_0000_1111
|
||||||
|
|
@ -205,13 +209,6 @@ def calculate_simplifications(args, available_operators):
|
||||||
|
|
||||||
unary_operators = {
|
unary_operators = {
|
||||||
'!': lambda x: ~x,
|
'!': lambda x: ~x,
|
||||||
|
|
||||||
# these were found by running the simplifier with -o xor,and,or,not
|
|
||||||
# 10 - x
|
|
||||||
"<00>": lambda x: 0,
|
|
||||||
"<01>": lambda x: ~x,
|
|
||||||
"<10>": lambda x: x,
|
|
||||||
"<11>": lambda x: M,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binary_operators = {
|
binary_operators = {
|
||||||
|
|
@ -226,26 +223,6 @@ def calculate_simplifications(args, available_operators):
|
||||||
|
|
||||||
'!=': lambda x, y: x ^ y, # xor
|
'!=': lambda x, y: x ^ y, # xor
|
||||||
'==': lambda x, y: ~(x ^ y), # nxor
|
'==': lambda x, y: ~(x ^ y), # nxor
|
||||||
|
|
||||||
# these were found by running the simplifier with -o xor,and,or,not
|
|
||||||
# 0011 - x
|
|
||||||
# 0101 - y
|
|
||||||
"<0000>": lambda x, y: 0,
|
|
||||||
"<1000>": lambda x, y: ~(x | y),
|
|
||||||
"<0100>": lambda x, y: x ^ (x | y),
|
|
||||||
"<1100>": lambda x, y: ~x,
|
|
||||||
"<0010>": lambda x, y: x ^ (x & y),
|
|
||||||
"<1010>": lambda x, y: ~y,
|
|
||||||
"<0110>": lambda x, y: x ^ y,
|
|
||||||
"<1110>": lambda x, y: ~(x & y),
|
|
||||||
"<0001>": lambda x, y: x & y,
|
|
||||||
"<1001>": lambda x, y: x ^ ~y,
|
|
||||||
"<0101>": lambda x, y: y,
|
|
||||||
"<1101>": lambda x, y: ~x | y,
|
|
||||||
"<0011>": lambda x, y: x,
|
|
||||||
"<1011>": lambda x, y: x | ~y,
|
|
||||||
"<0111>": lambda x, y: x | y,
|
|
||||||
"<1111>": lambda x, y: M,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def print_status():
|
def print_status():
|
||||||
|
|
@ -374,109 +351,288 @@ def get_simplifications(args, available_operators):
|
||||||
|
|
||||||
return cache[available_operators];
|
return cache[available_operators];
|
||||||
|
|
||||||
def create_parser():
|
# def create_parser():
|
||||||
from pyparsing import infix_notation, opAssoc, Word, oneOf
|
# from pyparsing import infixNotation, opAssoc, Word, oneOf
|
||||||
|
#
|
||||||
|
# # this can't handle parenthesis very well...
|
||||||
|
# # do I really have to write my own parser?
|
||||||
|
# root = infixNotation(Word("01wxyz"), [
|
||||||
|
# ('!', 1, opAssoc.RIGHT),
|
||||||
|
# (oneOf('< <= > >='), 2, opAssoc.LEFT),
|
||||||
|
# (oneOf('== !='), 2, opAssoc.LEFT),
|
||||||
|
# (oneOf('&& !& &!'), 2, opAssoc.LEFT),
|
||||||
|
# (oneOf('|| !| |!'), 2, opAssoc.LEFT)]);
|
||||||
|
#
|
||||||
|
# return root;
|
||||||
|
|
||||||
# this can't handle parenthesis very well...
|
def parse(text):
|
||||||
# do I really have to write my own parser?
|
class Tokenizer:
|
||||||
root = infix_notation(Word("01wxyz"), [
|
def __init__(self, text):
|
||||||
('!', 1, opAssoc.RIGHT),
|
self.position = 0;
|
||||||
(oneOf('< <= > >='), 2, opAssoc.LEFT),
|
self.text = text;
|
||||||
(oneOf('== !='), 2, opAssoc.LEFT),
|
self.tokenkind = None;
|
||||||
(oneOf('&& !& &!'), 2, opAssoc.LEFT),
|
self.tokendata = None;
|
||||||
(oneOf('|| !| |!'), 2, opAssoc.LEFT)]);
|
|
||||||
|
def next(self):
|
||||||
|
# skip whitespace:
|
||||||
|
while self.position < len(self.text) and self.text[self.position].isspace():
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
if self.position == len(self.text):
|
||||||
|
self.tokenkind = "EOF";
|
||||||
|
return;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "0" | "1":
|
||||||
|
self.tokenkind = "literal";
|
||||||
|
self.tokendata = self.text[self.position];
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
case "w" | "x" | "y" | "z":
|
||||||
|
self.tokenkind = "variable";
|
||||||
|
self.tokendata = self.text[self.position];
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
case "(" | ")":
|
||||||
|
self.tokenkind = self.text[self.position];
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
case ">":
|
||||||
|
# could be ">" or ">=":
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "=":
|
||||||
|
self.tokenkind = ">=";
|
||||||
|
self.position += 1;
|
||||||
|
case _:
|
||||||
|
self.tokenkind = ">"
|
||||||
|
|
||||||
|
case "<":
|
||||||
|
# could be "<" or "<=":
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "=":
|
||||||
|
self.tokenkind = "<=";
|
||||||
|
self.position += 1;
|
||||||
|
case _:
|
||||||
|
self.tokenkind = "<"
|
||||||
|
|
||||||
|
case "=":
|
||||||
|
# could only be "=="
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "=":
|
||||||
|
self.tokenkind = "==";
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
case _:
|
||||||
|
raise BaseException("expecting '=' after '='");
|
||||||
|
|
||||||
|
case "!":
|
||||||
|
# could be "!" or "!|" or "&!" or "!="
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "&":
|
||||||
|
self.tokenkind = "!&";
|
||||||
|
self.position += 1;
|
||||||
|
case "|":
|
||||||
|
self.tokenkind = "!|";
|
||||||
|
self.position += 1;
|
||||||
|
case "=":
|
||||||
|
self.tokenkind = "!=";
|
||||||
|
self.position += 1;
|
||||||
|
case _:
|
||||||
|
self.tokenkind = "!"
|
||||||
|
|
||||||
|
case "&":
|
||||||
|
# could be "&&" or "&!"
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "&":
|
||||||
|
self.tokenkind = "&&";
|
||||||
|
self.position += 1;
|
||||||
|
case "!":
|
||||||
|
self.tokenkind = "&!";
|
||||||
|
self.position += 1;
|
||||||
|
case _:
|
||||||
|
raise BaseException("expecting '&' or '!' after '&'");
|
||||||
|
|
||||||
|
case "|":
|
||||||
|
# could be "||" or "|!"
|
||||||
|
self.position += 1;
|
||||||
|
|
||||||
|
match self.text[self.position]:
|
||||||
|
case "|":
|
||||||
|
self.tokenkind = "||";
|
||||||
|
self.position += 1;
|
||||||
|
case "!":
|
||||||
|
self.tokenkind = "|!";
|
||||||
|
self.position += 1;
|
||||||
|
case _:
|
||||||
|
raise BaseException("expecting '|' or '!' after '|'");
|
||||||
|
|
||||||
|
case x:
|
||||||
|
raise BaseException(f'unknown token "{x}"!');
|
||||||
|
|
||||||
|
def parse_primary(tokenizer):
|
||||||
|
match tokenizer.tokenkind:
|
||||||
|
case "literal":
|
||||||
|
ast = ("literal", int(tokenizer.tokendata));
|
||||||
|
tokenizer.next();
|
||||||
|
|
||||||
|
case "variable":
|
||||||
|
ast = ("variable", tokenizer.tokendata);
|
||||||
|
tokenizer.next();
|
||||||
|
|
||||||
|
case "(":
|
||||||
|
tokenizer.next();
|
||||||
|
|
||||||
|
ast = parse_root(tokenizer);
|
||||||
|
|
||||||
|
if tokenizer.tokenkind != ")":
|
||||||
|
raise BaseException(f'expected token ")", found: {tokenizer.tokenkind}');
|
||||||
|
|
||||||
|
tokenizer.next();
|
||||||
|
|
||||||
|
case x:
|
||||||
|
raise BaseException(f'unexpected token "{x}"!');
|
||||||
|
|
||||||
|
return ast;
|
||||||
|
|
||||||
|
def parse_prefix(tokenizer):
|
||||||
|
if tokenizer.tokenkind == "!":
|
||||||
|
tokenizer.next();
|
||||||
|
return ("!", parse_prefix(tokenizer));
|
||||||
|
else:
|
||||||
|
return parse_primary(tokenizer);
|
||||||
|
|
||||||
|
def parse_compares(tokenizer):
|
||||||
|
left = parse_prefix(tokenizer);
|
||||||
|
|
||||||
|
while tokenizer.tokenkind in ("<=", "<", ">", ">="):
|
||||||
|
op = tokenizer.tokenkind;
|
||||||
|
tokenizer.next();
|
||||||
|
left = (op, left, parse_prefix(tokenizer));
|
||||||
|
|
||||||
|
return left;
|
||||||
|
|
||||||
|
def parse_equals(tokenizer):
|
||||||
|
left = parse_compares(tokenizer);
|
||||||
|
|
||||||
|
while tokenizer.tokenkind in ("==", "!="):
|
||||||
|
op = tokenizer.tokenkind;
|
||||||
|
tokenizer.next();
|
||||||
|
left = (op, left, parse_compares(tokenizer));
|
||||||
|
|
||||||
|
return left;
|
||||||
|
|
||||||
|
def parse_ands(tokenizer):
|
||||||
|
left = parse_equals(tokenizer);
|
||||||
|
|
||||||
|
while tokenizer.tokenkind in ("&&", "&!", "!&"):
|
||||||
|
op = tokenizer.tokenkind;
|
||||||
|
tokenizer.next();
|
||||||
|
left = (op, left, parse_equals(tokenizer));
|
||||||
|
|
||||||
|
return left;
|
||||||
|
|
||||||
|
def parse_ors(tokenizer):
|
||||||
|
left = parse_ands(tokenizer);
|
||||||
|
|
||||||
|
while tokenizer.tokenkind in ("||", "|!", "!|"):
|
||||||
|
op = tokenizer.tokenkind;
|
||||||
|
tokenizer.next();
|
||||||
|
left = (op, left, parse_ands(tokenizer));
|
||||||
|
|
||||||
|
return left;
|
||||||
|
|
||||||
|
def parse_root(tokenizer):
|
||||||
|
return parse_ors(tokenizer);
|
||||||
|
|
||||||
|
tokenizer = Tokenizer(text);
|
||||||
|
|
||||||
|
tokenizer.next();
|
||||||
|
|
||||||
|
root = parse_root(tokenizer);
|
||||||
|
|
||||||
|
if tokenizer.tokenkind != "EOF":
|
||||||
|
raise BaseException(
|
||||||
|
f"reached end of expression. "
|
||||||
|
f"Expecting EOF. found: {tokenizer.tokenkind}!");
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
|
|
||||||
def parse(parser, text):
|
|
||||||
return parser.parseString(text, parseAll = True).asList()[0]
|
|
||||||
|
|
||||||
def evaluate(expr):
|
def evaluate(expr):
|
||||||
match expr:
|
match expr:
|
||||||
case "0":
|
case ("literal", 0): return 0;
|
||||||
return 0;
|
case ("literal", 1): return M;
|
||||||
case "1":
|
|
||||||
return M;
|
case ("variable", "w"): return W;
|
||||||
case "w":
|
case ("variable", "x"): return X;
|
||||||
return W;
|
case ("variable", "y"): return Y;
|
||||||
case "x":
|
case ("variable", "z"): return Z;
|
||||||
return X;
|
|
||||||
case "y":
|
case ("!", inner):
|
||||||
return Y;
|
return ~evaluate(inner) & M;
|
||||||
case "z":
|
|
||||||
return Z;
|
case ("<", left, right):
|
||||||
case ("!", subexp):
|
return (~evaluate(left) & evaluate(right)) & M;
|
||||||
return ~evaluate(subexp) & M;
|
case ("<=", left, right):
|
||||||
case (first, "||", *rest):
|
return (~evaluate(left) | evaluate(right)) & M;
|
||||||
result = evaluate(first);
|
case (">=", left, right):
|
||||||
for subexpr in rest[::2]: result = result | evaluate(subexpr);
|
return ( evaluate(left) | ~evaluate(right)) & M;
|
||||||
return result;
|
case (">", left, right):
|
||||||
case (first, "!|", *rest):
|
return ( evaluate(left) & ~evaluate(right)) & M;
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = ~(result | evaluate(subexpr)) & M;
|
case ("!=", left, right):
|
||||||
return result;
|
return (evaluate(left) ^ evaluate(right)) & M;
|
||||||
case (first, "|!", *rest):
|
case ("==", left, right):
|
||||||
result = evaluate(first);
|
return ~(evaluate(left) ^ evaluate(right)) & M;
|
||||||
for subexpr in rest[::2]: result = (~result | evaluate(subexpr)) & M;
|
|
||||||
return result;
|
case ("||", left, right):
|
||||||
case (first, "&&", *rest):
|
return evaluate(left) | evaluate(right);
|
||||||
result = evaluate(first);
|
case ("|!", left, right):
|
||||||
for subexpr in rest[::2]: result = result & evaluate(subexpr);
|
return (~evaluate(left) | evaluate(right)) & M;
|
||||||
return result;
|
case ("!|", left, right):
|
||||||
case (first, "!&", *rest):
|
return ~(evaluate(left) | evaluate(right)) & M;
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = ~(result & evaluate(subexpr)) & M;
|
case ("&&", left, right):
|
||||||
return result;
|
return evaluate(left) & evaluate(right);
|
||||||
case (first, "&!", *rest):
|
case ("&!", left, right):
|
||||||
result = evaluate(first);
|
return (~evaluate(left) & evaluate(right)) & M;
|
||||||
for subexpr in rest[::2]: result = (~result & evaluate(subexpr)) & M;
|
case ("!&", left, right):
|
||||||
return result;
|
return ~(evaluate(left) & evaluate(right)) & M;
|
||||||
case (first, "<", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = (~result & evaluate(subexpr)) & M;
|
|
||||||
return result;
|
|
||||||
case (first, "<=", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = (~result | evaluate(subexpr)) & M;
|
|
||||||
return result;
|
|
||||||
case (first, ">", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = (result & ~evaluate(subexpr)) & M;
|
|
||||||
return result;
|
|
||||||
case (first, ">=", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = (result | ~evaluate(subexpr)) & M;
|
|
||||||
return result;
|
|
||||||
case (first, "!=", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = (result ^ evaluate(subexpr)) & M
|
|
||||||
return result;
|
|
||||||
case (first, "==", *rest):
|
|
||||||
result = evaluate(first);
|
|
||||||
for subexpr in rest[::2]: result = ~(result ^ evaluate(subexpr)) & M
|
|
||||||
return result;
|
|
||||||
case _:
|
case _:
|
||||||
print(expr);
|
print(f'expr = {expr}');
|
||||||
assert(not "TODO");
|
assert(not "TODO");
|
||||||
|
|
||||||
def repl(args, cost, lookup):
|
def repl(args, cost, lookup):
|
||||||
import readline;
|
import readline;
|
||||||
print("Give a boolean expression using the variables 'w', 'x', 'y' and 'z'.");
|
print("Give a boolean expression using the variables 'w', 'x', 'y' and 'z'.");
|
||||||
print("Operations: not ('!'), or ('||'), and ('&&').""");
|
print("Operators: not ('!'), or ('||'), and ('&&').");
|
||||||
|
|
||||||
|
print();
|
||||||
|
|
||||||
|
print("The py-parser struggles with deeply-nested parentheses.");
|
||||||
|
print("I may have to just write my recursive-descent parser.");
|
||||||
|
|
||||||
print();
|
print();
|
||||||
|
|
||||||
if args.extended_operators:
|
if args.extended_operators:
|
||||||
print("Extended operations: nor ('!|'), orn ('|!'), nand ('!&'), ");
|
print("Extended operators: nor ('!|'), orn ('|!'), nand ('!&'), ");
|
||||||
print("andn ('&!'), xor ('!='), and nxor ('==')");
|
print("andn ('&!'), xor ('!='), and nxor ('==')");
|
||||||
|
|
||||||
print();
|
print();
|
||||||
|
|
||||||
print(f'I can do anything in {max(cost.values())} operations.')
|
print(f'I can simplify any tree down to {max(cost.values())} operators or less.')
|
||||||
print();
|
print();
|
||||||
|
|
||||||
parser = create_parser();
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
line = input(">>> ");
|
line = input(">>> ");
|
||||||
|
|
@ -487,10 +643,24 @@ def repl(args, cost, lookup):
|
||||||
|
|
||||||
if not line: continue;
|
if not line: continue;
|
||||||
|
|
||||||
truthtable = evaluate(parse(parser, line));
|
try:
|
||||||
|
parsed = parse(line);
|
||||||
|
except BaseException as e:
|
||||||
|
print(f"syntax error: {e}");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
truthtable = evaluate(parsed);
|
||||||
|
|
||||||
if truthtable in lookup:
|
if truthtable in lookup:
|
||||||
print(f'{cost[truthtable]}: {pretty(lookup[truthtable])}')
|
text = "";
|
||||||
|
|
||||||
|
c = cost[truthtable];
|
||||||
|
|
||||||
|
LITERAL_ESCAPE = "\033[38;2;200;200;100m";
|
||||||
|
|
||||||
|
print(f'{cost[truthtable]}: {pretty(lookup[truthtable], args.color)}')
|
||||||
|
|
||||||
|
print(text);
|
||||||
else:
|
else:
|
||||||
print('unreachable.')
|
print('unreachable.')
|
||||||
|
|
||||||
|
|
@ -506,12 +676,18 @@ def main(args):
|
||||||
|
|
||||||
if args.printout:
|
if args.printout:
|
||||||
for truthtable, exp in sorted(lookup.items()):
|
for truthtable, exp in sorted(lookup.items()):
|
||||||
print(f'{truthtable:016b}: {pretty(exp)}');
|
print(f'{truthtable:016b}: {pretty(exp, args.color)}');
|
||||||
elif args.command:
|
elif args.command:
|
||||||
truthtable = evaluate(parse(create_parser(), args.command));
|
try:
|
||||||
|
parsed = parse(args.command);
|
||||||
|
except BaseException as e:
|
||||||
|
print(f"syntax error: {e}");
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
truthtable = evaluate(parsed);
|
||||||
|
|
||||||
if truthtable in lookup:
|
if truthtable in lookup:
|
||||||
print(pretty(lookup[truthtable]));
|
print(pretty(lookup[truthtable], args.color));
|
||||||
else:
|
else:
|
||||||
print('unreachable.')
|
print('unreachable.')
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue