Commit 17c6fae8 authored by Taddeus Kroes's avatar Taddeus Kroes

Added logical operators.

parent 685f3ea3
......@@ -28,34 +28,36 @@ OP_MUL = 5
OP_DIV = 6
OP_POW = 7
OP_SUBSCRIPT = 8
OP_AND = 9
OP_OR = 10
# N-ary (functions)
OP_INT = 9
OP_INT_INDEF = 10
OP_COMMA = 11
OP_SQRT = 12
OP_DER = 13
OP_LOG = 14
OP_INT = 11
OP_INT_INDEF = 12
OP_COMMA = 13
OP_SQRT = 14
OP_DER = 15
OP_LOG = 16
# Goniometry
OP_SIN = 15
OP_COS = 16
OP_TAN = 17
OP_SIN = 17
OP_COS = 18
OP_TAN = 19
OP_SOLVE = 18
OP_EQ = 19
OP_SOLVE = 20
OP_EQ = 21
OP_POSSIBILITIES = 20
OP_HINT = 21
OP_REWRITE_ALL = 22
OP_REWRITE = 23
OP_POSSIBILITIES = 22
OP_HINT = 23
OP_REWRITE_ALL = 24
OP_REWRITE = 25
# Special identifiers
PI = 'pi'
E = 'e'
INFINITY = 'oo'
SPECIAL_TOKENS = [PI, INFINITY]
SPECIAL_TOKENS = [PI, E, INFINITY]
# Default base to use in parsing 'log(...)'
DEFAULT_LOGARITHM_BASE = 10
......@@ -75,6 +77,8 @@ OP_MAP = {
'/': OP_DIV,
'^': OP_POW,
'_': OP_SUBSCRIPT,
'^^': OP_AND,
'vv': OP_OR,
'sin': OP_SIN,
'cos': OP_COS,
'tan': OP_TAN,
......@@ -103,6 +107,8 @@ TOKEN_MAP = {
OP_DIV: 'DIVIDE',
OP_POW: 'POW',
OP_SUBSCRIPT: 'SUB',
OP_AND: 'AND',
OP_OR: 'OR',
OP_SQRT: 'FUNCTION',
OP_SIN: 'FUNCTION',
OP_COS: 'FUNCTION',
......@@ -226,6 +232,12 @@ class ExpressionBase(object):
def __pos__(self):
return self.reduce_negation()
def __and__(self, other):
return ExpressionNode(OP_AND, self, to_expression(other))
def __or__(self, other):
return ExpressionNode(OP_OR, self, to_expression(other))
def reduce_negation(self, n=1):
"""Remove n negation flags from the node."""
assert self.negated
......
......@@ -87,10 +87,12 @@ class Parser(BisonParser):
precedences = (
('left', ('COMMA', )),
('right', ('INTEGRAL', 'DERIVATIVE')),
('left', ('OR', )),
('left', ('AND', )),
('left', ('EQ', )),
('left', ('MINUS', 'PLUS')),
('left', ('TIMES', 'DIVIDE')),
('right', ('FUNCTION', )),
('left', ('EQ', )),
('left', ('NEG', )),
('right', ('POW', )),
('left', ('SUB', )),
......@@ -225,6 +227,9 @@ class Parser(BisonParser):
for i, keyword in enumerate(words):
data = data.replace(chr(i), keyword)
# Fix TIMES operator next to OR
data = re.sub(r'\*?vv\*?', 'vv', data)
if self.verbose and data_before != data: # pragma: nocover
print 'hook_read_after() modified the input data:'
print 'before:', repr(data_before)
......@@ -527,14 +532,16 @@ class Parser(BisonParser):
| exp TIMES exp
| exp DIVIDE exp
| exp EQ exp
| exp AND exp
| exp OR exp
| exp MINUS exp
| power
"""
if 0 <= option < 4: # rule: exp {PLUS,TIMES,DIVIDE,EQ} exp
if 0 <= option <= 5: # rule: exp {PLUS,TIMES,DIVIDE,EQ,AND,OR} exp
return Node(values[1], values[0], values[2])
if option == 4: # rule: exp MINUS exp
if option == 6: # rule: exp MINUS exp
node = values[2]
# Add negation to the left-most child
......@@ -549,7 +556,7 @@ class Parser(BisonParser):
return Node(OP_ADD, values[0], values[2])
if option == 5: # rule: power
if option == 7: # rule: power
return Node(OP_POW, *values[0])
raise BisonSyntaxError('Unsupported option %d in target "%s".'
......@@ -573,8 +580,9 @@ class Parser(BisonParser):
functions = []
for token in SPECIAL_TOKENS:
operators += '"%s"%s{ returntoken(IDENTIFIER); }\n' \
% (token, ' ' * (8 - len(token)))
if len(token) > 1:
operators += '"%s"%s{ returntoken(IDENTIFIER); }\n' \
% (token, ' ' * (8 - len(token)))
for op_str, op in OP_MAP.iteritems():
if TOKEN_MAP[op] == 'FUNCTION':
......
......@@ -38,6 +38,14 @@ class TestParser(unittest.TestCase):
self.assertNotEqual(possibilities1, possibilities2)
def test_binary(self):
a, b, c = tree('a, b, c')
self.assertEqual(tree('a ^^ b'), a & b)
self.assertEqual(tree('a vv b'), a | b)
self.assertEqual(tree('a vv b vv c'), (a | b) | c)
self.assertEqual(tree('a vv b ^^ c'), a | (b & c))
def test_preprocessor(self):
self.assertEqual(tree('ab'), tree('a * b'))
self.assertEqual(tree('abc'), tree('a * b * c'))
......
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