Moved argument parser and added 'hint' and 'apply'

Introduced new symbols "?" (suggest hint) and '@' (apply one suggestion).
Moved the argument parser to main.py.

Removed replace from expression{leaf,node}.
parent 834e15e0
#!/usr/bin/python #!/usr/bin/python
"""
Shell front-end for the mathematical term rewriting system. This shell will
parse mathematical expressions into an expression tree, produce possible
rewrite steps and, if requested, provide a hint to rewrite the last entered
expression.
"""
import argparse
import sys
import os
def init_readline(): def init_readline():
import os
try: try:
import readline import readline
except ImportError: except ImportError:
...@@ -19,7 +28,48 @@ def init_readline(): ...@@ -19,7 +28,48 @@ def init_readline():
atexit.register(readline.write_history_file, histfile) atexit.register(readline.write_history_file, histfile)
def get_args():
parser = argparse.ArgumentParser(prog='trs', description=__doc__)
parser.add_argument('--debug', '-d', action='store_true',
default=False,
help='Enable debug mode in bison and flex.')
parser.add_argument('--verbose', '-v', action='store_true',
default=False,
help='Enable verbose output messages (printed to stdout).')
parser.add_argument('--keepfiles', '-k', action='store_true',
default=False,
help='Keep temporary generated bison and lex files.')
parser.add_argument('--batch', '-b', action='store_true', default=False,
help='Disable interactive mode and execute expressions in batch' \
' mode.')
parser.add_argument('--interactive', action='store_true',
default=sys.stdin.isatty(),
help='Enable interactive mode (default). This is the inverse of' \
' --batch.')
return parser.parse_args()
def main():
from src.parser import Parser
args = get_args()
interactive = args.interactive and not args.batch
p = Parser(verbose=args.verbose,
keepfiles=args.keepfiles,
interactive=interactive)
node = p.run(debug=args.debug)
# Clear the line, when the shell exits.
if interactive:
print
return node
if __name__ == '__main__': if __name__ == '__main__':
from src.parser import main
init_readline() init_readline()
main() main()
...@@ -128,12 +128,6 @@ class ExpressionNode(Node, ExpressionBase): ...@@ -128,12 +128,6 @@ class ExpressionNode(Node, ExpressionBase):
def graph(self): # pragma: nocover def graph(self): # pragma: nocover
return generate_graph(self) return generate_graph(self)
def replace(self, node):
pos = self.parent.nodes.index(self)
self.parent.nodes[pos] = node
node.parent = self.parent
self.parent = None
def extract_polynome_properties(self): def extract_polynome_properties(self):
""" """
Extract polynome properties into tuple format: (coefficient, root, Extract polynome properties into tuple format: (coefficient, root,
...@@ -219,12 +213,3 @@ class ExpressionLeaf(Leaf, ExpressionBase): ...@@ -219,12 +213,3 @@ class ExpressionLeaf(Leaf, ExpressionBase):
""" """
# rule: 1 * r ^ 1 -> (1, r, 1) # rule: 1 * r ^ 1 -> (1, r, 1)
return (ExpressionLeaf(1), self, ExpressionLeaf(1)) return (ExpressionLeaf(1), self, ExpressionLeaf(1))
def replace(self, node):
if not hasattr(self, 'parent'):
return
pos = self.parent.nodes.index(self)
self.parent.nodes[pos] = node
node.parent = self.parent
self.parent = None
#!/usr/bin/env python
""" """
This parser will parse the given input and build an expression tree. Grammar This parser will parse the given input and build an expression tree. Grammar
file for the supported mathematical expressions. file for the supported mathematical expressions.
...@@ -6,8 +5,6 @@ file for the supported mathematical expressions. ...@@ -6,8 +5,6 @@ file for the supported mathematical expressions.
from node import ExpressionNode as Node, ExpressionLeaf as Leaf from node import ExpressionNode as Node, ExpressionLeaf as Leaf
import argparse
import os.path import os.path
PYBISON_BUILD = os.path.realpath('build/external/pybison') PYBISON_BUILD = os.path.realpath('build/external/pybison')
EXTERNAL_MODS = os.path.realpath('external') EXTERNAL_MODS = os.path.realpath('external')
...@@ -21,7 +18,7 @@ from graph_drawing.graph import generate_graph ...@@ -21,7 +18,7 @@ from graph_drawing.graph import generate_graph
from node import TYPE_OPERATOR, OP_COMMA from node import TYPE_OPERATOR, OP_COMMA
from rules import RULES from rules import RULES
from possibilities import filter_duplicates from possibilities import filter_duplicates, pick_suggestion, apply_suggestion
# Check for n-ary operator in child nodes # Check for n-ary operator in child nodes
...@@ -55,7 +52,7 @@ class Parser(BisonParser): ...@@ -55,7 +52,7 @@ class Parser(BisonParser):
# of tokens of the lex script. # of tokens of the lex script.
tokens = ['NUMBER', 'IDENTIFIER', tokens = ['NUMBER', 'IDENTIFIER',
'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW', 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'POW',
'LPAREN', 'RPAREN', 'COMMA', 'LPAREN', 'RPAREN', 'COMMA', 'HINT', 'REWRITE',
'NEWLINE', 'QUIT', 'RAISE', 'GRAPH'] 'NEWLINE', 'QUIT', 'RAISE', 'GRAPH']
# ------------------------------ # ------------------------------
...@@ -75,11 +72,9 @@ class Parser(BisonParser): ...@@ -75,11 +72,9 @@ class Parser(BisonParser):
BisonParser.__init__(self, **kwargs) BisonParser.__init__(self, **kwargs)
self.interactive = kwargs.get('interactive', 0) self.interactive = kwargs.get('interactive', 0)
self.timeout = kwargs.get('timeout', 0) self.timeout = kwargs.get('timeout', 0)
self.possibilities = [] self.possibilities = self.last_possibilities = []
# ------------------------------------------------------------------ # Override default read method with a version that prompts for input.
# override default read method with a version that prompts for input
# ------------------------------------------------------------------
def read(self, nbytes): def read(self, nbytes):
if self.file == sys.stdin and self.file.closed: if self.file == sys.stdin and self.file.closed:
return '' return ''
...@@ -90,9 +85,14 @@ class Parser(BisonParser): ...@@ -90,9 +85,14 @@ class Parser(BisonParser):
return '' return ''
def hook_read_before(self): def hook_read_before(self):
if self.interactive and self.possibilities: if self.possibilities:
if self.interactive: # pragma: nocover
print 'possibilities:' print 'possibilities:'
items = filter_duplicates(self.possibilities) items = filter_duplicates(self.possibilities)
self.last_possibilities = self.possibilities
if self.interactive: # pragma: nocover
print ' ' + '\n '.join(map(str, items)) print ' ' + '\n '.join(map(str, items))
self.possibilities = [] self.possibilities = []
...@@ -147,7 +147,7 @@ class Parser(BisonParser): ...@@ -147,7 +147,7 @@ class Parser(BisonParser):
if data == data_after: if data == data_after:
break break
if self.verbose: if self.verbose: # pragma: nocover
print 'hook_read_after() modified the input data:' print 'hook_read_after() modified the input data:'
print 'before:', data.replace('\n', '\\n') print 'before:', data.replace('\n', '\\n')
print 'after :', data_after.replace('\n', '\\n') print 'after :', data_after.replace('\n', '\\n')
...@@ -192,7 +192,7 @@ class Parser(BisonParser): ...@@ -192,7 +192,7 @@ class Parser(BisonParser):
# Interactive mode is enabled if the term rewriting system is used # Interactive mode is enabled if the term rewriting system is used
# as a shell. In that case, it is useful that the shell prints the # as a shell. In that case, it is useful that the shell prints the
# output of the evaluation. # output of the evaluation.
if self.interactive and values[1]: if self.interactive and values[1]: # pragma: nocover
print values[1] print values[1]
return values[1] return values[1]
...@@ -202,12 +202,22 @@ class Parser(BisonParser): ...@@ -202,12 +202,22 @@ class Parser(BisonParser):
line : NEWLINE line : NEWLINE
| exp NEWLINE | exp NEWLINE
| debug NEWLINE | debug NEWLINE
| HINT NEWLINE
| REWRITE NEWLINE
| RAISE NEWLINE | RAISE NEWLINE
""" """
if option in [1, 2]: if option in [1, 2]:
return values[0] return values[0]
if option == 3: if option == 3:
print pick_suggestion(self.last_possibilities)
return
if option == 4:
suggestion = pick_suggestion(self.last_possibilities)
return apply_suggestion(suggestion)
if option == 5:
raise RuntimeError('on_line: exception raised') raise RuntimeError('on_line: exception raised')
def on_debug(self, target, option, names, values): def on_debug(self, target, option, names, values):
...@@ -332,6 +342,8 @@ class Parser(BisonParser): ...@@ -332,6 +342,8 @@ class Parser(BisonParser):
"^" { returntoken(POW); } "^" { returntoken(POW); }
"/" { returntoken(DIVIDE); } "/" { returntoken(DIVIDE); }
"," { returntoken(COMMA); } "," { returntoken(COMMA); }
"?" { returntoken(HINT); }
"@" { returntoken(REWRITE); }
"quit" { yyterminate(); returntoken(QUIT); } "quit" { yyterminate(); returntoken(QUIT); }
"raise" { returntoken(RAISE); } "raise" { returntoken(RAISE); }
"graph" { returntoken(GRAPH); } "graph" { returntoken(GRAPH); }
...@@ -344,39 +356,3 @@ class Parser(BisonParser): ...@@ -344,39 +356,3 @@ class Parser(BisonParser):
yywrap() { return(1); } yywrap() { return(1); }
""" """
def get_args():
parser = argparse.ArgumentParser(prog='parser', description=__doc__)
parser.add_argument('--debug', '-d', action='store_true',
default=False,
help='Enable debug mode in bison and flex.')
parser.add_argument('--verbose', '-v', action='store_true',
default=False,
help='Enable verbose output messages (printed to stdout).')
parser.add_argument('--keepfiles', '-k', action='store_true',
default=False,
help='Keep temporary generated bison and lex files.')
parser.add_argument('--batch', '-b', action='store_true', default=False,
help='Disable interactive mode and execute expressions in batch' \
' mode.')
return parser.parse_args()
def main():
args = get_args()
interactive = not args.batch and sys.stdin.isatty()
p = Parser(verbose=args.verbose,
keepfiles=args.keepfiles,
interactive=interactive)
node = p.run(debug=args.debug)
# Clear the line, when the shell exits.
if interactive:
print
return node
...@@ -36,3 +36,13 @@ def filter_duplicates(items): ...@@ -36,3 +36,13 @@ def filter_duplicates(items):
unique.append(item) unique.append(item)
return unique return unique
def pick_suggestion(possibilities):
# TODO: pick the best suggestion.
suggestion = 0
return possibilities[suggestion]
def apply_suggestion(suggestion):
return suggestion.handler(suggestion.root, suggestion.args)
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