#!/usr/bin/env python # coding: utf-8 # In[177]: from rply import LexerGenerator class Lexer(): def __init__(self): self.lexer = LexerGenerator() def _add_tokens(self): # Print self.lexer.add('PRINT', r'print') self.lexer.add('SQRT', r'sqrt') # Parenthesis self.lexer.add('OPEN_PAREN', r'\(') self.lexer.add('CLOSE_PAREN', r'\)') # Semi Colon self.lexer.add('SEMI_COLON', r'\;') # Operators self.lexer.add('SUM', r'\+') self.lexer.add('SUB', r'\-') self.lexer.add('MUL', r'\*') self.lexer.add('DIV', r'\/') # Number self.lexer.add('NUMBER', r'\d+') # Ignore spaces self.lexer.ignore('\s+') def get_lexer(self): self._add_tokens() return self.lexer.build() # In[178]: # !pip install rply # !pip install ast # ## AST # In[179]: class Number(): def __init__(self, value): self.value = value def eval(self): return int(self.value) class BinaryOp(): def __init__(self, left, right): self.left = left self.right = right class Sum(BinaryOp): def eval(self): return self.left.eval() + self.right.eval() class Sub(BinaryOp): def eval(self): return self.left.eval() - self.right.eval() class Mul(BinaryOp): def eval(self): return self.left.eval() * self.right.eval() class Div(BinaryOp): def eval(self): return self.left.eval() / self.right.eval() class Print(): def __init__(self, value): self.value = value def eval(self): print(self.value.eval()) # In[205]: import fastnumbers fastnumbers.isreal("d") # ## Parser # In[199]: from rply import ParserGenerator # from ast import Number, Sum, Sub, Print class Parser(): def __init__(self): self.pg = ParserGenerator( # A list of all token names accepted by the parser. ['NUMBER', 'SQRT','PRINT', 'OPEN_PAREN', 'CLOSE_PAREN', 'SEMI_COLON', 'SUM', 'SUB', 'MUL', 'DIV'], precedence=[ ('left',['SUM','SUB']), ('left',['DIV','MUL']) ] ) def parse(self): # @self.pg.production('function : SQRT OPEN_PAREN expression CLOSE_PAREN') # def func(p): # # print(p) # return (p[2]) @self.pg.production('program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON') def program(p): return Print(p[2]) @self.pg.production('expression : expression SUM expression') @self.pg.production('expression : expression SUB expression') @self.pg.production('expression : expression MUL expression') @self.pg.production('expression : expression DIV expression') def expression(p): left = p[0] right = p[2] operator = p[1] if operator.gettokentype() == 'SUM': return Sum(left, right) elif operator.gettokentype() == 'SUB': return Sub(left, right) elif operator.gettokentype() == 'MUL': return Mul(left, right) elif operator.gettokentype() == 'DIV': return Div(left, right) @self.pg.production('expression : NUMBER') def number(p): return Number(p[0].value) @self.pg.error def error_handle(token): raise ValueError(token) def get_parser(self): return self.pg.build() # In[200]: get_ipython().run_cell_magic('time', '', 'text_input = """\nprint(SQRT(4*3/2));\n"""\n\nlexer = Lexer().get_lexer()\ntokens = lexer.lex(text_input)\n\npg = Parser()\npg.parse()\nparser = pg.get_parser()\n# print(parser)\nparser.parse(tokens).eval()\n') # In[ ]: