Solved preprocessor inserting multiplication signs in keywords.

parent 3d713049
......@@ -141,6 +141,10 @@ class Parser(BisonParser):
import re
# Replace known keywords with escape sequences.
for i, keyword in enumerate(Parser.words):
data = re.sub(keyword, chr(i), data, flags=re.I)
# TODO: remove this quick preprocessing hack. This hack enables
# concatenated expressions, since the grammar currently does not
# support those. This workaround will replace:
......@@ -151,20 +155,24 @@ class Parser(BisonParser):
# - "4a" with "4*a".
# - "a4" with "a^4".
pattern = ('(?:(\))\s*(\()' # match: )( result: ) * (
+ '|([a-z0-9])\s*(\()' # match: a( result: a * (
+ '|(\))\s*([a-z0-9])' # match: )a result: ) * a
+ '|([a-z])\s*([a-z]+)' # match: ab result: a * b
+ '|([0-9])\s*([a-z])' # match: 4a result: 4 * a
+ '|([a-z])\s*([0-9])' # match: a4 result: a ^ 4
+ '|([0-9])\s+([0-9]))') # match: 4 4 result: 4 * 4
pattern = ('(?:(\))\s*(\()' # )( -> ) * (
+ '|([\x00-\x09\x0b-\x19a-z0-9])\s*(\()' # a( -> a * (
+ '|(\))\s*([\x00-\x09\x0b-\x19a-z0-9])' # )a -> ) * a
+ '|([\x00-\x09\x0b-\x19a-z])\s*'
+'([\x00-\x09\x0b-\x19a-z]+)' # ab -> a * b
+ '|([0-9])\s*([\x00-\x09\x0b-\x19a-z])' # 4a -> 4 * a
+ '|([\x00-\x09\x0b-\x19a-z])\s*([0-9])' # a4 -> a ^ 4
+ '|([0-9])\s+([0-9]))' # 4 4 -> 4 * 4
)
def preprocess_data(match):
left, right = filter(None, match.groups())
# Filter words (otherwise they will be preprocessed as well)
if left + right in Parser.words:
return left + right
# Make sure there are no multiplication and exponentiation signs
# inserted between a function and its argument(s): "sin x" should
# not be written as "sin*x", because that is bogus.
if ord(left) <= 0x9 or 0x0b <= ord(left) <= 0x19:
return left + ' ' + right
# If all characters on the right are numbers. e.g. "a4", the
# expression implies exponentiation. Make sure ")4" is not
......@@ -180,18 +188,20 @@ class Parser(BisonParser):
data_before = data
# Iteratively replace all matches.
while True:
data_after = re.sub(pattern, preprocess_data, data)
i = 0
if data == data_after:
break
while i < len(data):
data = data[:i] + re.sub(pattern, preprocess_data, data[i:])
i += 1
data = data_after
# Replace escape sequences with original keywords.
for i, keyword in enumerate(Parser.words):
data = data.replace(chr(i), keyword)
if self.verbose and data_before != data_after: # pragma: nocover
if self.verbose and data_before != data: # pragma: nocover
print 'hook_read_after() modified the input data:'
print 'before:', repr(data_before)
print 'after :', repr(data_after)
print 'after :', repr(data)
return data
......
......@@ -50,7 +50,8 @@ class TestParser(unittest.TestCase):
root, x = tree('sin x, x')
self.assertEqual(root, sin(x))
self.assertEqual(tree('sin x ^ 2'), sin(x) ** 2)
#FIXME: self.assertEqual(tree('sin x ^ 2'), sin(x ** 2))
self.assertEqual(tree('sin 2 x'), sin(2) * x)
self.assertEqual(tree('sin(x) ^ 2'), sin(x) ** 2)
self.assertEqual(tree('sin (x) ^ 2'), sin(x) ** 2)
self.assertEqual(tree('sin(x ^ 2)'), sin(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