Commit 196a602c authored by Taddeus Kroes's avatar Taddeus Kroes

Added notation for absolute value to the parser.

parent 1952f7ba
...@@ -21,35 +21,36 @@ TYPE_FLOAT = 8 ...@@ -21,35 +21,36 @@ TYPE_FLOAT = 8
# Unary # Unary
OP_NEG = 1 OP_NEG = 1
OP_ABS = 2
# Binary # Binary
OP_ADD = 2 OP_ADD = 3
OP_SUB = 3 OP_SUB = 4
OP_MUL = 4 OP_MUL = 5
OP_DIV = 5 OP_DIV = 6
OP_POW = 6 OP_POW = 7
OP_SUBSCRIPT = 7 OP_SUBSCRIPT = 8
# N-ary (functions) # N-ary (functions)
OP_INT = 8 OP_INT = 9
OP_INT_INDEF = 9 OP_INT_INDEF = 10
OP_COMMA = 10 OP_COMMA = 11
OP_SQRT = 11 OP_SQRT = 12
OP_DER = 12 OP_DER = 13
OP_LOG = 13 OP_LOG = 14
# Goniometry # Goniometry
OP_SIN = 14 OP_SIN = 15
OP_COS = 15 OP_COS = 16
OP_TAN = 16 OP_TAN = 17
OP_SOLVE = 17 OP_SOLVE = 18
OP_EQ = 18 OP_EQ = 19
OP_POSSIBILITIES = 19 OP_POSSIBILITIES = 20
OP_HINT = 20 OP_HINT = 21
OP_REWRITE_ALL = 21 OP_REWRITE_ALL = 22
OP_REWRITE = 22 OP_REWRITE = 23
# Special identifiers # Special identifiers
PI = 'pi' PI = 'pi'
...@@ -94,6 +95,7 @@ OP_MAP = { ...@@ -94,6 +95,7 @@ OP_MAP = {
OP_VALUE_MAP = dict([(v, k) for k, v in OP_MAP.iteritems()]) OP_VALUE_MAP = dict([(v, k) for k, v in OP_MAP.iteritems()])
OP_MAP['ln'] = OP_LOG OP_MAP['ln'] = OP_LOG
OP_VALUE_MAP[OP_INT_INDEF] = 'indef' OP_VALUE_MAP[OP_INT_INDEF] = 'indef'
OP_VALUE_MAP[OP_ABS] = 'abs'
TOKEN_MAP = { TOKEN_MAP = {
OP_COMMA: 'COMMA', OP_COMMA: 'COMMA',
...@@ -319,6 +321,9 @@ class ExpressionNode(Node, ExpressionBase): ...@@ -319,6 +321,9 @@ class ExpressionNode(Node, ExpressionBase):
return '[%s]%s%s' % (F, lbnd, ubnd) return '[%s]%s%s' % (F, lbnd, ubnd)
if self.op == OP_ABS:
return '|%s|' % children[0]
def __str__(self): # pragma: nocover def __str__(self): # pragma: nocover
return generate_line(self) return generate_line(self)
......
...@@ -18,7 +18,7 @@ from node import ExpressionBase, ExpressionNode as Node, \ ...@@ -18,7 +18,7 @@ from node import ExpressionBase, ExpressionNode as Node, \
ExpressionLeaf as Leaf, OP_MAP, OP_DER, TOKEN_MAP, TYPE_OPERATOR, \ ExpressionLeaf as Leaf, OP_MAP, OP_DER, TOKEN_MAP, TYPE_OPERATOR, \
OP_COMMA, OP_NEG, OP_MUL, OP_DIV, OP_POW, OP_LOG, OP_ADD, Scope, E, \ OP_COMMA, OP_NEG, OP_MUL, OP_DIV, OP_POW, OP_LOG, OP_ADD, Scope, E, \
DEFAULT_LOGARITHM_BASE, OP_VALUE_MAP, SPECIAL_TOKENS, OP_INT, \ DEFAULT_LOGARITHM_BASE, OP_VALUE_MAP, SPECIAL_TOKENS, OP_INT, \
OP_INT_INDEF OP_INT_INDEF, OP_ABS
from rules import RULES from rules import RULES
from rules.utils import find_variable from rules.utils import find_variable
from strategy import pick_suggestion from strategy import pick_suggestion
...@@ -78,7 +78,7 @@ class Parser(BisonParser): ...@@ -78,7 +78,7 @@ class Parser(BisonParser):
# of tokens of the lex script. # of tokens of the lex script.
tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH', tokens = ['NUMBER', 'IDENTIFIER', 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH',
'LPAREN', 'RPAREN', 'FUNCTION', 'FUNCTION_LPAREN', 'LBRACKET', 'LPAREN', 'RPAREN', 'FUNCTION', 'FUNCTION_LPAREN', 'LBRACKET',
'RBRACKET', 'PRIME', 'DERIVATIVE'] \ 'RBRACKET', 'PIPE', 'PRIME', 'DERIVATIVE'] \
+ filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values()) + filter(lambda t: t != 'FUNCTION', TOKEN_MAP.values())
# ------------------------------ # ------------------------------
...@@ -180,16 +180,16 @@ class Parser(BisonParser): ...@@ -180,16 +180,16 @@ class Parser(BisonParser):
# - "4a" with "4*a". # - "4a" with "4*a".
# - "a4" with "a^4". # - "a4" with "a^4".
pattern = ('(?:(\))\s*(\(|\[)' # )( -> ) * ( pattern = ('(?:(\))\s*([([])' # )( -> ) * (
# )[ -> ) * [ # )[ -> ) * [
+ '|([\x00-\x09\x0b-\x19a-z0-9])\s*(\(|\[)' # a( -> a * ( + '|([\x00-\x09\x0b-\x19a-z0-9])\s*([([])' # a( -> a * (
# a[ -> a * [ # a[ -> a * [
+ '|(\))\s*([\x00-\x09\x0b-\x19a-z0-9])' # )a -> ) * a + '|(\))\s*([\x00-\x09\x0b-\x19a-z0-9])' # )a -> ) * a
+ '|([\x00-\x09\x0b-\x19a-z])\s*' + '|([\x00-\x09\x0b-\x19a-z])\s*'
+ '([\x00-\x09\x0b-\x19a-z])' # ab -> a * b + '([\x00-\x09\x0b-\x19a-z])' # ab -> a * b
+ '|([0-9])\s*([\x00-\x09\x0b-\x19a-z])' # 4a -> 4 * a + '|([0-9])\s*([\x00-\x09\x0b-\x19a-z])' # 4a -> 4 * a
+ '|([\x00-\x09\x0b-\x19a-z])([0-9])' # a4 -> a ^ 4 + '|([\x00-\x09\x0b-\x19a-z])([0-9])' # a4 -> a ^ 4
+ '|([\x00-\x09\x0b-\x19a-z0-9])(\s+[0-9]))' # a 4 -> a * 4, + '|([\x00-\x09\x0b-\x19a-z0-9])(\s+[0-9]))' # a 4 -> a * 4
# 4 4 -> 4 * 4 # 4 4 -> 4 * 4
) )
...@@ -399,6 +399,7 @@ class Parser(BisonParser): ...@@ -399,6 +399,7 @@ class Parser(BisonParser):
| INTEGRAL exp | INTEGRAL exp
| integral_bounds TIMES exp %prec INTEGRAL | integral_bounds TIMES exp %prec INTEGRAL
| LBRACKET exp RBRACKET lbnd ubnd | LBRACKET exp RBRACKET lbnd ubnd
| PIPE exp PIPE
""" """
if option == 0: # rule: NEG exp if option == 0: # rule: NEG exp
...@@ -464,6 +465,9 @@ class Parser(BisonParser): ...@@ -464,6 +465,9 @@ class Parser(BisonParser):
if option == 7: # rule: LBRACKET exp RBRACKET lbnd ubnd if option == 7: # rule: LBRACKET exp RBRACKET lbnd ubnd
return Node(OP_INT_INDEF, values[1], values[3], values[4]) return Node(OP_INT_INDEF, values[1], values[3], values[4])
if option == 8: # rule: PIPE exp PIPE
return Node(OP_ABS, values[1])
raise BisonSyntaxError('Unsupported option %d in target "%s".' raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover % (option, target)) # pragma: nocover
...@@ -633,6 +637,7 @@ class Parser(BisonParser): ...@@ -633,6 +637,7 @@ class Parser(BisonParser):
"[" { returntoken(LBRACKET); } "[" { returntoken(LBRACKET); }
"]" { returntoken(RBRACKET); } "]" { returntoken(RBRACKET); }
"'" { returntoken(PRIME); } "'" { returntoken(PRIME); }
"|" { returntoken(PIPE); }
log_([0-9]+|[a-zA-Z])"*(" { returntoken(FUNCTION_LPAREN); } log_([0-9]+|[a-zA-Z])"*(" { returntoken(FUNCTION_LPAREN); }
log_([0-9]+|[a-zA-Z])"*" { returntoken(FUNCTION); } log_([0-9]+|[a-zA-Z])"*" { returntoken(FUNCTION); }
""" + operators + r""" """ + operators + r"""
......
from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_MUL, OP_DIV, \ from ..node import ExpressionNode as N, ExpressionLeaf as L, OP_MUL, OP_DIV, \
INFINITY INFINITY, OP_ABS
def greatest_common_divisor(a, b): def greatest_common_divisor(a, b):
...@@ -133,3 +133,10 @@ def infinity(): ...@@ -133,3 +133,10 @@ def infinity():
Return an infinity leaf node. Return an infinity leaf node.
""" """
return L(INFINITY) return L(INFINITY)
def absolute(exp):
"""
Put an 'absolute value' operator on top of the given expression.
"""
return N(OP_ABS, exp)
...@@ -10,6 +10,7 @@ from src.rules.goniometry import sin, cos ...@@ -10,6 +10,7 @@ from src.rules.goniometry import sin, cos
from src.rules.derivatives import der from src.rules.derivatives import der
from src.rules.logarithmic import log, ln from src.rules.logarithmic import log, ln
from src.rules.integrals import integral, indef from src.rules.integrals import integral, indef
from src.rules.utils import absolute
class TestParser(unittest.TestCase): class TestParser(unittest.TestCase):
...@@ -51,6 +52,14 @@ class TestParser(unittest.TestCase): ...@@ -51,6 +52,14 @@ class TestParser(unittest.TestCase):
self.assertEqual(tree('2(a + b)'), tree('2 * (a + b)')) self.assertEqual(tree('2(a + b)'), tree('2 * (a + b)'))
self.assertEqual(tree('(a + b)2'), tree('(a + b) * 2')) self.assertEqual(tree('(a + b)2'), tree('(a + b) * 2'))
self.assertEqual(tree('(a)(b)'), tree('(a) * (b)'))
self.assertEqual(tree('(a)[b]\''), tree('(a) * [b]\''))
# FIXME: self.assertEqual(tree('(a)|b|'), tree('(a) * |b|'))
# FIXME: self.assertEqual(tree('|a|(b)'), tree('|a| * (b)'))
# FIXME: self.assertEqual(tree('a|b|'), tree('a * |b|'))
# FIXME: self.assertEqual(tree('|a|b'), tree('|a| * b'))
def test_moved_negation(self): def test_moved_negation(self):
a, b = tree('a,b') a, b = tree('a,b')
...@@ -128,3 +137,9 @@ class TestParser(unittest.TestCase): ...@@ -128,3 +137,9 @@ class TestParser(unittest.TestCase):
x2, a, b = tree('x ^ 2, a, b') x2, a, b = tree('x ^ 2, a, b')
self.assertEqual(tree('[x ^ 2]_a^b'), indef(x2, a, b)) self.assertEqual(tree('[x ^ 2]_a^b'), indef(x2, a, b))
def test_absolute_value(self):
x = tree('x')
self.assertEqual(tree('|x|'), absolute(x))
self.assertEqual(tree('|x2|'), absolute(x ** 2))
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