import fileinput import sys, getopt import os from enum import Enum, unique import sys from JackTokenizer import JackTokenizer,TOKEN_TYPE,KEYWORD_TYPE,tokentype,tokendict from SymbolTable import SymbolTable from VmWriter import VmWriter,SEG_TYPE,OP_TYPE,opdict from CompileEngine import CompileEngine
class CompileCodeWriter: def __init__(self,infile): self.parser = JackTokenizer(infile) self.engile = CompileEngine(infile) self.out = VmWriter(infile) self.classTable = SymbolTable() self.subTable = SymbolTable() self.vmout = VmWriter(infile) self.classname = "" self.subname = "" self.subkind = "" self.subtype = "" self.iflabelcnt = 0 self.whilelabelcnt = 0 self.writeClassCode() self.out.close()
def ifLabel(self): res = [] res.append("IF_END" + str(self.iflabelcnt)) res.append("IF_" + str(self.iflabelcnt)) self.iflabelcnt += 1 return res
def whileLabel(self): res = [] res.append("WHILE_EXP" + str(self.whilelabelcnt)) res.append("WHILE_END" + str(self.whilelabelcnt)) self.whilelabelcnt += 1 return res
def functionLabel(self): return self.classname + "." + self.subname
def writeClassCode(self): self.classTable.startSubroutine() self.parser.advance() self.classname = self.parser.currToken() self.parser.advance() self.parser.advance() while self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD and \ (self.parser.keyWord() == "static" or self.parser.keyWord() == "field"): self.writeClassVarDecCode() while self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD and \ (self.parser.keyWord() == "method" or \ self.parser.keyWord() == "constructor" or \ self.parser.keyWord() == "function"): self.subkind = self.parser.keyWord() self.writeSubroutineCode() self.parser.advance()
return True
def writeClassVarDecCode(self): varname = "" vartype = "" varkind = ""
varkind = self.parser.keyWord() self.parser.advance() vartype = self.parser.currToken() self.parser.advance() varname = self.parser.currToken() self.parser.advance() self.classTable.define(varname,vartype,varkind) while not (self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ self.parser.symbol() == ";"): self.parser.advance() varname = self.parser.currToken() self.classTable.define(varname,vartype,varkind) self.parser.advance() self.parser.advance()
return True
def writeSubroutineCode(self): fieldcnt = 0 self.subTable.startSubroutine()
self.subkind = self.parser.currToken() self.parser.advance() if self.subkind == "method": self.subTable.define("this",self.classname,"argument") self.subtype = self.parser.currToken() self.parser.advance() self.subname = self.parser.currToken() self.parser.advance() self.parser.advance() self.writeParameterListCode() self.parser.advance() self.writeSubroutineBodyCode()
return True def writeSubroutineBodyCode(self): nlocals = 0 self.parser.advance() while self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD and \ self.parser.keyWord() == "var": nlocals += self.writeVarDecCode() funcname = self.classname + "." + self.subname self.out.writeFunction(funcname,nlocals) if self.subkind == "constructor": fieldcnt = self.classTable.varCount("field") self.out.writePush("constant",fieldcnt) self.out.writeCall("Memory.alloc",1) self.out.writePop("pointer",0) elif self.subkind == "method": self.out.writePush("argument",0) self.out.writePop("pointer",0)
self.writeStatementsCode() self.parser.advance() return True
def writeParameterListCode(self): varname = "" varkind = "argument" vartype = "" paramcnt = 0
while not (self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and\ self.parser.symbol() == ")"): vartype = self.parser.currToken() self.parser.advance() varname = self.parser.currToken() paramcnt += 1 self.parser.advance() self.subTable.define(varname,vartype,varkind) if self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL: if self.parser.symbol() == ",": self.parser.advance() elif self.parser.symbol() == ")": break
return paramcnt def writeVarDecCode(self): nlocals = 1 varname = "" varkind = "var" vartype = ""
varkind = self.parser.keyWord() self.parser.advance() vartype = self.parser.currToken() self.parser.advance() varname = self.parser.currToken() self.parser.advance() self.subTable.define(varname,vartype,varkind)
while not (self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ self.parser.symbol() == ";"): self.parser.advance() nlocals += 1 varname = self.parser.currToken() self.subTable.define(varname,vartype,varkind) self.parser.advance() self.parser.advance() return nlocals def writeStatementsCode(self): while self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD and \ (self.parser.keyWord() == "do" or \ self.parser.keyWord() == "if" or \ self.parser.keyWord() == "while" or \ self.parser.keyWord() == "let" or \ self.parser.keyWord() == "return"): if self.parser.keyWord() == "do": self.writeDoCode() elif self.parser.keyWord() == "if": self.writeIfCode() elif self.parser.keyWord() == "while": self.writeWhileCode() elif self.parser.keyWord() == "let": self.writeLetCode() elif self.parser.keyWord() == "return": self.writeReturnCode() else: print("valid statement define!\n") exit(1)
return True def writeDoCode(self): funcname = [] argsCnt = 0 varname = "" vartype = "" varkind = "" varidx = ""
self.parser.advance() while not (self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ self.parser.symbol() == "("): if self.parser.tokenType() != TOKEN_TYPE.TOKEN_SYMBOL: funcname.append(self.parser.currToken()) self.parser.advance()
self.parser.advance() callname = "" varname = funcname[0] if len(funcname) == 1: self.out.writePush("pointer",0) callname = self.classname + "." + funcname[0] argsCnt += 1 elif len(funcname) == 2: if self.subTable.indexOf(varname) >= 0: vartype = self.subTable.typeOf(varname) varkind = self.subTable.kindOf(varname) varidx = self.subTable.indexOf(varname) callname = vartype + "." + funcname[1] argsCnt += 1 if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) elif self.classTable.indexOf(varname) >= 0: vartype = self.classTable.typeOf(varname) varkind = self.classTable.kindOf(varname) varidx = self.classTable.indexOf(varname) callname = vartype + "." + funcname[1] argsCnt += 1 if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) else: callname = funcname[0] + "." + funcname[1] argsCnt += self.writeExpressionListCode() self.parser.advance() self.parser.advance() self.out.writeCall(callname,argsCnt) self.out.writePop("temp",0)
return True def writeLetCode(self): varname = "" vartype = "" varkind = "" varidx = "" isArray = False self.parser.advance() varname = self.parser.currToken() if self.subTable.indexOf(varname) >= 0: vartype = self.subTable.typeOf(varname) varkind = self.subTable.kindOf(varname) varidx = self.subTable.indexOf(varname) elif self.classTable.indexOf(varname) >= 0: vartype = self.classTable.typeOf(varname) varkind = self.classTable.kindOf(varname) varidx = self.classTable.indexOf(varname) else: print("invalid var statement!") return False
self.parser.advance() if self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ self.parser.symbol() == '[': isArray = True self.parser.advance() self.writeExpressionCode() if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) self.out.writeArithmetic("+") self.parser.advance()
self.parser.advance() self.writeExpressionCode() if isArray: self.out.writePop("temp",0) self.out.writePop("pointer",1) self.out.writePush("temp",0) self.out.writePop("that",0) else: if varkind == "field": self.out.writePop("this",varidx) elif varkind == "var": self.out.writePop("local",varidx) elif varkind == "static": self.out.writePop("static",varidx) elif varkind == "argument": self.out.writePop("argument",varidx) self.parser.advance() return True def writeWhileCode(self): label = self.whileLabel()
self.parser.advance() self.parser.advance() self.out.writeLabel(label[0]) self.writeExpressionCode() self.out.writeSigArithmetic("~") self.out.writeIf(label[1]) self.parser.advance() self.parser.advance() self.writeStatementsCode() self.out.writeGoto(label[0]) self.out.writeLabel(label[1]) self.parser.advance()
return True def writeReturnCode(self): self.parser.advance() if not (self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ self.parser.symbol() == ';'): self.writeExpressionCode() self.parser.advance() if self.subtype == "void": self.out.writePush("constant",0) self.out.writeReturn()
return True def writeIfCode(self): label = self.ifLabel()
self.parser.advance() self.parser.advance() self.writeExpressionCode() self.out.writeSigArithmetic("~") self.parser.advance() self.parser.advance() self.out.writeIf(label[1]) self.writeStatementsCode() self.out.writeGoto(label[0]) self.parser.advance() self.out.writeLabel(label[1]) if self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD and \ self.parser.keyWord() == "else": self.parser.advance() self.parser.advance() self.writeStatementsCode() self.parser.advance() self.out.writeLabel(label[0])
return True def writeExpressionCode(self): self.writeTermCode()
while self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ (self.parser.symbol() == "+" or self.parser.symbol() == "-" or \ self.parser.symbol() == "*" or self.parser.symbol() == "/" or \ self.parser.symbol() == "&" or self.parser.symbol() == "|" or \ self.parser.symbol() == ">" or self.parser.symbol() == "<" or \ self.parser.symbol() == "="): op = self.parser.symbol() self.parser.advance() self.writeTermCode() if op == "*": self.out.writeCall("Math.multiply",2) elif op == '/': self.out.writeCall("Math.divide",2) else: self.out.writeArithmetic(op) return True def writeTermCode(self): varname = "" vartype = "" varkind = "" varidx = 0 paramCnt = 0
if self.parser.tokenType() == TOKEN_TYPE.TOKEN_INT_CONST: self.out.writePush("constant",self.parser.intVal()) self.parser.advance() elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_STRING_CONST: val = self.parser.stringVal() self.out.writePush("constant",len(val)) self.out.writeCall("String.new",1) for c in val: self.out.writePush("constant",ord(c)) self.out.writeCall("String.appendChar",2) self.parser.advance() elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_KEYWORD: if self.parser.keyWord() == "true" or self.parser.keyWord() == "false" or \ self.parser.keyWord() == "null" or self.parser.keyWord() == "this": if self.parser.keyWord() == "true": self.out.writePush("constant",0) self.out.writeSigArithmetic("~") elif self.parser.keyWord() == "false": self.out.writePush("constant",0) elif self.parser.keyWord() == "null": self.out.writePush("constant",0) elif self.parser.keyWord() == "this": self.out.writePush("pointer",0) self.parser.advance() elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL: if self.parser.symbol() == "(": self.parser.advance() self.writeExpressionCode() self.parser.advance() elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and \ (self.parser.symbol() == "-" or self.parser.symbol() == "~"): op = self.parser.symbol() self.parser.advance() self.writeTermCode() self.out.writeSigArithmetic(op) elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_IDENTIFIER: termname = self.parser.currToken() self.parser.advance()
if self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and self.parser.symbol() == "[": if self.subTable.indexOf(termname) >= 0: vartype = self.subTable.typeOf(termname) varkind = self.subTable.kindOf(termname) varidx = self.subTable.indexOf(termname) elif self.classTable.indexOf(termname) >= 0: vartype = self.classTable.typeOf(termname) varkind = self.classTable.kindOf(termname) varidx = self.classTable.indexOf(termname) else: print("invalid var statement!") return False
self.parser.advance() self.writeExpressionCode() if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) self.out.writeArithmetic("+") self.out.writePop("pointer",1) self.out.writePush("that",0)
self.parser.advance() elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and self.parser.symbol() == ".": self.parser.advance()
termfunc = self.parser.currToken() self.parser.advance()
if self.subTable.indexOf(termname) >= 0: vartype = self.subTable.typeOf(termname) varkind = self.subTable.kindOf(termname) varidx = self.subTable.indexOf(termname) paramCnt += 1 if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) elif self.classTable.indexOf(termname) >= 0: vartype = self.classTable.typeOf(termname) varkind = self.classTable.kindOf(termname) varidx = self.classTable.indexOf(termname) paramCnt += 1 if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx) else: vartype = termname
self.parser.advance() paramCnt += self.writeExpressionListCode() self.parser.advance() self.out.writeCall(vartype + "." + termfunc,paramCnt) elif self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL and self.parser.symbol() == "(": self.parser.advance() self.out.writePush("pointer",0) paramCnt = self.writeExpressionListCode() + 1 self.parser.advance() self.out.writeCall(self.classname + "." + termfunc,paramCnt) else: if self.subTable.indexOf(termname) >= 0: vartype = self.subTable.typeOf(termname) varkind = self.subTable.kindOf(termname) varidx = self.subTable.indexOf(termname) elif self.classTable.indexOf(termname) >= 0: vartype = self.classTable.typeOf(termname) varkind = self.classTable.kindOf(termname) varidx = self.classTable.indexOf(termname) else: print("invalid var statement!") return False
if varkind == "field": self.out.writePush("this",varidx) elif varkind == "var": self.out.writePush("local",varidx) elif varkind == "static": self.out.writePush("static",varidx) elif varkind == "argument": self.out.writePush("argument",varidx)
return True def writeExpressionListCode(self): argsCnt = 0
if self.parser.symbol() == ')' and \ self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL: return argsCnt
argsCnt += 1 self.writeExpressionCode() while self.parser.symbol() == ',' and \ self.parser.tokenType() == TOKEN_TYPE.TOKEN_SYMBOL: self.parser.advance() argsCnt += 1 self.writeExpressionCode()
return argsCnt
def main(input): if os.path.exists(input): if os.path.isdir(input): files = os.listdir(input) for f in files: filename = input+f if filename.find(".jack") >= 0: CompileCodeWriter(input+f) else: CompileCodeWriter(input) else: print("invalid path")
if __name__ == "__main__": main(sys.argv[1])
|