def type_check_relational(node1, node2, op, token, is_bool=False): allowed_class = {'BasicType'} allowed_base = {'int', 'long', 'char', 'double', 'float'} if node1.type == "error" or node2.type == "error": return Node(type="error") if node1.type.class_type not in allowed_class or node2.type.class_type not in allowed_class: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if is_bool: if node1.type.type == "bool" and node2.type.type == "bool": return Node(name="binary_op", value="bool" + op, children=[node1, node2], type=BasicType('bool')) if node1.type.type not in allowed_base or node2.type.type not in allowed_base: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") node1, node2, typ = implicit_casting(node1, node2) return Node(name="binary_op", value=typ.stype + op, children=[node1, node2], type=BasicType('bool'))
def type_check_logical(node1, node2, op, token): allowed_class = {'BasicType'} allowed_base = {'int', 'long', 'char', 'double', 'float', 'bool'} if node1.type == "error" or node2.type == "error": return Node(type="error") if node1.type.class_type not in allowed_class or node2.type.class_type not in allowed_class: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if node1.type.type not in allowed_base or node2.type.type not in allowed_base: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if node1.type.type != "bool": node1 = Node(name="type_cast", value='bool', children=[node1], type=BasicType('bool')) if node2.type.type != "bool": node2 = Node(name="type_cast", value='bool', children=[node2], type=BasicType('bool')) return Node(name="binary_op", value=op, children=[node1, node2], type=BasicType('bool'))
def typecast(node1, type, token=None, hard=False): node1 = load_place(node1) assert isinstance(type, Type), "not of class Type" assert type.class_type in {"BasicType", "PointerType", "StructType"}, "not valid type" # assert node1.type.class_type in {"BasicType","PointerType"}, "not valid type" # assert "sconst@" not in node1.place, "string in typecast" if node1.type.stype == type.stype: if hard: node1.type = type return node1 elif "sconst@" in node1.place: # print(str(node1.type.stype),str(type.stype)) if token: Errors(errorType='TypeError', errorText="cannot assign string constant to type " + type.stype, token_object=token) return Node(type="error") else: assert "string in typecast" else: node = Node(name="type_cast", value=type.stype, children=[node1], type=type) node.code = node1.code node.place = node1.place if type.class_type == 'PointerType': type1 = 'long' else: type1 = type.type if node1.type.class_type == 'PointerType': type2 = 'long' else: type2 = node1.type.type if type1 == type2: return node if type1 in {"long", "int"} and type2 in {"long", "int"}: return node if "const@" in node1.place: node.place = get_const(const=get_const_value(node1.place), type=BasicType(type1)) return node node.place = get_newtmp(type=BasicType(type1)) node.code += [ gen(op=type2 + "_to_" + type1, place1=node1.place, place3=node.place, code=node.place + " = " + type2 + "_to_" + type1 + " " + node1.place) ] return node
def p_type_specifier(p): ''' type_specifier : VOID | CHAR | INT | LONG | FLOAT | DOUBLE | STRUCT IDENTIFIER | ENUM IDENTIFIER | BOOL ''' if p[1] == 'enum': pass elif p[1] == 'struct': success = sym_table.look_up_struct(name=p[2], token_object=p.slice[-1]) if success: p[0] = Node(type=success) else: p[0] = Node(type="error") else: if p[1] == 'void': p[0] = Node(type=Type()) else: p[0] = Node(type=BasicType(type=p[1])) assert isinstance(p[0], Node), "return object is not Node" assert p[0].type == 'error' or isinstance( p[0].type, Type), "unexpected type attribute of return object"
def p_conditional_expression(p): ''' conditional_expression : logical_or_expression | logical_or_expression QUES_MARK expression COLON conditional_expression ''' if len(p) == 2: p[0] = p[1] else: if p[1].type == "error" or p[3].type == "error" or p[5].type == "error": p[0] = Node(type="error") return allowed_class = {'BasicType'} allowed_base = {'int', 'long', 'char', 'bool', 'double', 'float'} if p[1].type.class_type not in allowed_class or p[ 1].type.type not in allowed_base: Errors(errorType='TypeError', errorText=p[2] + ' not support type ' + p[1].type.stype, token_object=p.slice[2]) p[0] = Node(type="error") return if p[3].type != p[5].type: Errors(errorType='TypeError', errorText='type should be same', token_object=p.slice[2]) p[0] = Node(type="error") p[1] = Node(name="type_cast", value='bool', children=[p[1]], type=BasicType('bool')) p[0] = Node("ternary_op", children=[p[1], p[3], p[5]], type=p[3].type)
def const_use(place, sconst=False): if "sconst@" in place: if sconst and place not in alloc.keys(): string = remove_backslash(place.split("@")[-1]) # print(string,len(string)) node_type = PointerType(type=BasicType("char"), array_size=[len(string) + 1], array_type=BasicType("char")) sym_table._add_entry(name=place, type=node_type) alloc[place] = string return if place not in alloc.keys(): node_type = BasicType("long") if place[0] == "l" else BasicType( "float") sym_table._add_entry(name=place, type=node_type) alloc[place] = get_const_value(place)
def get_newtmp(type=BasicType("long")): assert isinstance(type, Type), "inconsistent type for newtmp" global temp_cnt name = "tmp@" + str(temp_cnt) temp_cnt += 1 sym_table.add_entry(name=name, type=type) temp_dict[name] = sym_table.curr_symbol_table return name
def type_check_relational(node1, node2, op, token): allowed_class = {'BasicType', 'PointerType'} allowed_base = {'int', 'long', 'char', 'float', 'bool'} if node1.type == "error" or node2.type == "error": return Node(type="error") if "sconst@" in node1.place or "sconst@" in node2.place: Errors(errorType='TypeError', errorText=op + ' not support string constant', token_object=token) return Node(type="error") if node1.type.class_type not in allowed_class or node2.type.class_type not in allowed_class: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if node1.type.class_type == "PointerType": node1.type = BasicType("long") if node2.type.class_type == "PointerType": node2.type = BasicType("long") if node1.type.type not in allowed_base or node2.type.type not in allowed_base: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") node1, node2, typ = implicit_casting(node1, node2) node = Node(name="binary_op", value=typ.stype + op, children=[node1, node2], type=BasicType('bool')) node.code = node1.code + node2.code tmp, code = get_opcode(op=typ.stype + op, place1=node1.place, place2=node2.place, type=BasicType('bool')) node.code += [code] node.place = tmp return node
def p_primary_expression(p): ''' primary_expression : IDENTIFIER | INT_CONSTANT | HEX_CONSTANT | OCTAL_CONSTANT | EXPONENT_CONSTANT | REAL_CONSTANT | CHAR_CONSTANT | STR_CONSTANT | L_PAREN expression R_PAREN | TRUE | FALSE | NULL ''' if len(p) == 2: if p.slice[-1].type == "IDENTIFIER": #looking for id success = sym_table.look_up(name=p[1], token_object=p.slice[-1]) if success: p[0] = Node(name="id", value=p[1], type=success.type) else: p[0] = Node(name="id", type='error') return if p.slice[-1].type in [ "INT_CONSTANT", "HEX_CONSTANT", "OCTAL_CONSTANT" ]: p[0] = Node(name="constant", value=p[1], type=BasicType('int')) elif p.slice[-1].type in ["EXPONENT_CONSTANT", "REAL_CONSTANT"]: p[0] = Node(name="constant", value=p[1], type=BasicType('float')) elif p.slice[-1].type == "CHAR_CONSTANT": p[0] = Node(name="constant", value=p[1], type=BasicType('char')) elif p.slice[-1].type == "STR_CONSTANT": str_type = PointerType(type=BasicType('char'), array_size=[len(p[1])], array_type=BasicType('char')) p[0] = Node(name="constant", value=p[1], type=str_type) elif p.slice[-1].type == "NULL": p[0] = Node(name="constant", value=p[1], type=PointerType(type=Type())) else: p[0] = Node(name="constant", value=p[1], type=BasicType('bool')) p[0].constant = p[0].value else: p[0] = p[2]
def get_opcode(op=None, place1=None, place2=None, type=None): if isinstance(type, str): type = BasicType(type) assert "sconst@" not in place1 and "sconst@" not in place2, "string" if "const@" in place1 and "const@" in place2: return get_const(op_on_const(op, place1, place2), type=type), None tmp = get_newtmp(type) place1 = str(place1) place2 = str(place2) if op != "=": code = gen(op=op, place1=place1, place2=place2, place3=tmp) if "const@" in place1: const_use(place1) if "const@" in place2: const_use(place2) else: code = gen(op=op, place1=place1, place3=tmp) if "const@" in place1: const_use(place1) return tmp, code
def type_check_unary(node1, op, token, is_typename=False): allowed_base = {'int', 'float', 'double', 'char', 'long'} allowed_base_1 = {'int', 'char', 'long'} error = False if node1.type == "error": return Node(type="error") if op == "++" or op == "--": if node1.type.class_type == "BasicType" and node1.type.type in allowed_base: return Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) if node1.type.class_type == "PointerType": return Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) error = True elif op == "+" or op == "-": if node1.type.class_type == "BasicType" and node1.type.type in allowed_base: return Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) error = True elif op == "&": return Node(name="unary_op", value=op, children=[node1], type=PointerType(node1.type)) elif op == "*": if node1.type.class_type == "PointerType": return Node(name="unary_op", value=op, children=[node1], type=node1.type.type) Errors(errorType='TypeError', errorText="cannot dereference non-pointer type " + node1.type.stype, token_object=token) return Node(type="error") elif op == "~": if node1.type.class_type == "BasicType" and node1.type.type in allowed_base_1: return Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) error = True elif op == "!": if node1.type.is_convertible_to(BasicType('bool')): return Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=BasicType('bool')) error = True elif op == "sizeof": if is_typename: return Node(name="unary_op", value=op + ':' + node1.type.stype, type=BasicType(type='long')) if isinstance(node1.type, Type) == False: Errors(errorType='TypeError', errorText="cannot do sizeof on non type", token_object=token) return Node(type="error") if node1.type.class_type in {'BasicType', 'PointerType', 'StructType'}: return Node(name="unary_op", value=op, type=BasicType(type='long'), children=[node1]) error = True if error: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype, token_object=token) return Node(type="error")
def type_check_unary(node1, op, token, is_typename=False): allowed_base = {'int', 'float', 'char', 'long'} allowed_base_1 = {'int', 'char', 'long'} error = False error_const = False if node1.type == "error": return Node(type="error") const = False if 'const@' in node1.place: const = True if (op == "++" or op == "--"): if const: error_const = True elif (node1.type.class_type == "BasicType" and node1.type.type in allowed_base) or node1.type.class_type == "PointerType": node = Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) node.place = node1.place const_place = get_const(const=1, type=BasicType("long")) node_1 = Node(type=BasicType("long")) node_1.place = const_place node_assign = type_check_assign_op(node1, node_1, op=op[0] + "=", token=token) if node_assign.type == "error": return Node(type="error") node.code = node_assign.code return node # elif node1.type.class_type == "BasicType" and node1.type.type in allowed_base: # node = Node(name="unary_op",value=node1.type.stype+op,children=[node1],type=node1.type) # node.code = node1.code # const_place = get_const(const=1,type=node1.type,use=True) # node.code += [gen(op=node1.type.stype+op[0],place1=node1.place,place2=const_place,place3=node1.place)] # node.place = node1.place # return node # elif node1.type.class_type == "PointerType": # node = Node(name="unary_op",value=node1.type.stype+op,children=[node1],type=node1.type) # node.code = node1.code # width = node1.type.type_size # const_place = get_const(const=width,type="long",use=True) # node.code += [gen(op="long"+op[0],place1=node1.place,place2=const_place,place3=node1.place)] # node.place = node1.place # return node else: error = True elif op == "+" or op == "-": node1 = load_place(node1) if node1.type.class_type == "BasicType" and node1.type.type in allowed_base: node = Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) if op == "+": node.place = node1.place return node if "const@" in node1.place: neg = -1 if op == "-" else 1 node.place = get_const(neg * get_const_value(node1.place), type=node1.type) return node node.code = node1.code node.place = get_newtmp(type=node1.type) node.code += [ gen(op="u" + node1.type.stype + op, place1=node1.place, place3=node.place) ] return node error = True elif op == "&": if const: error_const = True else: node = Node(name="unary_op", value=op, children=[node1], type=PointerType(node1.type)) node.code = node1.code if "load$" in node1.place: node.place = node1.place.split("load$")[-1] return node node.place = get_newtmp() node.code += [ gen(op="addr", place1=node1.place, place3=node.place, code=node.place + " = " + "addr(" + node1.place + ")") ] return node elif op == "*": node1 = load_place(node1) if const: error_const = True elif node1.type.class_type == "PointerType": node = Node(name="unary_op", value=op, children=[node1], type=node1.type.type) if node.type.class_type == "PointerType": node.type.array_size = node1.type.array_size[1:] node.code = node1.code # node.place = get_newtmp(node1.type.type) # node.code += [gen(op="load",place1=node1.place,place3=node.place,code=node.place+" = "+"load("+node1.place+")")] node.place = "load$" + node1.place return node else: Errors(errorType='TypeError', errorText="cannot dereference non-pointer type " + node1.type.stype, token_object=token) return Node(type="error") elif op == "~": node1 = load_place(node1) if node1.type.class_type == "BasicType" and node1.type.type in allowed_base_1: node = Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=node1.type) if "const@" in node1.place: node.place = get_const(~get_const_value(node1.place), type=node1.type) return node node.code = node1.code node.place = get_newtmp(type=node1.type) node.code += [ gen(op=node1.type.stype + op, place1=node1.place, place3=node.place) ] return node error = True elif op == "!": node1 = load_place(node1) if node1.type.is_convertible_to(BasicType('bool')): node = Node(name="unary_op", value=node1.type.stype + op, children=[node1], type=BasicType('bool')) if "const@" in node1.place: value = 0 if get_const_value(node1.place) == 0 else 1 node.place = get_const(value, type='bool') return node node.code = node1.code node.place = get_newtmp(type=BasicType('bool')) node.code += [ gen(op="not_bool", place1=node1.place, place3=node.place) ] return node error = True elif op == "sizeof": if is_typename: node = Node(name="unary_op", value=op + ':' + node1.type.stype, type=BasicType(type='long')) node.place = get_const(const=node1.type.width, type="long") # node.code += [gen(op="=",place1=str(node1.type.width),place3=node.place)] return node if isinstance(node1.type, Type) == False: Errors(errorType='TypeError', errorText="cannot do sizeof on non type", token_object=token) return Node(type="error") if node1.type.class_type in {'BasicType', 'PointerType', 'StructType'}: node = Node(name="unary_op", value=op, type=BasicType(type='long'), children=[node1]) node.place = get_const(const=node1.type.width, type="long") # node.code += [gen(op="=",place1=str(node1.type.width),place3=node.place)] return node error = True if error_const: Errors(errorType='TypeError', errorText=op + " not valid on constant", token_object=token) return Node(type="error") if error: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype, token_object=token) return Node(type="error")
def type_check_logical(node1, node2, op, token): allowed_class = {'BasicType', 'PointerType'} allowed_base = {'int', 'long', 'char', 'float', 'bool'} if node1.type == "error" or node2.type == "error": return Node(type="error") if "sconst@" in node1.place or "sconst@" in node2.place: Errors(errorType='TypeError', errorText=op + ' not support string constant', token_object=token) return Node(type="error") if node1.type.class_type not in allowed_class or node2.type.class_type not in allowed_class: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if node1.type.class_type == "BasicType" and node1.type.type not in allowed_base: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") if node2.type.class_type == "BasicType" and node2.type.type not in allowed_base: Errors(errorType='TypeError', errorText=op + ' not support type ' + node1.type.stype + ',' + node2.type.stype, token_object=token) return Node(type="error") # if node1.type.type != "bool": # node1 = typecast(node1,BasicType("bool")) # if node2.type.type != "bool": # node2 = typecast(node2,BasicType("bool")) node = Node(name="binary_op", value=op, children=[node1, node2], type=BasicType('bool')) # node.code = node1.code + node2.code # tmp,code = get_opcode(op=op,place1=node1.place,place2=node2.place,type=BasicType('bool')) # node.code += [code] # node.place = tmp if op == "&&": if "const@" in node1.place and "const@" in node2.place: value = 1 if get_const_value(node1.place) and get_const_value( node2.place) else 0 node.place = get_const(value, "bool") return node if "const@" in node1.place: const_use(node1.place) if "const@" in node2.place: const_use(node2.place) node.place = get_newtmp(BasicType('bool')) label1 = get_newlabel() label2 = get_newlabel() node.code = node1.code node.code += [gen(op="ifz", place1=node1.place, place2=label1)] node.code += node2.code node.code += [gen(op="ifz", place1=node2.place, place2=label1)] node.code += [ gen(op="bool=", place1=get_const(1, type='bool', use=True), place3=node.place) ] node.code += [gen(op="goto", place1=label2)] node.code += [gen(op="label", place1=label1)] node.code += [ gen(op="bool=", place1=get_const(0, type='bool', use=True), place3=node.place) ] node.code += [gen(op="label", place1=label2)] else: if "const@" in node1.place and "const@" in node2.place: value = 1 if get_const_value(node1.place) or get_const_value( node2.place) else 0 node.place = get_const(value, "bool") return node if "const@" in node1.place: const_use(node1.place) if "const@" in node2.place: const_use(node2.place) node.place = get_newtmp(BasicType('bool')) label1 = get_newlabel() label2 = get_newlabel() node.code = node1.code node.code += [gen(op="ifnz", place1=node1.place, place2=label1)] node.code += node2.code node.code += [gen(op="ifnz", place1=node2.place, place2=label1)] node.code += [ gen(op="bool=", place1=get_const(0, type='bool', use=True), place3=node.place) ] node.code += [gen(op="goto", place1=label2)] node.code += [gen(op="label", place1=label1)] node.code += [ gen(op="bool=", place1=get_const(1, type='bool', use=True), place3=node.place) ] node.code += [gen(op="label", place1=label2)] return node