This is a minimal example of a python ply parser run from a single file which does not produce any files on disk when run. It should use most of the main features of the ply language so might be suitable for a paste-and-adapt approach.
Download"""A minimal example of using ply all in one file, illustrating most
of the features you are likely to need.
Parses an simple lisp with a + function and numbers."""
from ply.lex import lex
from ply.yacc import yacc
def listify(gen):
"Convert a generator into a function which returns a list"
def patched(*args, **kwargs):
return list(gen(*args, **kwargs))
return patched
class Lexer(object):
t_PLUS = r"\+"
t_OPEN = r"\("
t_CLOSE = r"\)"
t_ignore = " "
def t_NUMBER(self, t):
r"\d+"
t.value = int(t.value)
return t
tokens = "PLUS OPEN CLOSE NUMBER".split()
def t_error(self, t):
raise Exception(t)
lexer = lex(module=Lexer())
class Parser(object):
"e.g (+ (+ 1 2) (+ 3 4))"
starting = "statement" # default is first method
def p_statement(self, p):
"""statement : OPEN PLUS numbers CLOSE
| OPEN PLUS statements CLOSE
"""
p[0] = sum(p[3])
def p_statements(self, p):
"statements : statement statements"
p[0] = (p[1],) + p[2]
def p_statements2(self, p):
"statements : statement"
p[0] = (p[1],)
def p_numbers(self, p):
"numbers : NUMBER"
p[0] = (p[1],)
def p_numbers2(self, p):
"numbers : numbers NUMBER"
p[0] = p[1] + (p[2],)
def p_error(self, p):
raise Exception(p)
tokens = Lexer.tokens
if __name__ == '__main__':
lexer = lex(module=Lexer())
parser = yacc(module=Parser(), write_tables=0)
while True:
print parser.parse(raw_input("lisp>"))
# TESTS - run with nosetests modulename
def test_parser():
lexer = lex(module=Lexer())
parser = yacc(module=Parser())
assert parser.parse("(+(+1 2) (+3 4)) ", lexer=lexer) == 10
def test_lexer():
lexer = lex(module=Lexer())
lexer.input("( ) 1 2 + (")
tokens = []
@listify
def collect_until_None(f):
while True:
thing = f()
if thing is None:
break
yield thing
tokens = collect_until_None(lexer.token)
types = [t.type for t in tokens]
assert types == "OPEN CLOSE NUMBER NUMBER PLUS OPEN".split()
assert (tokens[2].value, tokens[3].value) == (1, 2)