Parser will no longer combine ADD/SUB/MUL nodes to n-ary nodes.

parent 4c003ee2
......@@ -20,21 +20,22 @@ from pybison import BisonParser, BisonSyntaxError
from graph_drawing.graph import generate_graph
from node import TYPE_OPERATOR, OP_ADD, OP_MUL, OP_SUB
from rules import RULES
# Check for n-ary operator in child nodes
def combine(op, op_type, *nodes):
# At least return the operator.
res = [op]
for n in nodes:
# Merge the children for all nodes which have the same operator.
if n.type == TYPE_OPERATOR and n.op == op_type:
res += n.nodes
else:
res.append(n)
return res
## Check for n-ary operator in child nodes
#def combine(op, op_type, *nodes):
# # At least return the operator.
# res = [op]
#
# for n in nodes:
# # Merge the children for all nodes which have the same operator.
# if n.type == TYPE_OPERATOR and n.op == op_type:
# res += n.nodes
# else:
# res.append(n)
#
# return res
class Parser(BisonParser):
......@@ -72,6 +73,7 @@ class Parser(BisonParser):
BisonParser.__init__(self, **kwargs)
self.interactive = kwargs.get('interactive', 0)
self.timeout = kwargs.get('timeout', 0)
self.possibilities = []
# ------------------------------------------------------------------
# override default read method with a version that prompts for input
......@@ -144,6 +146,15 @@ class Parser(BisonParser):
return data
def hook_handler(self, target, option, names, values, retval):
if not retval or retval.type not in RULES:
return retval
for handler in RULES[retval.type]:
self.possibilities.extend(handler(retval))
return retval
# ---------------------------------------------------------------
# These methods are the python handlers for the bison targets.
# (which get called by the bison code each time the corresponding
......@@ -247,20 +258,8 @@ class Parser(BisonParser):
| exp POW exp
"""
if option == 0: # rule: exp PLUS exp
return Node(*(combine('+', OP_ADD, values[0], values[2])))
if option == 1: # rule: exp MINUS exp
return Node(*(combine('-', OP_SUB, values[0], values[2])))
if option == 2: # rule: exp TIMES exp
return Node(*(combine('*', OP_MUL, values[0], values[2])))
if option == 3: # rule: exp DIVIDE exp
return Node('/', values[0], values[2])
if option == 4: # rule: exp POW exp
return Node('^', values[0], values[2])
if 0 <= option < 5: # rule: exp PLUS exp
return Node(values[1], values[0], values[2])
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
......
from ..node import ExpressionNode as Node, OP_ADD
from .poly import match_combine_factors#, match_combine_parentheses
RULES = {
OP_ADD: [match_combine_factors],
#OP_MUL: [match_combine_parentheses],
}
from itertools import combinations
from node import ExpressionNode as Node, ExpressionLeaf as Leaf
from possibilities import Possibility as P
from ..node import ExpressionLeaf as Leaf, TYPE_OPERATOR
from ..possibilities import Possibility as P
def match_combine_factors(node):
"""
n + exp + m -> exp + (n + m)
k0 * v ^ n + exp + k1 * v ^ n -> exp + (k0 + k1) * v ^ n
"""
if node.type != TYPE_OPERATOR:
return []
p = []
if node.is_nary():
......@@ -59,7 +61,7 @@ def combine_numerics(root, args):
Combine two numeric leaves in an n-ary plus.
Example:
3 + 4 -> 7
>>> 3 + 4 -> 7
"""
numerics, others = args
value = sum([n.value for n in numerics])
......@@ -94,17 +96,3 @@ def combine_orders(root, args):
combined = Node('*', Leaf(coeff), ident)
return nary_node('+', others + [combined])
def nary_node(operator, scope):
"""
Create a binary expression tree for an n-ary operator. Takes the operator
and a list of expression nodes as arguments.
"""
return scope[0] if len(scope) == 1 \
else Node(operator, nary_node(operator, scope[:-1]), scope[-1])
rules = {
'+': [match_combine_factors],
}
from ..node import ExpressionNode as Node
def nary_node(operator, scope):
"""
Create a binary expression tree for an n-ary operator. Takes the operator
and a list of expression nodes as arguments.
"""
return scope[0] if len(scope) == 1 \
else Node(operator, nary_node(operator, scope[:-1]), scope[-1])
......@@ -15,7 +15,8 @@ class TestB1Ch8(unittest.TestCase):
('-5*(-3)^2', N('*', N('-', L(5)),
N('^', N('-', L(3)), L(2)))),
('7p-3p', N('-', N('*', L(7), L('p')), N('*', L(3), L('p')))),
('-5a*-6', N('*', N('-', L(5)), L('a'), N('-', L(6)))),
('3a-8--5-2a', N('-', N('*', L(3), L('a')), L(8),
N('-', L(5)), N('*', L(2), L('a')))),
('-5a*-6', N('*', N('*', N('-', L(5)), L('a')),
N('-', L(6)))),
('3a-8--5-2a', N('-', N('-', N('-', N('*', L(3), L('a')), L(8)),
N('-', L(5))), N('*', L(2), L('a')))),
])
......@@ -51,12 +51,13 @@ class TestCalc(unittest.TestCase):
N('+', L('c'), L('d')))),
('a+b(c+d)', N('+', L('a'), N('*', L('b'),
N('+', L('c'), L('d'))))),
('abcd', N('*', L('a'), L('b'), L('c'), L('d'))),
('ab(c)d', N('*', L('a'), L('b'), L('c'), L('d'))),
#('ab(c)d', N('*', L('a'), N('*', L('b'),
# N('*', L('c'), L('d'))))),
('ab*(c)*d', N('*', L('a'), L('b'), L('c'), L('d'))),
('ab*(c)^d', N('*', L('a'), L('b'),
('abcd', N('*', N('*', N('*', L('a'), L('b')),
L('c')), L('d'))),
('ab(c)d', N('*', N('*', N('*', L('a'), L('b')),
L('c')), L('d'))),
('ab*(c)*d', N('*', N('*', N('*', L('a'), L('b')),
L('c')), L('d'))),
('ab*(c)^d', N('*', N('*', L('a'), L('b')),
N('^', L('c'), L('d')))),
]
......
import unittest
from src.node import ExpressionNode as N, ExpressionLeaf as L
from src.rules import match_combine_factors, combine_numerics, \
combine_orders, nary_node
from src.rules.poly import match_combine_factors, combine_numerics, \
combine_orders
from src.rules.utils import nary_node
from src.possibilities import Possibility as P
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment