def _visit_func_decl(self, node: ASTNode): # Only for member function node.record = Record( node.children[0].token.lexeme, SymbolType(node.children[2].token.lexeme, []), RecordType.FUNCTION, node.children[0].token.location, params=[param.record for param in node.children[1].children], )
def _visit_func_param(self, node: ASTNode): node.record = Record( node.children[1].token.lexeme, # ID SymbolType( node.children[0].token.lexeme, [child.token for child in node.children[2].children], ), RecordType.PARAM, node.children[1].token.location, )
def _visit_var_decl(self, node: ASTNode): node.record = Record( node.children[1].token.lexeme, # ID SymbolType( node.children[0].token.lexeme, [child.token for child in node.children[2].children], ), None, node.children[1].token.location, )
def _visit_main(self, node: ASTNode): table = SymbolTable("main") for child in node.children[0].children: # Locals table.insert(child.record) node.record = Record( "main", SymbolType("void", []), RecordType.FUNCTION, node.token.location, params=[], table=table, )
def _visit_func_def(self, node: ASTNode): name = node.children[1].token.lexeme table = SymbolTable(name, is_function=True) params = [param.record for param in node.children[2].children] for param in params: table.insert(param) for child in node.children[4].children: # Locals table.insert(child.record) node.record = Record( name, SymbolType(node.children[3].token.lexeme, []), RecordType.FUNCTION, node.children[1].token.location, params=params, table=table, ) scope = node.children[0].token if scope: parent = BaseType(scope.lexeme).table if not parent: self.error( 'Use of undeclared class "{name}"'.format( name=scope.lexeme), scope.location, ) return records = parent.entries.get(name, []) record = next( (r for r in records if r.record_type == RecordType.FUNCTION and equal_params(r.params, params) and r.type.base is node.record.type.base), None, ) if not record: self.error( 'Member function "{scope}::{name}{type}" is defined but has not been declared' .format(scope=scope.lexeme, name=name, type=node.record.format_type()), scope.location, ) return record.table = table # Attach table on existing record in the class table table.inherits = [BaseType(scope.lexeme)] table.name = scope.lexeme + "::" + table.name node.record = record else: GLOBALS.insert(node.record)
def _visit_class_decl(self, node: ASTNode): name = node.children[0].token.lexeme table = SymbolTable( name, [ BaseType(inherit.token.lexeme) for inherit in node.children[1].children ], ) for child in node.children[2].children: # Members table.insert(child.record) node.record = Record(name, None, RecordType.CLASS, node.children[0].token.location, table=table)
def _type_for_data_member( self, node: ASTNode, types: List[SymbolType], records: List[Record], is_first: bool, ) -> SymbolType: token = node.children[0].token record = next( (r for r in records if r.record_type in DATA_RECORD_TYPES), None, ) if record is None: self.error( 'Use of undeclared {type} "{name}"'.format( type="local variable" if is_first else "data member", name=token.lexeme, ), token.location, ) return None index_types = types or [] if len(index_types) > len(record.type.dims) or any( type_ != SymbolType(INT, []) for type_ in index_types): self.error( 'Invalid indexing for "{name}", type is "{type}"'.format( name=token.lexeme, type=record.format_type()), token.location, ) return None if index_types: # Reserve space for offset calculation node.temp_record = Record("", SymbolType(INT, []), RecordType.TEMP, None) self.scope.insert(node.temp_record) node.record = record return SymbolType(record.type.base, record.type.dims[len(index_types):])
def _temp_record(self, type_, node): if type_: node.record = Record("", type_, RecordType.TEMP, None) self.scope.insert(node.record)
def _visit_var(self, node: ASTNode): first_record = node.children[0].record record = Record( "", first_record.type, RecordType.TEMP, first_record.location, ) if first_record.record_type == RecordType.DATA: node.temp_record = Record( "", first_record.type, RecordType.TEMP, first_record.location, ) node.temp_record.offset = 8 for child in node.children: if child.node_type == GroupNodeType.DATA_MEMBER: record.offset += child.record.offset index_list = child.children[1] if index_list.children: # Array indexing offset_code = [] with self.register() as ofs_reg, self.register( ) as tmp_reg: op, start_addr = "addi", ["r14", str(-record.offset)] if node.temp_record: op, start_addr = ( "lw", [str(-node.temp_record.offset) + "(r14)"], ) elif child.record.is_pointer(): op, start_addr = "lw", [ child.record.memory_location() ] _add_line(offset_code, op, [ofs_reg, *start_addr]) for i, index in enumerate(index_list.children): node.code += index.code self.load_in_reg(offset_code, index, tmp_reg) _add_line( offset_code, "muli", [ tmp_reg, tmp_reg, str(child.record.type.mul_for_dim(i)), ], ) _add_line(offset_code, "sub", [ofs_reg, ofs_reg, tmp_reg]) _add_line( offset_code, "sw", [child.temp_record.memory_location(), ofs_reg], ) node.code += offset_code record.offset = 0 node.temp_record = child.temp_record else: offset = 8 # Leave space for return value and r15 in stack frame offset += self.scope.current_size() if "::" in child.record.table.name: # Add `this` pointer with self.register() as register: if node.temp_record: _add_line( node.code, "lw", [register, node.temp_record.memory_location()], ) _add_line( node.code, "addi", [register, register, str(-record.offset)], ) else: _add_line( node.code, "addi", [register, "r14", str(-record.offset)], ) _add_line( node.code, "sw", [str(-offset) + "(r14)", register], ) offset += 4 for arg in child.children[1].children: # Handle arguments node.code += arg.code with self.register() as register: if arg.record and arg.record.type.is_complex(): # Pass complex arguments as pointers _add_line( node.code, "addi", [register, "r14", str(-arg.record.offset)], ) else: self.load_in_reg(node.code, arg, register) _add_line( node.code, "sw", [str(-offset) + "(r14)", register], ) if arg.record: if arg.record.type.is_complex(): offset += 4 else: offset += arg.record.type.size else: # Literal # TODO Handle float literal offset += 4 with self.new_frame(node.code): # Call function _add_line( node.code, "jl", [ "r15", self.get_mangled(child.record.table.name, "func") ], ) with self.register() as register: # Retrieve return value _add_line( node.code, "lw", [register, str(-self.scope.current_size()) + "(r14)"], ) _add_line(node.code, "sw", [child.record.memory_location(), register]) record.offset = child.record.offset node.record = record