Created
February 3, 2019 23:13
-
-
Save costrouc/f08bb88902437ba9d92017eb4c673581 to your computer and use it in GitHub Desktop.
parser + ast + python source code translation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import ast | |
| import astunparse | |
| import sly | |
| class CalculatorLexer(sly.Lexer): | |
| tokens = { SYMBOL, NUMBER, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN } | |
| ignore = ' \t' | |
| SYMBOL = r'[A-Za-z][A-Za-z0-9_]*' | |
| PLUS = r'\+' | |
| MINUS = r'\-' | |
| TIMES = r'\*' | |
| DIVIDE = '/' | |
| LPAREN = '\(' | |
| RPAREN = '\)' | |
| @_(r'[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?') | |
| def NUMBER(self, t): | |
| t.value = float(t.value) | |
| return t | |
| class CalculatorParser(sly.Parser): | |
| tokens = CalculatorLexer.tokens | |
| precedence = ( | |
| ('left', 'PLUS', 'MINUS'), | |
| ('left', 'TIMES', 'DIVIDE'), | |
| ('left', 'UMINUS') | |
| ) | |
| @_('expr PLUS expr', | |
| 'expr MINUS expr', | |
| 'expr TIMES expr', | |
| 'expr DIVIDE expr') | |
| def expr(self, p): | |
| op_map = { | |
| '+': ast.Add, | |
| '-': ast.Sub, | |
| '*': ast.Mult, | |
| '/': ast.Div | |
| } | |
| return ast.BinOp(p.expr0, op_map[p[1]](), p.expr1) | |
| @_('MINUS expr %prec UMINUS') | |
| def expr(self, p): | |
| return ast.UnaryOp(ast.USub(), p.expr) | |
| @_('NUMBER') | |
| def expr(self, p): | |
| return ast.Num(p[0]) | |
| @_('LPAREN expr RPAREN') | |
| def expr(self, p): | |
| return p.expr | |
| @_('SYMBOL LPAREN expr RPAREN') | |
| def expr(self, p): | |
| return ast.Call(func=ast.Name(id=p.SYMBOL), args=[p.expr], keywords=[]) | |
| if __name__ == '__main__': | |
| parser = CalculatorParser() | |
| lexer = CalculatorLexer() | |
| print('Simple Calculator to exit type (q)uit') | |
| while True: | |
| text = input('calc> ') | |
| if text in {'q', 'quit'}: break | |
| tree = parser.parse(lexer.tokenize(text)) | |
| source = astunparse.unparse(tree)[:-1] # remove newline | |
| print('SOURCE', source) | |
| print('EVAL', eval(source)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment