# -*- coding: utf-8 -*- from ast import * from lexer import * from token import * class Parser: def __init__(self, lex): self.lexer = lex self.token = lex.scan() self.count = 1 #debug return def parse(self): return self.program() def move(self): print self.count, self.token #debug self.count += 1 #debug self.token = self.lexer.scan() return def error(self, msg): raise Exception(msg) def match(self, tag): if self.token == None: self.error("Unexpected end of file.") if self.token.tag != tag: self.error("match: expected %s got %s\n" %(tag, self.token.tag)) val = self.token.value self.move() return val # boolean = join { "||" join }. def boolean(self): res = self.join() while self.token.tag == Tag.OPERATOR and self.token.value == "||": self.move() res = BinaryExpression(res, "||", self.join()) return res # join = equality { "&&" equality }. def join(self): res = self.equality() while self.token.tag == Tag.OPERATOR and self.token.value == "&&": self.move() res = BinaryExpression(res, "&&", self.relation()) return res # equality = relation { ( "==" | "!=" ) relation }. def equality(self): res = self.relation() while self.token.tag == Tag.OPERATOR and self.token.value in ["==", "!="]: op = self.match(Tag.OPERATOR) res = BinaryExpression(res, op, self.relation()) return res # relation = expression { ( "<" | "<=" | ">=" | ">" ) expression }. def relation(self): res = self.expression() while self.token.tag == Tag.OPERATOR and self.token.value in ["<", "<=", ">=", ">"]: op = self.match(Tag.OPERATOR) res = BinaryExpression(res, op, self.expression()) return res # expression = term { ( "+" | "-" ) term }. def expression(self): res = self.term() while self.token.tag == Tag.OPERATOR and self.token.value in ["+", "-"]: op = self.match(Tag.OPERATOR) res = BinaryExpression(res, op, self.term()) return res # term = unary { ( "*" | "/" | "%" ) unary }. def term(self): res = self.unary() while self.token.tag == Tag.OPERATOR and self.token.value in ["*", "/", "%"]: op = self.match(Tag.OPERATOR) res = BinaryExpression(res, op, self.unary()) return res # unary = "!" unary | "-" unary | factor. def unary(self): if self.token.tag == Tag.OPERATOR and self.token.value == "!": self.move() return UnaryExpression("!", self.unary()) if self.token.tag == Tag.OPERATOR and self.token.value == "-": self.move() return UnaryExpression("-", self.unary()) return self.factor() # factor = "(" boolean ")" | integer | "true" | "false" | ident | function_call. def factor(self): if self.token.tag == Tag.LPAREN: self.move() res = self.boolean() self.match(Tag.RPAREN) return res if self.token.tag == Tag.NUMBER: return Constant(self.match(Tag.NUMBER)) if self.token.tag == Tag.TRUE: self.move() return Constant(1) if self.token.tag == Tag.FALSE: self.move() return Constant(0) ''' Wegen der Änderung in function_call() kann die Grammatik nicht mehr mit einem Lookahead von 1 geparst werden. Die Lösung hier ist, den Aufruf von function_call() zu "inlinen". Muss irgendwann aber geändert werden. Eine Lösung wäre Funktionen mit call aufzurufen oder eben auf LL(2) oder LR umzusteigen. ''' if self.token.tag == Tag.IDENT: name = self.match(Tag.IDENT) if self.token.tag == Tag.LBRAK: # function_call self.match(Tag.LBRAK) args = [] if self.token.tag == Tag.RBRAK else self.expression_list() self.match(Tag.RBRAK) return FunctionCall(name, args) return Variable(name)# variable error("unknown factor begins with " + self.token.tag) # function_call = ident "[" [ expression_list ] "]". ''' function_call muss eine expression sein sonst geht alles folgende nicht: foo = bar[] @foo[bar] spam[5] + eggs[1] andererseits ist function_call dann kein statement mehr exit[] wäre also falsch. Der Aufruf muss in einem assignment verkapselt werden: dummy = exit[] ''' def function_call(self): name = self.match(Tag.IDENT) self.match(Tag.LBRAK) args = [] if self.token.tag == Tag.RBRAK else self.expression_list() self.match(Tag.RBRAK) return FunctionCall(name, args) # ident_list = ident { "," ident }. def ident_list(self): ident = [self.match(Tag.IDENT)] while self.token.tag == Tag.COMMA: self.move() ident.append(self.match(Tag.IDENT)) return ident # expression_list = boolean { "," boolean }. def expression_list(self): exp = [self.boolean()] while self.token.tag == Tag.COMMA: self.move() exp.append(self.boolean()) return exp # function_list = function { function }. def function_list(self): funcs = [self.function()] while self.token: funcs.append(self.function()) return funcs # statement_list = statement { statement }. def statement_list(self): stat = [self.statement()] while self.token.tag not in [Tag.END, Tag.ELSE]: stat.append(self.statement()) return stat # function = "fun" ident "[" [ ident_list ] "]" nl statement_list "end" nl. def function(self): self.match(Tag.FUN) name = self.match(Tag.IDENT) self.match(Tag.LBRAK) args = [] if self.token.tag == Tag.RBRAK else self.ident_list() self.match(Tag.RBRAK) self.match(Tag.NEWLINE) block = self.statement_list() self.match(Tag.END) self.match(Tag.NEWLINE) return Function(name, args, block) # statement = [ if_statement | while_statement | assign_statement | return_statement ]. def statement(self): return {Tag.IF: self.if_statement, Tag.WHILE: self.while_statement, Tag.IDENT: self.assignment, Tag.RETURN: self.return_statement }[self.token.tag]() # if_statement = "if" boolean nl statement_list [ "else" [ nl ] statement_list ] "end" nl. def if_statement(self): self.match(Tag.IF) condition = self.boolean() self.match(Tag.NEWLINE) true_case = self.statement_list() else_case = [] if self.token.tag == Tag.ELSE: self.move() if self.token.tag == Tag.NEWLINE: self.move() else_case = self.statement_list() self.match(Tag.END) self.match(Tag.NEWLINE) return IfStatement(condition, true_case, else_case) # while_statement = "while" boolean nl statement_list "end" nl. def while_statement(self): self.match(Tag.WHILE) condition = self.boolean() self.match(Tag.NEWLINE) body = self.statement_list() self.match(Tag.END) self.match(Tag.NEWLINE) return WhileStatement(condition, body) # return_statement = "@" boolean nl. def return_statement(self): self.match(Tag.RETURN) exp = self.boolean() self.match(Tag.NEWLINE) return ReturnStatement(exp) # assignment = ident "=" boolean nl. def assignment(self): name = self.match(Tag.IDENT) self.match(Tag.ASSIGNMENT) exp = self.boolean() self.match(Tag.NEWLINE) return AssignStatement(name, exp) # program = function_list. def program(self): return Program(self.function_list())