def visitMethod_decl(self, ctx:DecafParser.Method_declContext): method_name = ctx.ID(0).getText() return_type = ctx.TYPE(0) line_number = ctx.start.line # Checks if the method has already been declared. if self.st.probe(method_name) != None: print('[Error]: The method ' + method_name + ' on line: ' + line_number + 'was already declared!') else: self.body += method_name self.body += ':\n' params = [] # Loops through paramaters and creates a var symbol for them and appends them to a list. if len(params) > 1: for param in range(len(ctx.ID())): param_name = ctx.ID(param).getText() params.append(param_name) var_symbol = self.st.probe(param_name) if var_symbol == None: var_symbol = VarSymbol(id=param_name, type='int', line=ctx.start.line, size=8, mem=self.st.stack_pointer) self.st.addSymbol(var_symbol) var_addr = var_symbol.getAddr() self.body += '\tmovq %rax, -' + str(var_addr[0]) + '(%rsp)\n' params.pop(0) method_symbol = MethodSymbol(id=method_name, type=return_type, line=line_number, params=params) self.st.addSymbol(method_symbol) visit = self.visitChildren(ctx) return visit
def visit_ProcedureDecl(self, node): proc_name = node.proc_name proc_symbol = ProcedureSymbol(proc_name) self.current_scope.insert(proc_symbol) print('ENTER scope: %s' % proc_name) # Scope for parameters and local variables procedure_scope = ScopedSymbolTable( scope_name=proc_name, scope_level=self.current_scope.scope_level + 1, enclosing_scope=self.current_scope) self.current_scope = procedure_scope # Insert parameters into the procedure scope for param in node.params: param_type = self.current_scope.lookup(param.type_node.value) param_name = param.var_node.value var_symbol = VarSymbol(param_name, param_type) self.current_scope.insert(var_symbol) proc_symbol.params.append(var_symbol) self.visit(node.block_node) print(procedure_scope) self.current_scope = self.current_scope.enclosing_scope print('LEAVE scope: %s' % proc_name)
def visitField_decl(self, ctx:DecafParser.Field_declContext): line_num = ctx.start.line data_type = ctx.data_type().getText() field_decls = ctx.field_arg() for f in field_decls: array_size = 0 field_symbol = self.st.probe(f.getText()) if f.int_literal() != None: array_size = f.int_literal().getText() if int(array_size) <= 0: print('Error on line', line_num,', array \'', f.ID().getText(),'\' must have a declaration value greater than 0') if field_symbol != None: print('Error on line', line_num,', variable \'', f.ID().getText(),'\' has already been declared on line',field_symbol.line) else: field_symbol = VarSymbol(id=f.ID().getText(), type=data_type, line=line_num, size=8, mem=HEAP) self.st.addSymbol(field_symbol) self.visitChildren(ctx)
def visit_FunctionDecl(self, node): func_name = node.func_name type_name = node.return_type.value type_symbol = self.current_scope.lookup(str.upper(type_name)) func_symbol = FunctionSymbol(func_name, type_symbol) self.current_scope.insert(func_symbol) print('ENTER scope: %s' % func_name) # Scope for parameters and local variables function_scope = ScopedSymbolTable( scope_name=func_name, scope_level=self.current_scope.scope_level + 1, enclosing_scope=self.current_scope) self.current_scope = function_scope # Insert parameters into the function_scope for param in node.params: param_type = self.current_scope.lookup( str.upper(param.type_node.value)) param_name = param.var_node.value var_symbol = VarSymbol(param_name, param_type) self.current_scope.insert(var_symbol) func_symbol.params.append(var_symbol) self.visit(node.block_node) print(function_scope) self.current_scope = self.current_scope.enclosing_scope print('LEAVE scope: %s' % func_name)
def visitVar_decl(self, ctx: DecafParser.Var_declContext): line_num = ctx.start.line var_ids = ctx.ID() data_type = ctx.data_type().getText() for v in var_ids: id_symbol = self.st.probe(v.getText()) if id_symbol != None: # 1 print('Error on line ' + str(line_num) + ', variable \'' + v.getText() + '\' has already been declared on line ' + str(id_symbol.line)) else: id_symbol = VarSymbol(id=v.getText(), type=data_type, line=line_num, size=8, mem=STACK) self.st.addSymbol(id_symbol) self.visitChildren(ctx)
def visitMethod_decl(self, ctx: DecafParser.Method_declContext): line_num = ctx.start.line method_name = ctx.ID(0).getText() method_type = ctx.return_type().getText() method_params = [] for i in range(len(ctx.data_type())): param_type = ctx.data_type(i).getText() param_name = ctx.ID(i + 1).getText() param_symbol = VarSymbol(id=param_name, type=param_type, line=line_num, size=8, mem=STACK) method_params.append(param_symbol) method_symbol = MethodSymbol(method_name, method_type, line_num, method_params) self.st.addSymbol(method_symbol) self.body += method_name + ':\n' if method_name == 'main': self.body += 'movq %rsp, %rbp\n' self.st.enterScope() for i in range(len(method_params)): self.st.addSymbol(method_params[i]) self.body += 'movq ' + param_registers[i] + ',' + str(method_params[i].getAddr()) + '(%rsp)\n' self.visitChildren(ctx) self.body += 'ret\n' self.st.exitScope()
def visitField_decl(self, ctx: DecafParser.Field_declContext): line_num = ctx.start.line data_type = ctx.data_type().getText() field_count = len(ctx.field_name()) for i in range(field_count): field_name = ctx.field_name(i).getText() if ctx.field_name(i).int_literal(): array_size = int(ctx.field_name(i).int_literal().getText()) if array_size <= 0: print('Error on line', line_num, 'array declared with length 0') else: array_size = 1 field_symbol = self.st.probe(field_name) if field_symbol: print('Error on line', line_num, 'field', field_name, 'is already declared on line', field_symbol.line) else: field_symbol = VarSymbol(id=field_name, type=data_type, line=line_num, size=8 * array_size, mem=HEAP) self.st.addSymbol(field_symbol) self.visitChildren(ctx)
def visitVar_decl(self, ctx:DecafParser.Var_declContext): # Loops through all variables (to evaluate int x, y, z for example.) for i in range(len(ctx.ID())): var_name = ctx.ID(i).getText() var_symbol = self.st.probe(var_name) if "[" in var_name: array_var_name = ctx.ID(i).getText() split_var = array_var_name.split('[', 1)[0] else: if var_symbol == None: var_symbol = VarSymbol(id=var_name, type='int', line=ctx.start.line, size=8, mem=self.st.stack_pointer) self.st.addSymbol(var_symbol) var_addr = var_symbol.getAddr() self.body += '\tmovq %rax, -' + str(var_addr[0]) + '(%rsp)\n' else: print('[Error]:', var_symbol.id + ', declared on line', ctx.start.line, 'has already been declared on line', var_symbol.line) visit = self.visitChildren(ctx) return visit
def visit_VarDecl(self, node): type_name = node.type_node.value type_symbol = self.current_scope.lookup(type_name) # We have all the information we need to create a variable symbol. # Create the symbol and insert it into the symbol table. var_name = node.var_node.value var_symbol = VarSymbol(var_name, type_symbol) # Signal an error if the table alrady has a symbol # with the same name if self.current_scope.lookup(var_name, current_scope_only=True): raise Exception("Error: Duplicate identifier '%s' found" % var_name) self.current_scope.insert(var_symbol)
def visit_VarDecl(self, node): type_name = node.type_node.value type_symbol = self.current_scope.lookup(type_name) var_name = node.var_node.value var_symbol = VarSymbol(var_name, type_symbol) if(self.current_scope.lookup(var_name, current_scope_only=True) is not None): raise NameError("Cannot initialize a variable that has already been declared '" + str(var_name) + "' on line: " + str(node.token.get_line())) self.current_scope.insert(var_symbol) if(node.assign_node): self.visit(node.assign_node) return var_symbol
def visitVardeclr(self, ctx: DecafParser.VardeclrContext): vtype = None vid = None for i in ctx.children: tkn = i.getText() if tkn == 'int' or tkn == 'boolean': vtype = tkn elif tkn == ',' or tkn == ';': continue elif tkn != None: vid = tkn if self.st.probe(vid) != None: raiseErr("Variable " + vid + " already declared in scope.", ctx) self.st.addSymbol(VarSymbol(vid, vtype, 0, 8, 0)) return self.visitChildren(ctx)
def visitVar_decl(self, ctx: DecafParser.Var_declContext): # semantic rule: No identifier is declared twice in the same scope # test with testdata/semantics/illegal-01.dcf line_num = ctx.start.line for var_decl in ctx.ID(): var_name = var_decl.getText() # gets the variable name (eg. x) var_symbol = self.st.probe( var_name) # search Symbol Table for variable entry if var_symbol != None: # if variable does NOT exist in Symbol Table print('Error on line', line_num, 'variable \'', var_name, '\' already declared on line', var_symbol.line) else: var_symbol = VarSymbol(id=var_name, type='int', line=line_num, size=8, mem=STACK) self.st.addSymbol( var_symbol ) # add var_symbol to the scope (st abbreviation of SymbolTable) return self.visitChildren(ctx)
def visitMethod_arg(self, ctx: DecafParser.Method_argContext): line_num = ctx.start.line data_type = ctx.data_type().getText() var_decls = ctx.ID().getText() var_symbol = self.st.probe(var_decls) if var_symbol != None: # 1 print( 'Error on line', line_num, ', variable \'', var_decls, '\' has already been declared on line ' + str(var_symbol.line)) else: print(var_decls) var_symbol = VarSymbol(id=var_decls, type=data_type, line=line_num, size=8, mem=STACK) self.st.addSymbol(var_symbol) self.visitChildren(ctx)
def visitMethod_decl(self, ctx:DecafParser.Method_declContext): data_type = "" line_num = ctx.start.line method_name = ctx.ID().getText() method_args = ctx.method_arg() method_params = [] if ctx.data_type() != None: data_type = ctx.data_type().getText() else: data_type = "void" for i in method_args: arg_type = i.data_type().getText() method_arg = VarSymbol(id=i.ID().getText(), type=arg_type, line=line_num, size=8, mem=STACK) method_params.append(method_arg) method_symbol = MethodSymbol(id=method_name, type=data_type, line=line_num, params=method_params) self.body += method_name + ':\n' if method_name == 'main': self.body += 'movq %rsp, %rbp\n' self.st.enterScope() for i in range(len(method_params)): self.st.addSymbol(method_params[i]) #Saving each method parameter onto a location on the stack(Memory) self.body += 'movq ' + param_registers[i] + ',' + str(method_params[i].getAddr()) + '(%rsp)\n' self.visitChildren(ctx) self.body += 'ret\n' self.st.exitScope()
def visitField_decl(self, ctx:DecafParser.Field_declContext): for i in range(len(ctx.field_name())): var_name = ctx.field_name(i).getText() var_symbol = self.st.probe(var_name) # Declaration is an array. if "[" in var_name: array_var_name = ctx.field_name(i).getText() split_var = array_var_name.split('[', 1)[0] if var_symbol == None: var_symbol = VarSymbol(id=split_var, type='int', line=ctx.start.line, size=8, mem=self.st.stack_pointer) self.st.addSymbol(var_symbol) var_addr = var_symbol.getAddr() self.body += '\tmovq %rax, -' + str(var_addr[0]) + '(%rsp)\n' else: if var_symbol == None: var_symbol = VarSymbol(id=var_name, type='int', line=ctx.start.line, size=8, mem=self.st.stack_pointer) self.st.addSymbol(var_symbol) var_addr = var_symbol.getAddr() self.body += '\tmovq %rax, -' + str(var_addr[0]) + '(%rsp)\n' else: print('[Error]:', var_symbol.id + ', declared on line', ctx.start.line, 'has already been declared on line', var_symbol.line) visit = self.visitChildren(ctx) return visit
def visitVar_decal(self, ctx: DecafParser.Var_decalContext): line_number = ctx.start.line var_name = ctx.var_name(0).id(0).getText() var_value = ctx.var_value() if self.st.lookup(var_name) != None: if self.st.lookup(var_name).type == "array" and ctx.assign_op: value = var_value.getText() """ check if an array is being evaluated to anything but an array """ try: if self.st.lookup(value).type != "int": print( "ERROR: cannot evaluate array to int, line number:", line_number) else: int(value) except: print("ERROR: cannot evaluate array to int, line number:", line_number) """ check if a varible is decalred twice """ if "=" in ctx.getText(): pass else: if self.st.probe(var_name) != None: print("ERROR: varible", "'" + var_name + "'", "decalred twice", " on line", line_number) else: for i in range(len(ctx.var_name())): if "[" in var_name: Feild_decalsysmbol = VarSymbol( id=var_name.id().getText(), type="array", line=line_number, size=8, mem=SymbolTable.HEAP) self.st.addSymbol(Feild_decalsysmbol) else: if ctx.var_type(0) != None: Feild_decalsysmbol = VarSymbol( id=ctx.var_name(i).id(0).getText(), type=ctx.var_type(0).getText(), line=line_number, size=8, mem=SymbolTable.STACK) self.st.addSymbol(Feild_decalsysmbol) VarNames = ctx.var_name() for i in range(len(VarNames)): for j in range(i + 1, len(VarNames)): if VarNames[i].getText() == VarNames[j].getText(): print("ERROR: varible", "'" + VarNames[i].getText() + "'", "decalred twice", " on line", line_number) else: for k in VarNames: Feild_decalsysmbol = VarSymbol(id=k, type=type, line=ctx.var_type(i), size=8, mem=SymbolTable.STACK) self.st.addSymbol(Feild_decalsysmbol) if ctx.assign_op() != None: """var_name_type = self.st.lookup(var_name).type""" """ check that the operands of "+=" and -= is not a boolean or int """ if "+=" in ctx.assign_op().getText() or "-=" in ctx.assign_op( ).getText(): for items in ctx.var_name(): var_name = items.getText() var_name_type = self.st.lookup(var_name).type if var_name_type == "boolean": if ctx.var_value().getText( ) == "true" or ctx.var_value().getText() == "false": print( "ERROR: cannot assign boolean here, line number:", line_number) else: var_name_type = self.st.lookup(var_name).type var_value_type = self.st.lookup( var_value.id().getText()).type if var_name_type and var_value_type != "int": print( "ERROR: type int must be used when using", ctx.assign_op().getText(), "line number", line_number) else: if self.st.lookup(var_value.id()) != None: """ check a var_name is being assinged to the same type of var_value """ if self.st.lookup(var_name).type != self.st.lookup( var_value.id().getText()).type: var_name_type = self.st.lookup(var_name).type var_value_type = self.st.lookup( var_value.id().getText()).type print("cannot assign", var_name_type, "to", var_value_type) else: if self.st.lookup(var_name) != None: if self.st.lookup(var_name).type == "int": try: int(var_value.getText()) except: pass #var_name_type = self.st.lookup(var_name).type #print("cannot assign", var_name_type,"to this type here", line_number ) if ctx.var_name(0).expr() != None: exprID = ctx.var_name(0).expr().getText() exprType = self.st.lookup(exprID).type """ check the type of expression as it must be int """ if exprType != "int": print( "ERROR: expected int, got " + exprType + " instead, line number:", line_number) """ check if an array has an int and not any other type """ if "[" in ctx.var_name(0).getText(): if self.st.lookup(var_name).type != "array": errorType = self.st.lookup(var_name).type print("ERROR: varible needs to be an array type not", errorType, "on line", line_number) """ check var name existed before it assinged """ if var_name: var_symbol = self.st.lookup(var_name) if var_symbol != None: for i in range(len(ctx.var_name())): if "=" in ctx.getText(): #get var_name from the text var_name = ctx.var_name(i).id(0).getText() #get symbol of vars from symbol table var_symbol = self.st.lookup(var_name) #get address of symbol var_addr = var_symbol.getAddr() self.body += 'movq ' + str(var_addr) + '(%rsp), %rax\n' else: print( "ERROR:", "varible referanced but never assinged " + "'" + var_name + "' " + "on line", line_number) if var_value != None: var_value = var_value.getText() if '()' in var_value: var_value = self.st.lookup(var_value) if var_symbol != None: pass else: print( "ERROR:", "varible referanced but never assinged " + "'" + var_name + "' " + "on line", line_number) return self.visitChildren(ctx)
def visitFeild_decal(self, ctx: DecafParser.Feild_decalContext): """ line_number is used in all further methods, it is used to get the line number which something is written on """ line_number = ctx.start.line Feildtype = ctx.field_type().getText() """get the id of the vield decal""" feildVarName = ctx.feild_name(0).id().getText() """get the field name to check if it already exisits""" VarName = ctx.feild_name(0) if self.st.probe(feildVarName) != None: print("ERROR: varible", "'" + feildVarName + "'", "decalred twice", " on line", line_number) else: """check if the var_name contains a [ is it does then it's a array varible """ if "[" in VarName.getText(): int_litereal = None for i in range(len(ctx.feild_name())): int_litereal = ctx.feild_name(i).int_litereal() if int_litereal != None: int_litereal = int_litereal.getText() """check that the int litereal is bigger than zero""" if int(int_litereal) > 0: """if everything is samanticly valid add the array to the symbol table""" Feild_decalsysmbol = VarSymbol( id=VarName.id().getText(), type="array", line=line_number, size=8, mem=SymbolTable.HEAP) self.st.addSymbol(Feild_decalsysmbol) else: print( "ERROR: arrays of length zero are not allowed" + ", line", line_number) else: Feild_decalsysmbol = VarSymbol(id=feildVarName, type=Feildtype, line=line_number, size=8, mem=SymbolTable.HEAP) self.st.addSymbol(Feild_decalsysmbol) val = self.visitChildren(ctx) feildVarNames = ctx.feild_name() """ loop through the array of all feild decals and check if any of them have already decalred by comparing the all of the field names againt each other """ for i in range(len(feildVarNames)): for j in range(i + 1, len(feildVarNames)): if feildVarNames[i].getText() == feildVarNames[j].getText(): print("ERROR: varible", "'" + feildVarNames[i].getText() + "'", "decalred twice", " on line", line_number) else: """if everything is valid add to symbol table""" for k in feildVarNames: Feild_decalsysmbol = VarSymbol(id=k, type=Feildtype, line=line_number, size=8, mem=SymbolTable.HEAP) self.st.addSymbol(Feild_decalsysmbol) return val
def visitMethod_decl(self, ctx: DecafParser.Method_declContext): self.params param_types = [] ctx.method_param_type() #line used for debugging #print(ctx.method_param_type(0).getText()) method_name = ctx.id(0).getText() return_type = ctx.method_type().getText() line_number = ctx.start.line for i in range(len(ctx.method_param_type())): param_types.append(ctx.method_param_type(i).getText()) for i in range(len(ctx.method_Param_names())): self.params.append(ctx.method_Param_names(i).getText()) #line used for debugging #print(ctx.method_Param_names(0).getText()) for i in range(len(param_types)): if self.params == []: method_params = VarSymbol(id=self.params[i], type=param_types[i], line=line_number, size=8, mem=SymbolTable.STACK) self.st.addSymbol(method_params) else: method_params = VarSymbol(id=self.params[i], type=param_types[i], line=line_number, size=8, mem=SymbolTable.STACK) self.st.addSymbol(method_params) method_symbol = MethodSymbol(id=method_name, type=return_type, line=line_number, params=ctx.method_Param_names()) self.st.addSymbol(method_symbol) if self.st.lookup(method_name) != None: for i in range(len(self.st.lookup(method_name).params)): method_params = VarSymbol( id=ctx.method_Param_names(i).getText(), type=ctx.method_param_type(i).getText(), line=line_number, size=8, mem=SymbolTable.STACK) self.st.addSymbol(method_params) """don't add main to code more than once""" if "main" in method_name: pass else: self.body += method_name + ":" + "\n" """get the statment in the return statment""" returnStatment = ctx.block().statement() if returnStatment != None: for item in returnStatment: if "if" in item.getText(): pass elif "return" in item.getText(): if self.st.lookup(item.expr(0)) == None: """if return of method is void then throw and error""" if return_type == "void": print("method on line:", line_number, "should not return anything") elif return_type == "int": """try to int the expr, if that fails throw an error""" try: int(item.expr(0).getText()) except: print( "ERROR: wrong return type found for method on line:", line_number) elif self.st.lookup( item.expr(0).getText()).type != return_type: print( "ERROR: type of retrun statement does not match method return type, line number:", line_number) else: Addr = self.st.lookup( item.expr(0).getText()).getAddr() self.st.stack_pointer[-1] += 8 self.body += 'movq %rax, ' + str( -self.st.stack_pointer[-1]) + '(%rsp)\n' self.body += "movq " + str( Addr) + " (%rbp), " + " %rax" + "\n" "" if return_type == "int" and returnStatment == []: print("ERROR: method missing return statement", line_number) if return_type == "boolean" and returnStatment == []: print("ERROR: method missing return statement", line_number) return self.visitChildren(ctx)