Skip to content

Instantly share code, notes, and snippets.

@fabiocerqueira
Last active August 29, 2015 14:11
Show Gist options
  • Save fabiocerqueira/b4bd410bfe6a895c4f98 to your computer and use it in GitHub Desktop.
Save fabiocerqueira/b4bd410bfe6a895c4f98 to your computer and use it in GitHub Desktop.
An example of how to make a parsing with rply
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import warnings
from rply import ParserGenerator, LexerGenerator, ParsingError
from rply.lexer import LexingError
from rply.token import BaseBox
lg = LexerGenerator()
lg.add('NUMBER', r'\d+')
lg.add('WALK', r'andar')
lg.add('TURN', r'girar')
lg.add('STEP', r'passo(s)?')
lg.add('DOT', r'\.')
lg.add('COLON', r':')
lg.add('LEFT', r'esquerda')
lg.add('RIGHT', r'direita')
lg.add('DEGREE', r'grau(s)?')
lg.add('CATCH', r'pegar')
lg.add('DROP', r'soltar')
lg.add('DO', r'faça')
lg.add('END', r'fim')
lg.add('TIMES', r'vez(es)?')
lg.ignore(r'\s+')
class Number(BaseBox):
def __init__(self, value):
self.value = value
def eval(self):
return self.value
class Walk(BaseBox):
def __init__(self, value):
self.value = value
def eval(self):
return ">>> Andei {} passos!".format(self.value.eval())
class Turn(BaseBox):
def __init__(self, degree, direction):
self.degree = degree
self.direction = direction
def eval(self):
return ">>> Girei {} graus a {}".format(self.degree.eval(),
self.direction)
class Catch(BaseBox):
def eval(self):
return ">>> Peguei!"
class Drop(BaseBox):
def eval(self):
return ">>> Soltei!"
class DoStmt(BaseBox):
def __init__(self, times, blocks):
self.times = times
self.blocks = blocks
def eval(self):
out = ">>> Começando a fazer\n"
for i in range(self.times.eval()):
for block in self.blocks:
out += "\t" + block.eval() + "\n"
out += ">>> fim"
return out
pg = ParserGenerator(
['NUMBER', 'WALK', 'TURN', 'STEP', 'DOT', 'RIGHT',
'LEFT', 'DEGREE', 'CATCH', 'DROP', 'DO', 'COLON',
'TIMES', 'END'],
)
@pg.production('program : block')
def program(p):
return p[0]
@pg.production('block : stmts')
def block(p):
return p[0]
@pg.production('stmts : stmts stmt')
def stmts_b(p):
if p[1] is None:
return p[0]
else:
return p[0] + [p[1]]
@pg.production('stmts : stmt')
def stmts_stmt(p):
if p[0] is None:
return []
else:
return [p[0]]
@pg.production('stmt : walk_expr')
@pg.production('stmt : turn_expr')
@pg.production('stmt : catch_expr')
@pg.production('stmt : drop_expr')
@pg.production('stmt : do_stmt')
def stmt(p):
return p[0]
@pg.production('walk_expr : WALK number STEP DOT')
def expression_walk(p):
return Walk(p[1])
@pg.production('number : NUMBER')
def expr_number(p):
return Number(int(p[0].getstr()))
@pg.production('turn_expr : TURN number DEGREE direction DOT')
def expression_turn(p):
return Turn(p[1], p[3])
@pg.production('turn_expr : TURN direction DOT')
def expression_simple_turn(p):
return Turn(Number(90), p[1])
@pg.production('direction : RIGHT')
@pg.production('direction : LEFT')
def direction(p):
return p[0].getstr()
@pg.production('catch_expr : CATCH DOT')
def expression_catch(p):
return Catch()
@pg.production('drop_expr : DROP DOT')
def expression_drop(p):
return Drop()
@pg.production('do_stmt : DO number TIMES COLON block END')
def expression_do(p):
return DoStmt(p[1], p[4])
def robo_run(source_code):
l = lg.build()
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore')
for expr in pg.build().parse(l.lex(source_code)):
print expr.eval()
except ParsingError as e:
print "ParsingError: lineno={} colno={}".format(
e.getsourcepos().lineno, e.getsourcepos().colno)
except LexingError as e:
print "LexingError: lineno={} colno={}".format(
e.getsourcepos().lineno, e.getsourcepos().colno)
if __name__ == '__main__':
source_code = """
girar 3 graus esquerda.
andar 10 passos.
girar direita.
pegar.
soltar.
faça 2 vezes:
pegar.
andar 1 passo.
soltar.
fim
girar 45 graus direita.
"""
robo_run(source_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment