Skip to content
Snippets Groups Projects
Commit 046889e2 authored by Xun Yang's avatar Xun Yang
Browse files

methodNode ReturnNode codeGen

parent 21fdaf4e
No related branches found
No related tags found
No related merge requests found
...@@ -58,6 +58,7 @@ def reachabilityChecking(ASTs): ...@@ -58,6 +58,7 @@ def reachabilityChecking(ASTs):
#################################################### ####################################################
def codeGen(ASTs, output="output"): def codeGen(ASTs, output="output"):
ASTs = ASTs[:1] # TOREMOVE: don't compile stdlib for now
for t in ASTs: for t in ASTs:
t[1].codeGen() t[1].codeGen()
# Outputting the generated code into className.s # Outputting the generated code into className.s
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
# String, String, String/None, String/None # String, String, String/None, String/None
def p(instruction, arg1, arg2="", comment=""): def p(instruction, arg1, arg2="", comment=""):
result = " " + instruction + " " + str(arg1) result = " " + instruction + " " + str(arg1)
if arg2 != "": if arg2:
result += ", " + str(arg2) result += ", " + arg2
if comment: if comment:
result += " ;" + comment result += " ;" + comment
return result + "\n" return result + "\n"
......
...@@ -92,7 +92,7 @@ class BlockNode(ASTNode): ...@@ -92,7 +92,7 @@ class BlockNode(ASTNode):
if not inMaybe: if not inMaybe:
raise Exception("ERROR: cannot reach block node in class {}".format(self.typeName)) raise Exception("ERROR: cannot reach block node in class {}".format(self.typeName))
# Checking reachability of each statement # Checking reachability of each statement
prevOut = inMaybe # Note: in[S1] = in[L] prevOut = inMaybe # Note: in[S1] = in[L]
for statement in self.statements: for statement in self.statements:
...@@ -122,6 +122,8 @@ class VarDclNode(ASTNode): ...@@ -122,6 +122,8 @@ class VarDclNode(ASTNode):
self.dclType = TypeNode(parseTree.children[0], typeName) self.dclType = TypeNode(parseTree.children[0], typeName)
self.name = parseTree.children[1].lex self.name = parseTree.children[1].lex
self.offset = 0 # offset on the stack
if len(parseTree.children) > 2: if len(parseTree.children) > 2:
# Handling rule: variableInit expr # Handling rule: variableInit expr
self.variableInit = makeNodeFromExpr(parseTree.children[3].children[0], typeName) self.variableInit = makeNodeFromExpr(parseTree.children[3].children[0], typeName)
...@@ -201,7 +203,7 @@ class IfNode(ASTNode): ...@@ -201,7 +203,7 @@ class IfNode(ASTNode):
# No need to check for empty statement, since in[ifBody] = inMaybe # No need to check for empty statement, since in[ifBody] = inMaybe
if self.ifBody: if self.ifBody:
self.ifBody.reachCheck(inMaybe) self.ifBody.reachCheck(inMaybe)
if not self.elseBody: if not self.elseBody:
# L : if (E) S # L : if (E) S
# in[S] = in[L] # in[S] = in[L]
...@@ -250,7 +252,7 @@ class WhileNode(ASTNode): ...@@ -250,7 +252,7 @@ class WhileNode(ASTNode):
def reachCheck(self, inMaybe): def reachCheck(self, inMaybe):
if not inMaybe: if not inMaybe:
raise Exception("in[s] = no for WhileNode in class {}".format(self.typeName)) raise Exception("in[s] = no for WhileNode in class {}".format(self.typeName))
# Checking constant expression in whileBound # Checking constant expression in whileBound
con = None # default to None: i.e. not a constant expression con = None # default to None: i.e. not a constant expression
if hasattr(self.whileBound, "getConstant"): if hasattr(self.whileBound, "getConstant"):
...@@ -261,7 +263,7 @@ class WhileNode(ASTNode): ...@@ -261,7 +263,7 @@ class WhileNode(ASTNode):
# General case: while(E) S # General case: while(E) S
if con == None: if con == None:
self.outMaybe = inMaybe self.outMaybe = inMaybe
# while(false) S # while(false) S
elif con == False or con == 0: elif con == False or con == 0:
self.outMaybe = inMaybe self.outMaybe = inMaybe
inMaybeWhileBody = False inMaybeWhileBody = False
...@@ -270,12 +272,12 @@ class WhileNode(ASTNode): ...@@ -270,12 +272,12 @@ class WhileNode(ASTNode):
# Checking reachability on whileBody # Checking reachability on whileBody
if self.whileBody: if self.whileBody:
self.whileBody.reachCheck(inMaybeWhileBody) self.whileBody.reachCheck(inMaybeWhileBody)
elif not inMaybeWhileBody: # empty block/empty statement that's unreachable elif not inMaybeWhileBody: # empty block/empty statement that's unreachable
raise Exception("ERROR: unreachable empty statment/block at while node for class {}".format(self.typeName)) raise Exception("ERROR: unreachable empty statment/block at while node for class {}".format(self.typeName))
return return
# returnStatement # returnStatement
# Rules: # Rules:
...@@ -310,6 +312,12 @@ class ReturnNode(ASTNode): ...@@ -310,6 +312,12 @@ class ReturnNode(ASTNode):
raise Exception("ERROR: return statement unreachable at class {}".format(self.typeName)) raise Exception("ERROR: return statement unreachable at class {}".format(self.typeName))
self.outMaybe = False # out[L] = no self.outMaybe = False # out[L] = no
def codeGen(self):
self.code = ""
if self.expr:
self.expr.codeGen()
self.code += self.expr.code
# forStatement and forStatementNoShortIf # forStatement and forStatementNoShortIf
# Rules: # Rules:
# 1. forStatement FOR LPAREN forInit SEMICO forExpr SEMICO forInit RPAREN statement # 1. forStatement FOR LPAREN forInit SEMICO forExpr SEMICO forInit RPAREN statement
...@@ -376,7 +384,7 @@ class ForNode(ASTNode): ...@@ -376,7 +384,7 @@ class ForNode(ASTNode):
def reachCheck(self, inMaybe): def reachCheck(self, inMaybe):
if not inMaybe: if not inMaybe:
raise Exception("in[s] = no for ForNode in class {}".format(self.typeName)) raise Exception("in[s] = no for ForNode in class {}".format(self.typeName))
# Checking constant expression in whileBound # Checking constant expression in whileBound
con = None # default to None: i.e. not a constant expression con = None # default to None: i.e. not a constant expression
if hasattr(self.forBound, "getConstant"): if hasattr(self.forBound, "getConstant"):
...@@ -396,7 +404,7 @@ class ForNode(ASTNode): ...@@ -396,7 +404,7 @@ class ForNode(ASTNode):
# Checking reachability on whileBody # Checking reachability on whileBody
if self.bodyStatement: if self.bodyStatement:
self.bodyStatement.reachCheck(inMaybeForBody) self.bodyStatement.reachCheck(inMaybeForBody)
elif inMaybeForBody: # checking if the empty forBody can be reached elif inMaybeForBody: # checking if the empty forBody can be reached
raise Exception("ERROR: unreachable empty statement/block at for node at class {}".format(self.typeName)) raise Exception("ERROR: unreachable empty statement/block at for node at class {}".format(self.typeName))
return return
...@@ -5,6 +5,7 @@ from UnitNodes import ParamNode ...@@ -5,6 +5,7 @@ from UnitNodes import ParamNode
from TheTypeNode import TypeNode from TheTypeNode import TypeNode
from Environment import Env from Environment import Env
from collections import OrderedDict from collections import OrderedDict
from CodeGenUtils import p, pLabel, genProcedure
# field # field
class FieldNode(ASTNode): class FieldNode(ASTNode):
...@@ -171,13 +172,41 @@ class MethodNode(ASTNode): ...@@ -171,13 +172,41 @@ class MethodNode(ASTNode):
self.body.reachCheck(True) # For method bodies, in[L] = maybe by default self.body.reachCheck(True) # For method bodies, in[L] = maybe by default
self.outMaybe = self.body.outMaybe self.outMaybe = self.body.outMaybe
# Check if out[method body] is a maybe for non-void methods # Check if out[method body] is a maybe for non-void methods
if not self.methodType or self.myType.name == "void": # Omitting the check for constructors and void functions if not self.methodType or self.myType.name == "void": # Omitting the check for constructors and void functions
return return
if self.outMaybe: if self.outMaybe:
raise Exception("Non-void method '{}' in class '{}' does not return".format(self.name, self.typeName)) raise Exception("Non-void method '{}' in class '{}' does not return".format(self.name, self.typeName))
return return
def codeGen(self):
if hasattr(self, "code") and self.code != "":
return
self.code = pLabel(self.typeName + "_" + self.name + "_" + self.paramTypes, "method")
if self.body:
bodyCode = ""
# push all local var to stack
vars = getVarDclNodes(self.body)
for i in range(len(vars)):
vars[i].offset = i * 4 + 16
bodyCode += p("push", 0)
self.body.codeGen()
bodyCode += self.body.code
# pop off all the local var
for i in range(len(vars)):
bodyCode += p("pop", "edx")
self.code += genProcedure(bodyCode, "method definition for " + self.name)
else:
self.code += p("ret", "")
############# helper for forward ref checking ######## ############# helper for forward ref checking ########
# Input: AST Node # Input: AST Node
# Output: A list of names to be check # Output: A list of names to be check
...@@ -208,3 +237,16 @@ def getNameNodes(node): ...@@ -208,3 +237,16 @@ def getNameNodes(node):
result.extend(getNameNodes(c)) result.extend(getNameNodes(c))
return result return result
# Input: Block Node
# Output: A list of local var dcl to be pushed onto the stack
def getVarDclNodes(node):
result = []
for s in node.statements:
if s.__class__.__name__ == 'VarDclNode':
result += [s]
if s.__class__.__name__ == 'BlockNode':
result += getVarDclNodes(node)
return result
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment