summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenedikt Böhm <bb@xnull.de>2009-06-29 12:28:01 +0200
committerBenedikt Böhm <bb@xnull.de>2009-06-29 12:28:01 +0200
commit4aedc5d76250fae734af1cd89256ec70e165ab18 (patch)
tree9f9c290f7d31a9aa966045019972670382596d45
parent17fab2bc59945045a8df39ece8c845d1565245da (diff)
downloadswppy-4aedc5d76250fae734af1cd89256ec70e165ab18.tar.gz
swppy-4aedc5d76250fae734af1cd89256ec70e165ab18.tar.xz
swppy-4aedc5d76250fae734af1cd89256ec70e165ab18.zip
fix function_call
- function_call is now an expression and a statement - call keyword is required to make lookahead = 1 work
-rw-r--r--doc/mylang.ebnf36
-rw-r--r--src/__init__.py18
-rw-r--r--src/front/ast.py2
-rw-r--r--src/front/lexer.py1
-rw-r--r--src/front/parser.py103
-rw-r--r--src/front/token.py1
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 "<Function: %s %s %s>" % (self.name, str(self.params), str(self.statements))
+ return "<Function: %s(%s) at line %d: %s>" % (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")