Skip to content

Instantly share code, notes, and snippets.

@soasme
Created July 3, 2018 10:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soasme/9cf367101f5fe34494b1a3b388f3edf4 to your computer and use it in GitHub Desktop.
Save soasme/9cf367101f5fe34494b1a3b388f3edf4 to your computer and use it in GitHub Desktop.
from rpython.rlib.parsing.ebnfparse import parse_ebnf, make_parse_function
from rpython.rlib.parsing.parsing import ParseError
from rpython.rlib.parsing.deterministic import LexerError
EBNF = """
IGNORE: " |\n";
NUMBER: "\-?(0|[1-9][0-9]*)(\.[0-9]+)?";
expr : NUMBER >(arith_op NUMBER)+< | <NUMBER>;
arith_op: <"+"> | <"-">;
main: <expr> [EOF];
"""
regexes, rules, _to_ast = parse_ebnf(EBNF)
parse_ebnf = make_parse_function(regexes, rules, eof=True)
to_ast = _to_ast()
def eval(ast):
if ast.symbol == 'main':
expr = ast.children[0]
return eval(expr);
elif ast.symbol == 'expr':
term = eval(ast.children[0])
for i in range(1, len(ast.children[1:]), 2):
op, term_i = ast.children[i], eval(ast.children[i+1])
if op.additional_info == '+':
term = term + term_i
elif op.additional_info == '-':
term = term - term_i
return term
elif ast.symbol == 'NUMBER':
if ast.additional_info.startswith('-'):
return -1 * float(ast.additional_info[1:])
else:
return float(ast.additional_info)
else:
print(ast)
raise ValueError('unknown ast.')
def run(source):
tree = parse_ebnf(source)
ast = to_ast.transform(tree)
print(eval(ast))
if __name__ == '__main__':
while True:
try:
print '>',
expr = run(raw_input())
except Exception as e:
print(e)
@soasme
Copy link
Author

soasme commented Jul 3, 2018

$ virtualenv venv
$ source venv/bin/activate
$ pip install rpython
$ python ebnf-demo.py
> 1 + 1 + 2
4.0
> -1 + -1 + -2
-4.0
> -1+-1+-1
-3.0
> ^C

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment