def make_il(self, il_code, symbol_table, c): """ Make code for this node """ symbol_table.new_scope() if self.first: self.first.make_il(il_code, symbol_table, c) start = il_code.get_label() cont = il_code.get_label() end = il_code.get_label() c = c.set_continue(cont).set_break(end) il_code.add(control_cmds.Label(start)) with report_err(): if self.second: cond = self.second.make_il(il_code, symbol_table, c) il_code.add(control_cmds.JumpZero(cond, end)) with report_err(): self.stat.make_il(il_code, symbol_table, c) il_code.add(control_cmds.Label(cont)) with report_err(): if self.third: self.third.make_il(il_code, symbol_table, c) il_code.add(control_cmds.Jump(start)) il_code.add(control_cmds.Label(end)) symbol_table.end_scope()
def nonarith(self, left, right, il_code): """ Check equality of non-arithmetic expressions """ # If either operand is a null pointer constant, cast it to the other's pointer type. if left.ctype.is_pointer() and right.null_ptr_const: right = set_type(right, left.ctype, il_code) elif right.ctype.is_pointer() and left.null_ptr_const: left = set_type(left, right.ctype, il_code) # If both operands are not pointer types, quit now if not left.ctype.is_pointer() or not right.ctype.is_pointer(): with report_err(): err = "comparison between incomparable types" raise CompilerError(err, self.op.r) # If one side is pointer to void, cast the other to same. elif left.ctype.arg.is_void(): check_cast(right, left.ctype, self.op.r) right = set_type(right, left.ctype, il_code) elif right.ctype.arg.is_void(): check_cast(left, right.ctype, self.op.r) left = set_type(left, right.ctype, il_code) # If both types are still incompatible, warn! elif not left.ctype.compatible(right.ctype): with report_err(): err = "comparison between distinct pointer types" raise CompilerError(err, self.op.r) # Now, we can do comparison out = ILValue(ctypes.integer) il_code.add(self.eq_il_cmd(out, left, right)) return out
def parse_struct_spec(self, node, redec): """Parse struct ctype from the given decl_nodes.Struct node. node (decl_nodes.Struct) - the Struct node to parse redec (bool) - Whether this declaration is alone like so: struct S; or declares variables/has storage specifiers: struct S *p; extern struct S; If it's the first, then this is always a forward declaration for a new `struct S` but if it's the second and a `struct S` already exists in higher scope, it's just using the higher scope struct. """ has_members = node.members is not None ctype_req = StructCType if node.tag: tag = str(node.tag) ctype = self.symbol_table.lookup_struct(tag) if ctype and not isinstance(ctype, ctype_req): err = f"defined as wrong kind of tag '{node.kind} {tag}'" raise CompilerError(err, node.r) if not ctype or has_members or redec: ctype = self.symbol_table.add_struct(tag, ctype_req(tag)) if has_members and ctype.is_complete(): err = f"redefinition of '{node.kind} {tag}'" raise CompilerError(err, node.r) else: ctype = ctype_req(None) if not has_members: return ctype # Struct does have members members = [] members_set = set() for member in node.members: decl_infos = [] # needed in case get_decl_infos below fails with report_err(): decl_infos = self.get_decl_infos(member) for decl_info in decl_infos: with report_err(): self.check_struct_member_decl_info(decl_info, node.kind, members_set) name = decl_info.identifier.content members_set.add(name) members.append((name, decl_info.ctype)) ctype.set_members(members) return ctype
def make_il(self, il_code, symbol_table, c): """ Make code for this declaration """ self.set_self_vars(il_code, symbol_table, c) decl_infos = self.get_decl_infos(self.node) for info in decl_infos: with report_err(): info.process(il_code, symbol_table, c)
def make_il(self, il_code, symbol_table, c): """ Make code for this node """ start = il_code.get_label() end = il_code.get_label() il_code.add(control_cmds.Label(start)) c = c.set_continue(start).set_break(end) with report_err(): self.stat.make_il(il_code, symbol_table, c) with report_err(): cond = self.cond.make_il(il_code, symbol_table, c) il_code.add(control_cmds.JumpZero(cond, end)) il_code.add(control_cmds.Jump(start)) il_code.add(control_cmds.Label(end))
def make_il(self, il_code, symbol_table, c): """ Make IL code for returning this value """ label = self.get_label(c) if label: il_code.add(control_cmds.Jump(label)) else: with report_err(): err = f"{self.descr} statement not in loop" raise CompilerError(err, self.r)
def make_il(self, il_code, symbol_table, c): """ Make code for this if statement """ endif_label = il_code.get_label() with report_err(): cond = self.cond.make_il(il_code, symbol_table, c) il_code.add(control_cmds.JumpZero(cond, endif_label)) with report_err(): self.stat.make_il(il_code, symbol_table, c) if self.else_stat: end_label = il_code.get_label() il_code.add(control_cmds.Jump(end_label)) il_code.add(control_cmds.Label(endif_label)) with report_err(): self.else_stat.make_il(il_code, symbol_table, c) il_code.add(control_cmds.Label(end_label)) else: il_code.add(control_cmds.Label(endif_label))
def make_il(self, il_code, symbol_table, c, no_scope=False): """Make IL code for every block item, in order. If no_scope is True, then don`t create a new symbol table scope. Used by function definition so that parameters can live in the scope of the function body. """ if not no_scope: symbol_table.new_scope() c = c.set_global(False) for item in self.items: with report_err(): item.make_il(il_code, symbol_table, c) if not no_scope: symbol_table.end_scope()
def get_decl_infos(self, node): """Given a node, returns a list of decl_info objects for that node.""" any_dec = bool(node.decls) base_type, storage = self.make_specs_ctype(node.specs, any_dec) out = [] for decl, init in zip(node.decls, node.inits): with report_err(): ctype, identifier = self.make_ctype(decl, base_type) if ctype.is_function(): param_identifiers = self.extract_params(decl) else: param_identifiers = [] out.append( DeclInfo(identifier, ctype, decl.r, storage, init, self.body, param_identifiers)) return out
def make_il(self, il_code, symbol_table, c): """ Make code for the root """ for node in self.nodes: with report_err(): c = c.set_global(True) node.make_il(il_code, symbol_table, c)