Implemented expression preprocessor and 'graph' statement.

parent 24f62cbb
graph_drawing @ 003a9e25
Subproject commit 4d65a52b8ba0f0ad1843cb5535a485ff372317a3
Subproject commit 003a9e2536ed7d899b570f07d7d6a0ce60c5f155
pybison @ eb1d1da4
Subproject commit 2ae8c15dba13faba38e1a3d1a711cf6d24395a5a
Subproject commit eb1d1da4c21cc3f48cabe19485381e3f7e80f279
......@@ -39,8 +39,8 @@ class Parser(BisonParser):
# of tokens of the lex script.
tokens = ['NUMBER', 'IDENTIFIER',
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
'LPAREN', 'RPAREN', 'COMMA', 'CONCAT_POW',
'NEWLINE', 'QUIT', 'RAISE']
'LPAREN', 'RPAREN', 'COMMA', #'CONCAT_POW',
'NEWLINE', 'QUIT', 'RAISE', 'GRAPH']
# ------------------------------
# precedences
......@@ -71,6 +71,64 @@ class Parser(BisonParser):
except EOFError:
return ''
def hook_read(self, data):
"""
This hook will be called when the read() method returned. The data
argument points to the data read by the read() method. This hook
function should return the data to be used by the parser.
"""
import re
# TODO: remove this quick preprocesing hack. This hack enabled
# concatenated expressions, since the grammar currently does not
# support those. This workaround will replace:
# - ")(" with ")*(".
# - "a(" with "a*(".
# - ")a" with ")*a".
# - "ab" with "a*b".
# - "4a" with "4*a".
# - "a4" with "a^4".
pattern = ('(?:(\))\s*(\()' # match: )(
+ '|([a-z0-9])\s*(\()' # match: a(
+ '|(\))\s*([a-z0-9])' # match: )a
+ '|([a-z])\s*([a-z]+)' # match: ab
+ '|([0-9])\s*([a-z])' # match: 4a
+ '|([a-z])\s*([0-9]))') # match: a4
def preprocess_data(match):
left, right = filter(None, match.groups())
# Filter words (otherwise they will be preprocessed as well)
if left + right in ['graph', 'raise']:
return left + right
# If all characters on the right are numbers. e.g. "a4", the
# expression implies exponentiation. Make sure ")4" is not
# converted into an exponentiation, because that's multipliciation.
if left != ')' \
and all(map(lambda x: 48 <= ord(x) < 58, list(right))):
return '%s^%s' % (left, right)
# match: ab | abc | abcd (where left = "a")
return '*'.join([left] + list(right))
# Iteratively replace all matches.
while True:
data_after = re.sub(pattern, preprocess_data, data)
if data == data_after:
break
if self.verbose:
print 'hook_read() modified the input data:'
print 'before:', data.replace('\n', '\\n')
print 'after :', data_after.replace('\n', '\\n')
data = data_after
return data
# ---------------------------------------------------------------
# These methods are the python handlers for the bison targets.
# (which get called by the bison code each time the corresponding
......@@ -103,14 +161,27 @@ class Parser(BisonParser):
"""
line : NEWLINE
| exp NEWLINE
| debug NEWLINE
| RAISE NEWLINE
"""
if option == 1:
if option in [1, 2]:
return values[0]
if option == 2:
if option == 3:
raise RuntimeError('on_line: exception raised')
def on_debug(self, target, option, names, values):
"""
debug : GRAPH exp
"""
if option == 0:
print generate_graph(values[1])
return values[1]
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
def on_exp(self, target, option, names, values):
"""
exp : NUMBER
......@@ -118,8 +189,8 @@ class Parser(BisonParser):
| LPAREN exp RPAREN
| unary
| binary
| concat
"""
# | concat
if option == 0: # rule: NUMBER
# TODO: A bit hacky, this achieves long integers and floats.
......@@ -132,9 +203,12 @@ class Parser(BisonParser):
if option == 2: # rule: LPAREN exp RPAREN
return values[1]
if option in [3, 4, 5]: # rule: unary | binary | concat
if option in [3, 4]: # rule: unary | binary
return values[0]
#if option in [3, 4, 5]: # rule: unary | binary | concat
# return values[0]
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
......@@ -179,39 +253,39 @@ class Parser(BisonParser):
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
def on_concat(self, option, target, names, values):
"""
concat : exp IDENTIFIER
| exp NUMBER
| exp LPAREN exp RPAREN
| exp CONCAT_POW
| CONCAT_POW
"""
if option in [0, 1]: # rule: exp IDENTIFIER | exp NUMBER
# example: xy -> x*y
# example: (x)4 -> x*4
val = int(values[1]) if option == 1 else values[1]
return Node('*', *(combine('*', values[0]) + [Leaf(val)]))
if option == 2: # rule: exp LPAREN exp RPAREN
# example: x(y) -> x*(y)
return Node('*', *(combine('*', values[0])
+ combine('*', values[2])))
if option == 3:
# example: xy4 -> x*y^4
identifier, exponent = list(values[1])
node = Node('^', Leaf(identifier), Leaf(int(exponent)))
return Node('*', values[0], node)
if option == 4:
# example: x4 -> x^4
identifier, exponent = list(values[0])
return Node('^', Leaf(identifier), Leaf(int(exponent)))
raise BisonSyntaxError('Unsupported option %d in target "%s".'
% (option, target)) # pragma: nocover
#def on_concat(self, option, target, names, values):
# """
# concat : exp IDENTIFIER %prec TIMES
# | exp NUMBER %prec TIMES
# | exp LPAREN exp RPAREN %prec TIMES
# | exp CONCAT_POW %prec TIMES
# | CONCAT_POW
# """
# if option in [0, 1]: # rule: exp IDENTIFIER | exp NUMBER
# # example: xy -> x*y
# # example: (x)4 -> x*4
# val = int(values[1]) if option == 1 else values[1]
# return Node('*', *(combine('*', values[0]) + [Leaf(val)]))
# if option == 2: # rule: exp LPAREN exp RPAREN
# # example: x(y) -> x*(y)
# return Node('*', *(combine('*', values[0])
# + combine('*', values[2])))
# if option == 3:
# # example: xy4 -> x*y^4
# identifier, exponent = list(values[1])
# node = Node('^', Leaf(identifier), Leaf(int(exponent)))
# return Node('*', values[0], node)
# if option == 4:
# # example: x4 -> x^4
# identifier, exponent = list(values[0])
# return Node('^', Leaf(identifier), Leaf(int(exponent)))
# raise BisonSyntaxError('Unsupported option %d in target "%s".'
# % (option, target)) # pragma: nocover
# -----------------------------------------
# raw lex script, verbatim here
......@@ -230,11 +304,11 @@ class Parser(BisonParser):
#define YY_INPUT(buf,result,max_size) { \
(*py_input)(py_parser, buf, &result, max_size); \
}
/*[a-zA-Z][0-9]+ { returntoken(CONCAT_POW); }*/
%}
%%
[a-zA-Z][0-9]+ { returntoken(CONCAT_POW); }
[0-9]+ { returntoken(NUMBER); }
[a-zA-Z] { returntoken(IDENTIFIER); }
"(" { returntoken(LPAREN); }
......@@ -247,6 +321,7 @@ class Parser(BisonParser):
"," { returntoken(COMMA); }
"quit" { printf("lex: got QUIT\n"); yyterminate(); returntoken(QUIT); }
"raise" { returntoken(RAISE); }
"graph" { returntoken(GRAPH); }
[ \t\v\f] {}
[\n] {yylineno++; returntoken(NEWLINE); }
......
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