def Return(token): if len(returnList): returnList[-1][2] = 1 token = lexer.peekNextToken() if token[1] == ";" and token[0] == "symbol": lexer.getNextToken() # consume the token # No value to be returned, just push const 0 text("push constant 0") if lexer.peekNextToken()[1] != "}": Error(token, "Unreachable code") elif token[0] in ["id", "number"]: # Return expression returnData = symbolTable.orderExpr("return") if not returnData[0]: return returnData elif token[1] == "this": text("push pointer 0") else: Error( token, "Unexpected token of type '" + token[0] + "' cannot be returned.") text("return") return [1]
def F(): global token if token.token_id == Token_ENUM.TK_LEFT_PAR: token = getNextToken() e = E() if token.token_id != Token_ENUM.TK_RIGHT_PAR: raise ValueError("Expecting right parenthesis ')', but found ", token.lexema) token = getNextToken() return F_prime(e) else: r = R() return F_prime(r)
def R(): global token if token.token_id != Token_ENUM.TK_DIGIT and token.token_id != Token_ENUM.TK_LETTER: raise ValueError("Expecting a letter or digit, but found ", token.lexema, token.token_id) if token.token_id == Token_ENUM.TK_DIGIT: digit = Digit(int(token.lexema)) token = getNextToken() return digit elif token.token_id == Token_ENUM.TK_LETTER: letter = Letter(token.lexema) token = getNextToken() return letter
def setObjectArgs(attribute): # Log bracket count when entering a function so you can later tell when the function is exited # function name, bracket pointer, value returned returnList.append( [symbolTable.objectName, symbolTable.bracketPointer[0], 0]) token = lexer.getNextToken() if token[1] != "(" and token[0] != "symbol": Error(token, "Expected '('") peekToken = lexer.peekNextToken() if peekToken[1] == ")" and peekToken[ 0] == "symbol": # Check if function has no arguments lexer.getNextToken() # Consume the token else: # Check syntax of function arguments expectedTypeList = [["keyword", "id"], ["id"], ["symbol"]] expectedTypePointer = 0 while token[1] != ")": token = lexer.getNextToken() if token[0] not in expectedTypeList[expectedTypePointer]: Error(token, "Expected a type followed by a variable name") elif expectedTypePointer == 0: pass elif expectedTypePointer == 1: # add variable to symbol table symbolTable.addSymbol(type="argument", attribute=attribute, symbol=token[1], scope="") elif expectedTypePointer == 2: if not token[1] in [",", ")"]: Error(token, "Expected ')' or ',' in parameters list") # incriment pointer expectedTypePointer += 1 if expectedTypePointer == 3: expectedTypePointer = 0 token = lexer.peekNextToken() if token[1] != "{" and token[0] != "symbol": Error(token, "Expected '{'") return [1]
def parseFile(): # Generate a list of methods to later be used in function calls token = lexer.peekNextToken() while (token[0] != "EOF"): if token[1] == "method": lexer.peekNextToken() # consume symbolTable.methodList.append(lexer.peekNextToken()[1]) token = lexer.peekNextToken() # Begin main parsing of file token = lexer.getNextToken() while (token[0] != "EOF"): stmt(token) token = lexer.getNextToken()
def createVar(token, attribute, context): # Check syntax of variables and add them to the symbol table tokenSwitch = 1 # Switch between checking for id and symbol with each loop while token[1] != ";": token = lexer.getNextToken() if token[1] != ";": if tokenSwitch: if token[0] != "id": Error(token, "Identifier expected") else: if objectType == "": # If refrenced from static context symbolTable.addSymbol(type=context, attribute=attribute, symbol=token[1], scope=symbolTable.objectName) else: symbolTable.addSymbol(type="local", attribute=attribute, symbol=token[1], scope=symbolTable.objectName) tokenSwitch = 0 else: if token[0] != "symbol" and token[1] != ",": Error(token, "Symbol expected") else: tokenSwitch = 1 return [1]
def method(token): # Check method is of correct type global objectType objectType = "method" token = lexer.getNextToken() if not token[1] in [ "int", "boolean", "char", "void", symbolTable.className ] and token[0] != "keyword": # Class name can be used in constructors return [0, "Invalid method declaration of type " + str(token[1])] attribute = token[1] setObjectName() symbolTable.symbolIndexList = [ [], [] ] # Reset symbolIndexList on creation of new object #Function header is the first argument to be added to the symbol table symbolTable.addSymbol(type="argument", attribute=attribute, symbol=symbolTable.className + "." + symbolTable.objectName, scope=symbolTable.objectName) # Push argument text("push argument 0") text("pop pointer 0") return setObjectArgs(attribute)
def parse(text): setInput(text) global token token = getNextToken() return E() if token.token_id != Token_ENUM.TK_EOF: raise ValueError("Input not parsed entirely.")
def setObjectName(): # Check function has appropriate type and name token = lexer.getNextToken() if token[0] != "id": Error(token, "Expected 'id'") # Reset counter and set new name on entry to new object symbolTable.objectName = token[1] symbolTable.labelCounter = [0, 0, 0] # Get number of declared variables in function while (token[1] != "{"): # loop to start of function token = lexer.peekNextToken() if token[0] == "EOF": Error(token, "Unexpected EOF") # Loop to end of the function # Incriment variable counter each time one is encountered bCount = 1 varCount = 0 while bCount: token = lexer.peekNextToken() if token[1] == "var": token = lexer.peekNextToken() # Consume data type # Check syntax of variables and add them to the symbol table tokenSwitch = 1 # Switch between checking for id and symbol with each loop while token[1] != ";": token = lexer.peekNextToken() if token[1] != ";": if tokenSwitch: if token[0] != "id": Error(token, "Expected token of type 'identifier'") else: varCount += 1 tokenSwitch = 0 else: if token[0] != "symbol" and token[1] != ",": Error(token, "Expected ','") else: tokenSwitch = 1 if token[0] == "EOF": Error(token, "Unexpected EOF") if token[1] == "{": bCount += 1 elif token[1] == "}": bCount -= 1 if token[0] == "EOF": Error(token, "Unexpected EOF") text("function " + symbolTable.className + "." + symbolTable.objectName + " " + str(varCount))
def F_prime(var): global token if token.token_id == Token_ENUM.OP_KLEENE: token = getNextToken() kleene = Kleene(var) return F_prime(kleene) else: #epsilon return var
def var(token): token = lexer.getNextToken() if not token[1] in ["int", "boolean", "char", "void", "Array" ] and token[0] != "id": return [0, "declared variable is of invalid type"] attribute = token[1] return createVar(token, attribute, 0)
def E_prime(var): global token if token.token_id == Token_ENUM.OP_OR: token = getNextToken() t = T() or_st = Or(var, t) return E_prime(or_st) else: #epsilon return var
def T_prime(var): global token if token.token_id == Token_ENUM.OP_CONCAT: token = getNextToken() f = F() concat_st = Concat(var, f) return T_prime(concat_st) else: #epsilon return var
def Class(token): token = lexer.getNextToken() if token[0] != "id": Error(token, "Expected 'id'") else: symbolTable.className = token[1] if lexer.peekNextToken()[1] != "{": Error(token, "Expected '{'") return [1]
def let(token): token = lexer.getNextToken() if token[0] != "id": return [0, "Expected 'id'"] peekToken = lexer.peekNextToken() if peekToken[1] == "[" and peekToken[0] == "symbol": # Check if array expr = [token] # Stores list of tokens in expression lexer.getNextToken() # consume token expr[-1][0] = "array" expr[-1][1] = [copy.copy(expr[-1]), []] # store function with arguments bCount = 1 while bCount: # Exit on obtaining all parameters token = lexer.getNextToken() if token[1] == "[" and token[0] == "symbol": bCount += 1 elif token[1] == "]" and token[0] == "symbol": bCount -= 1 if bCount: expr[-1][1][1].append(token) token = lexer.peekNextToken() # Revert peek symbolTable.arrayLetSwitch = 1 symbolTable.expressionToCode(expr) symbolTable.arrayLetSwitch = 0 getToken = lexer.getNextToken() if getToken[1] != "=" and getToken[0] != "operator": return [0, "Expected '='"] returnData = symbolTable.orderExpr("let") if not returnData[0]: return returnData text("pop temp 0") text("pop pointer 1") text("push temp 0") text("pop that 0") else: popData = symbolTable.pushPop(token) getToken = lexer.getNextToken() if getToken[1] != "=" and getToken[0] != "operator": return [0, "Expected '='"] returnData = symbolTable.orderExpr("let") if not returnData[0]: return returnData text("pop " + popData[0] + " " + str(popData[1])) return [1]
def constructor(token): # Check function is of correct type global objectType objectType = "constructor" token = lexer.getNextToken() if not token[1] == symbolTable.className: return [0, "Invalid method declaration of type " + str(token[1])] attribute = token[1] setObjectName() text("push constant " + str(symbolTable.staticVarCount)) # Alloc memory text("call Memory.alloc 1") text("pop pointer 0") return setObjectArgs(attribute)
def function(token): global objectType objectType = "function" symbolTable.symbolIndexList = [ [], [] ] # Reset symbolIndexList on creation of new object # Check function is of correct type token = lexer.getNextToken() if not token[1] in [ "int", "boolean", "char", "void", symbolTable.className ] and token[0] != "keyword": # Class name can be used in constructors return [0, "Invalid method declaration of type " + str(token[1])] attribute = token[1] setObjectName() return setObjectArgs(attribute)
def boolean(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "boolean")
def getNextToken(self, code): return lexer.getNextToken(code)
def int(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "int")
def void(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "void")
def static(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "static")
def field(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "field")
def char(token): token = lexer.getNextToken() attribute = token[1] return createVar(token, attribute, "char")
def orderExpr(exprType): ''' Obtains a list of tokens which comprise an expression ''' # Perform checks on the expression and wrap it up into a list bracketOpenCount = 0 expr = [] # Stores list of tokens in expression token = lexer.peekNextToken() errorToken = token # Hold current token for later error calls if exprType in ["if", "while"]: ending = "{" elif exprType in ["let", "do"]: ending = ";" elif exprType in ["return"]: ending = ";" token = [token[0], "return", token[2]] while token[1] != ending: token = lexer.getNextToken() # Consume token if token[0] == "EOF": Error(errorToken, "Unexpected EOF") expr.append(token) # Insure matching number of parenthesis if token[0] == "symbol" and token[1] == "(": bracketOpenCount += 1 elif token[0] == "symbol" and token[1] == ")": bracketOpenCount -= 1 if bracketOpenCount == -1: Error(errorToken, "Mismatched number of parenthesis") lastToken = token token = lexer.peekNextToken() # Check if next token implies the current token is a function call if lastToken[0] == "id" and (token[1] == "(" and token[0] == "symbol"): lexer.getNextToken() # consume token expr[-1][0] = "function" expr[-1][1] = [copy.copy(expr[-1]), []] # store function with arguments bCount = 1 while bCount: # Exit on obtaining all parameters token = lexer.getNextToken() if token[1] == "(": bCount += 1 elif token[1] == ")": bCount -= 1 if bCount: expr[-1][1][1].append(token) token = lexer.peekNextToken() # Revert peek # Check if next token implies the current token is array elif lastToken[0] == "id" and (token[1] == "[" and token[0] == "symbol"): lexer.getNextToken() # consume token expr[-1][0] = "array" expr[-1][1] = [copy.copy(expr[-1]), []] # store function with arguments bCount = 1 while bCount: # Exit on obtaining all parameters token = lexer.getNextToken() if token[1] == "[" and token[0] == "symbol": bCount += 1 elif token[1] == "]" and token[0] == "symbol": bCount -= 1 if bCount: expr[-1][1][1].append(token) token = lexer.peekNextToken() # Revert peek return runExpr(expr)