diff --git a/parser.py b/parser.py index 293bf77..8f3e5e4 100644 --- a/parser.py +++ b/parser.py @@ -1,20 +1,23 @@ from __future__ import print_function -from pprint import pprint from rply import ParserGenerator, LexerGenerator from rply.token import BaseBox lg = LexerGenerator() lg.add("LPAREN", r"\(") lg.add("RPAREN", r"\)") +lg.add("QUOTE", r"'") lg.add("ATOM", r"[^\s()]+") lg.ignore(r"\s+") -pg = ParserGenerator(["LPAREN", "RPAREN", "ATOM"]) +pg = ParserGenerator(["QUOTE", "LPAREN", "RPAREN", "ATOM"]) @pg.error def error_handler(token): - raise ValueError("unexpected %s" % token.gettokentype()) + type = token.gettokentype() + pos = token.getsourcepos() + raise ValueError("unexpected %s at (%s, %s)" % + (type, pos.lineno, pos.colno)) @pg.production("main : sexpr") @@ -22,49 +25,52 @@ def main(p): return p[0] -@pg.production("sexpr : LPAREN expr RPAREN") +@pg.production("sexpr : ATOM") +@pg.production("sexpr : QUOTE sexpr") +@pg.production("sexpr : LPAREN list RPAREN") def sexpr(p): - return BoxSexpr(p[1]) + if p[0].gettokentype() == "ATOM": + return BoxAtom(p[0].getstr()) + elif p[0].gettokentype() == "QUOTE": + return BoxQuote(p[1]) + else: + return p[1] -@pg.production("expr : ATOM") -def atom(p): - return BoxAtom(p[0].getstr()) - - -@pg.production("expr : ATOM sexpr") -@pg.production("expr : ATOM expr") -def sexpr(p): - return BoxExpr(BoxAtom(p[0].getstr()), p[1]) +@pg.production("list : sexpr") +@pg.production("list : sexpr list") +def list(p): + if len(p) == 1: + return BoxPair(p[0]) + else: + return BoxPair(p[0], p[1]) lexer = lg.build() parser = pg.build() -class BoxSexpr(BaseBox): - def __init__(self, expr): - self.expr = expr +class BoxQuote(BaseBox): + def __init__(self, sexpr): + self.sexpr = sexpr - def expr(self): - return self.expr + def sexpr(self): + return self.sexpr def __str__(self): - return "( %s )" % (self.expr) + return "' %s" % self.sexpr -class BoxExpr(BaseBox): - def __init__(self, atom, expr): - self.atom = atom - self.expr = expr - - def atom(self): - return self.atom - - def expr(self): - return self.expr +class BoxPair(BaseBox): + def __init__(self, x, y=None): + self.x = x + self.y = y def __str__(self): - return "%s . ( %s )" % (self.atom, self.expr) + if self.y is None: + y = "NIL" + else: + y = self.y + return "(%s . %s)" % (self.x, y) class BoxAtom(BaseBox): @@ -77,4 +83,14 @@ class BoxAtom(BaseBox): def __str__(self): return "%s" % (self.atom) + +print(parser.parse(lexer.lex("1"))) +print(parser.parse(lexer.lex("'1"))) +print(parser.parse(lexer.lex("+"))) +print(parser.parse(lexer.lex("'+"))) +print(parser.parse(lexer.lex("(+ 1 2)"))) +print(parser.parse(lexer.lex("'(+ 1 2)"))) print(parser.parse(lexer.lex("(+ 1 (* 3 2))"))) +print(parser.parse(lexer.lex("'(+ 1 (* 3 2))"))) +print(parser.parse(lexer.lex("(+ (* 4 5) (* 3 2))"))) +print(parser.parse(lexer.lex("(+ '(* 4 5) (* 3 2))")))