From 4aedc5d76250fae734af1cd89256ec70e165ab18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20B=C3=B6hm?= Date: Mon, 29 Jun 2009 12:28:01 +0200 Subject: fix function_call - function_call is now an expression and a statement - call keyword is required to make lookahead = 1 work --- doc/mylang.ebnf | 36 +++++++++--------- src/__init__.py | 18 ++------- src/front/ast.py | 2 +- src/front/lexer.py | 1 + src/front/parser.py | 103 ++++++++++++++++++---------------------------------- src/front/token.py | 1 + 6 files changed, 59 insertions(+), 102 deletions(-) diff --git a/doc/mylang.ebnf b/doc/mylang.ebnf index 7c67bbb..f84869f 100644 --- a/doc/mylang.ebnf +++ b/doc/mylang.ebnf @@ -8,27 +8,27 @@ nl = "\n". ident = letter { letter | digit }. integer = digit { digit }. -disjunction = conjunction { "||" conjunction }. -conjunction = boolean { "&&" boolean }. -boolean = "!" disjunction | comparison | "(" disjunction ")" | "true" | "false". -comparison = expression ( "==" | "!=" | "<" | "<=" | "=>" | ">" ) expression. - +boolean = join { "||" join }. +join = relation { "&&" relation }. +relation = expression { ( "==" | "!=" | "<" | "<=" | ">=" | ">" ) expression }. expression = term { ( "+" | "-" ) term }. term = unary { ( "*" | "/" | "%" ) unary }. -unary = ident | integer | "-" unary | "(" expression ")". +unary = "!" unary | "-" unary | factor. +factor = "(" boolean ")" | ident | integer | "true" | "false" | function_call. + +function_call = "call" ident "[" [ expression_list ] "]". ident_list = ident { "," ident }. -expression_list = expression { "," expression }. -function_list = function { nl function }. -statement_list = statement { nl statement }. - -function = "fun" ident "[" [ ident_list ] "]" nl statement_list nl "end". -statement = [ if_statement | while_statement | assign_statement | function_call | return_statement ]. - -if_statement = "if" expression nl statement_list nl [ "else" statement_list nl ] "end". -while_statement = "while" expression nl statement_list nl "end". -return_statement = "@" expression. -assign_statement = ident "=" expression. -function_call = ident "[" [ expression_list ] "]". +expression_list = boolean { "," boolean }. +function_list = function { function }. +statement_list = statement { statement }. + +function = "fun" ident "[" [ ident_list ] "]" nl statement_list "end" nl. +statement = ( if_statement | while_statement | assign_statement | return_statement | function_call ). + +if_statement = "if" boolean nl statement_list [ "else" nl statement_list ] "end" nl. +while_statement = "while" boolean nl statement_list "end" nl. +return_statement = "@" boolean nl. +assign_statement = ident "=" boolean nl. program = function_list. diff --git a/src/__init__.py b/src/__init__.py index 747efde..ad0278b 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -1,13 +1,12 @@ from front.lexer import Lexer from front.parser import Parser -#from front.symbols import SymbolTable def main(): source = '''fun fib[a] if a < 2 @1 end - @( fib[a-1] + fib[a-2] ) + @( call fib[a-1] + call fib[a-2] ) end # main function @@ -15,24 +14,13 @@ fun main[] sum = 0 i = 0 while (i < 10) - sum = sum + fib[i] + sum = sum + call fib[i] i = i + 1 end @sum end''' - #symbols = SymbolTable() - #lex = Lexer(source) - - # testing - #while True: - # token = lex.scan() - # print token.__repr__() - # if not token: - # break - - parse = Parser(Lexer(source)) - print parse.parse() + print Parser(Lexer(source)).parse() if __name__ == "__main__": main() diff --git a/src/front/ast.py b/src/front/ast.py index 751d38d..d6d4a3f 100644 --- a/src/front/ast.py +++ b/src/front/ast.py @@ -25,7 +25,7 @@ class Function(Node): self.lineno = lineno def __repr__(self): - return "" % (self.name, str(self.params), str(self.statements)) + return "" % (self.name, str(self.params), self.lineno, str(self.statements)) def eval(self,tacarray): return tacarray.append(te) diff --git a/src/front/lexer.py b/src/front/lexer.py index f2810cd..53ccaec 100644 --- a/src/front/lexer.py +++ b/src/front/lexer.py @@ -21,6 +21,7 @@ class Lexer: 'while': Token(Tag.WHILE), 'if': Token(Tag.IF), 'else': Token(Tag.ELSE), + 'call': Token(Tag.CALL), 'fun': Token(Tag.FUN), 'end': Token(Tag.END)} return diff --git a/src/front/parser.py b/src/front/parser.py index 29e300d..610a5bb 100644 --- a/src/front/parser.py +++ b/src/front/parser.py @@ -36,58 +36,41 @@ class Parser: def boolean(self): res = self.join() while self.token.tag == Tag.OPERATOR and self.token.value == "||": - self.move() - res = BinaryExpression(res, "||", self.join()) + res = BinaryExpression(res, self.match(Tag.OPERATOR), self.join(), self.lexer.line) return res - # join = equality { "&&" equality }. + # join = relation { "&&" relation }. 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()) + while self.token.tag == Tag.OPERATOR and self.token.value == "&&": + res = BinaryExpression(res, self.match(Tag.OPERATOR), self.relation(), self.lexer.line) return res - # relation = expression { ( "<" | "<=" | ">=" | ">" ) expression }. + # 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()) + while self.token.tag == Tag.OPERATOR and self.token.value in ["==", "!=", "<", "<=", ">=", ">"]: + res = BinaryExpression(res, self.match(Tag.OPERATOR), self.expression(), self.lexer.line) 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()) + res = BinaryExpression(res, self.match(Tag.OPERATOR), self.term(), self.lexer.line) 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()) + res = BinaryExpression(res, self.match(Tag.OPERATOR), self.unary(), self.lexer.line) 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()) + if self.token.tag == Tag.OPERATOR and self.token.value in ["!", "-"]: + return UnaryExpression(self.match(Tag.OPERATOR), self.unary(), self.lexer.line) return self.factor() # factor = "(" boolean ")" | integer | "true" | "false" | ident | function_call. @@ -98,46 +81,25 @@ class Parser: self.match(Tag.RPAREN) return res if self.token.tag == Tag.NUMBER: - return Constant(self.match(Tag.NUMBER)) + return Constant(self.match(Tag.NUMBER), self.lexer.line) if self.token.tag == Tag.TRUE: self.move() - return Constant(1) + return Constant(1, self.lexer.line) 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. - ''' + return Constant(0, self.lexer.line) 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[] - ''' + return Variable(self.match(Tag.IDENT), self.lexer.line) + return self.function_call() + + # function_call = "call" ident "[" [ expression_list ] "]". def function_call(self): + self.match(Tag.CALL) 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) + return FunctionCall(name, args, self.lexer.line) # ident_list = ident { "," ident }. def ident_list(self): @@ -171,6 +133,7 @@ class Parser: # function = "fun" ident "[" [ ident_list ] "]" nl statement_list "end" nl. def function(self): + line = self.lexer.line self.match(Tag.FUN) name = self.match(Tag.IDENT) self.match(Tag.LBRAK) @@ -180,18 +143,20 @@ class Parser: block = self.statement_list() self.match(Tag.END) self.match(Tag.NEWLINE) - return Function(name, args, block) + return Function(name, args, block, line) - # statement = [ if_statement | while_statement | assign_statement | return_statement ]. + # statement = [ if_statement | while_statement | assign_statement | return_statement | function_call ]. def statement(self): return {Tag.IF: self.if_statement, Tag.WHILE: self.while_statement, Tag.IDENT: self.assignment, - Tag.RETURN: self.return_statement + Tag.RETURN: self.return_statement, + Tag.CALL: self.function_call, }[self.token.tag]() - # if_statement = "if" boolean nl statement_list [ "else" [ nl ] statement_list ] "end" nl. + # if_statement = "if" boolean nl statement_list [ "else" nl statement_list ] "end" nl. def if_statement(self): + line = self.lexer.line self.match(Tag.IF) condition = self.boolean() self.match(Tag.NEWLINE) @@ -199,38 +164,40 @@ class Parser: else_case = [] if self.token.tag == Tag.ELSE: self.move() - if self.token.tag == Tag.NEWLINE: self.move() + self.match(Tag.NEWLINE) else_case = self.statement_list() self.match(Tag.END) self.match(Tag.NEWLINE) - return IfStatement(condition, true_case, else_case) + return IfStatement(condition, true_case, else_case, line) # while_statement = "while" boolean nl statement_list "end" nl. def while_statement(self): + line = self.lexer.line 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 WhileStatement(condition, body, line) # return_statement = "@" boolean nl. def return_statement(self): + line = self.lexer.line self.match(Tag.RETURN) exp = self.boolean() self.match(Tag.NEWLINE) - return ReturnStatement(exp) + return ReturnStatement(exp, line) # assignment = ident "=" boolean nl. def assignment(self): + line = self.lexer.line name = self.match(Tag.IDENT) self.match(Tag.ASSIGNMENT) exp = self.boolean() self.match(Tag.NEWLINE) - return AssignStatement(name, exp) + return AssignStatement(name, exp, line) # program = function_list. def program(self): return Program(self.function_list()) - diff --git a/src/front/token.py b/src/front/token.py index bfcc082..78e9dab 100644 --- a/src/front/token.py +++ b/src/front/token.py @@ -27,6 +27,7 @@ Tag.RPAREN = Tag("RPAREN") Tag.NEWLINE = Tag("NEWLINE") Tag.COMMA = Tag("COMMA") Tag.FUN = Tag("FUN") +Tag.CALL = Tag("CALL") Tag.ASSIGNMENT = Tag("ASSIGNMENT") Tag.RETURN = Tag("RETURN") Tag.OPERATOR = Tag("OPERATOR") -- cgit v1.2.3