def _exp_uminus(code: Code, exp): expression = exp['expression'] exp_type = exp['expression']['type'] _expression(code, expression) if isinstance(exp_type, TypeInt): code.neg_int() elif isinstance(exp_type, TypeReal): code.neg_double() else: raise NotImplementedError()
def _statement_function_call(code: Code, exp): ret = exp['type'] _exp_function_call(code, exp) if isinstance(ret, TypeInt) \ or isinstance(ret, TypeBool) \ or isinstance(ret, TypeStr) \ or isinstance(ret, TypeArray): code.pop() elif isinstance(ret, TypeReal): code.pop2()
def _exp_sub(code: Code, exp): left = exp['left'] right = exp['right'] left_type = exp['left']['type'] _expression(code, left) _expression(code, right) if isinstance(left_type, TypeInt): code.add_int() elif isinstance(left_type, TypeReal): code.add_double() else: raise NotImplementedError()
def _statement(code: Code, statement, loop_start: Optional[int] = None, breaks: Optional[List[int]] = None): node_type = statement['node'] if node_type == Node.VARIABLE_DEFINITION: _statement_var_def(code, statement) elif node_type == Node.CONSTANT_DEFINITION: _statement_var_def(code, statement) elif node_type == Node.VARIABLE_STORE: _statement_var_store(code, statement) elif node_type == Node.ARRAY_STORE: _statement_array_store(code, statement) elif node_type == Node.FUNCTION_CALL: _statement_function_call(code, statement) elif node_type == Node.RETURN: _statement_return(code, statement) elif node_type == Node.RETURN_VOID: code.return_void() elif node_type == Node.IF: _statement_if(code, statement, loop_start, breaks) elif node_type == Node.IF_ELSE: _statement_if_else(code, statement, loop_start, breaks) elif node_type == Node.WHILE: _statement_while(code, statement) elif node_type == Node.BREAK: break_pos = code.pos() code.goto() breaks.append(break_pos) elif node_type == Node.CONTINUE: code.goto(loop_start) else: raise NotImplementedError(node_type)
def _expression(code: Code, expression): node_type = expression['node'] if node_type == Node.UMINUS: _exp_uminus(code, expression) elif node_type == Node.UPLUS: _exp_uplus(code, expression) elif node_type == Node.MUL: _exp_mul(code, expression) elif node_type == Node.DIV: _exp_div(code, expression) elif node_type == Node.PLUS: _exp_plus(code, expression) elif node_type == Node.MINUS: _exp_minus(code, expression) elif node_type == Node.EQ: _exp_eq(code, expression) elif node_type == Node.NE: _exp_ne(code, expression) elif node_type == Node.LT: _exp_lt(code, expression) elif node_type == Node.GT: _exp_gt(code, expression) elif node_type == Node.LE: _exp_le(code, expression) elif node_type == Node.GE: _exp_ge(code, expression) elif node_type == Node.NOT: _exp_not(code, expression) elif node_type == Node.AND: _exp_and(code, expression) elif node_type == Node.OR: _exp_or(code, expression) elif node_type == Node.VARIABLE_LOAD: _exp_var_load(code, expression) elif node_type == Node.ARRAY_LOAD: _exp_array_load(code, expression) elif node_type == Node.VARIABLE_ASSIGNMENT: _exp_var_assign(code, expression) elif node_type == Node.ARRAY_ASSIGNMENT: _exp_array_assign(code, expression) elif node_type == Node.VALUE_INT: code.const_int(expression['value']) elif node_type == Node.VALUE_REAL: code.const_double(expression['value']) elif node_type == Node.VALUE_BOOL: code.const_int(int(expression['value'])) elif node_type == Node.VALUE_STR: code.const_string(expression['value']) elif node_type == Node.VALUE_ARRAY: _exp_value_array(code, expression) elif node_type == Node.FUNCTION_CALL_VALUE: _exp_function_call(code, expression) else: raise NotImplementedError()
def _statement_var_store(code: Code, exp): name = exp['name'] expression = exp['expression'] t = exp['type'] index = _locals[name] _expression(code, expression) if isinstance(t, TypeInt): code.store_int(index) elif isinstance(t, TypeReal): code.store_double(index) elif isinstance(t, TypeBool): code.store_int(index) elif isinstance(t, TypeStr): code.store_reference(index) elif isinstance(t, TypeArray): code.store_reference(index) else: raise NotImplementedError()
def _write_code(code: Code, output: BinaryIO): # calculate absolute positions of instructions, max_stack and max locals code_size = 0 inst_positions = [] stack = 0 max_stack = 0 for (index, instruction) in enumerate(code.instructions): inst_positions.append(code_size) code_size += code.instruction_length(index) stack += code.instruction_stack_diff(index) if max_stack < stack: max_stack = stack max_locals = 0 for local in code.locals: max_locals += local.size() size = CODE_ATTRIBUTE_DEFAULT_SIZE + code_size output.write(struct.pack(BE + U2, _code_attribute_name_index)) output.write(struct.pack(BE + U4, size)) output.write(struct.pack(BE + U2, max_stack)) output.write(struct.pack(BE + U2, max_locals)) output.write(struct.pack(BE + U4, code_size)) # write instructions for (i, instruction) in enumerate(code.instructions): _write_instruction(i, instruction, inst_positions, output) # exception table length output.write(struct.pack(BE + U2, 0)) # attributes count output.write(struct.pack(BE + U2, 0))
def __init__(self, name: str, descriptor: MethodDescriptor, constant_pool: ConstantPool): self._constant_pool = constant_pool self._name_index: int = constant_pool.method_name(name) self._descriptor_index: int = constant_pool.method_descriptor( descriptor) self._code: Code = Code(constant_pool) # setup local variables for p in descriptor.params_descriptors: if isinstance(p, IntDesc): self._code.variable_int() elif isinstance(p, LongDesc): self._code.variable_long() elif isinstance(p, FloatDesc): self._code.variable_float() elif isinstance(p, DoubleDesc): self._code.variable_double() elif isinstance(p, ClassDesc) or isinstance(p, ArrayDesc): self._code.variable_reference()
def _exp_plus(code: Code, exp): left = exp['left'] right = exp['right'] left_type = exp['left']['type'] _expression(code, left) _expression(code, right) if isinstance(left_type, TypeInt): code.add_int() elif isinstance(left_type, TypeReal): code.add_double() elif isinstance(left_type, TypeStr): code.invoke_virtual(*JM_STRING_CONCAT) else: raise NotImplementedError()
def _statement_if(code: Code, statement, loop_start: Optional[int] = None, breaks: Optional[List[int]] = None): condition = statement['condition'] statements = statement['statements'] _expression(code, condition) cond_pos = code.pos() code.if_eq() for s in statements: _statement(code, s, loop_start, breaks) end_pos = code.pos() code.update_jump(cond_pos, end_pos)
def _exp_ge(code: Code, exp): left = exp['left'] right = exp['right'] left_type = exp['left']['type'] _expression(code, left) _expression(code, right) if isinstance(left_type, TypeInt) or isinstance(left_type, TypeReal): if isinstance(left_type, TypeReal): code.cmp_double_g() cmp_pos = code.pos() code.if_ge() else: cmp_pos = code.pos() code.if_cmp_int_ge() code.const_int(0) goto_pos = code.pos() code.goto() true_pos = code.pos() code.const_int(1) end_pos = code.pos() code.update_jump(cmp_pos, true_pos) code.update_jump(goto_pos, end_pos) else: raise NotImplementedError()
def _exp_function_call(code: Code, exp): name = exp['name'] args_exps = exp['arguments'] params = exp['parameters'] ret = exp['type'] for e in args_exps: _expression(code, e) # check for predefined functions if name == FN_LEN and len(params) == 1: if isinstance(params[0], TypeStr): code.invoke_virtual(*JM_STRING_LENGTH) return elif isinstance(params[0], TypeArray): code.array_length() return if name == FN_INT and len(params) == 1: if isinstance(params[0], TypeInt): # nothing to do return elif isinstance(params[0], TypeReal): code.double_to_int() return elif isinstance(params[0], TypeBool): # nothing to do return elif isinstance(params[0], TypeStr): code.invoke_static(*JSM_INT_PARSE) return if name == FN_REAL and len(params) == 1: if isinstance(params[0], TypeInt): code.int_to_double() return elif isinstance(params[0], TypeReal): # nothing to do return elif isinstance(params[0], TypeBool): code.int_to_double() return elif isinstance(params[0], TypeStr): code.invoke_static(*JSM_DOUBLE_PARSE) return if name == FN_BOOL and len(params) == 1: if isinstance(params[0], TypeInt): code.const_int(1) code.and_int() return elif isinstance(params[0], TypeReal): code.const_double(0.0) code.cmp_double_l() cmp_pos = code.pos() code.if_eq() code.const_int(1) goto_pos = code.pos() code.goto() false_pos = code.pos() code.const_int(0) end_pos = code.pos() code.update_jump(cmp_pos, false_pos) code.update_jump(goto_pos, end_pos) return elif isinstance(params[0], TypeBool): # nothing to do return elif isinstance(params[0], TypeStr): code.invoke_static(*JSM_BOOLEAN_PARSE) return if name == FN_STR and len(params) == 1: if isinstance(params[0], TypeInt): code.invoke_static(*JSM_INT_TO_STRING) return elif isinstance(params[0], TypeReal): code.invoke_static(*JSM_DOUBLE_TO_STRING) return elif isinstance(params[0], TypeBool): code.invoke_static(*JSM_BOOLEAN_TO_STRING) return if name == FN_SUBSTRING and len(params) == 3: if isinstance(params[0], TypeStr) and isinstance( params[1], TypeInt) and isinstance(params[2], TypeInt): code.invoke_static(*JM_STRING_SUBSTRING) return if name == FN_WRITE and len(params) == 1: if isinstance(params[0], TypeStr): code.load_static_field(*JSF_STDOUT) code.swap() code.invoke_virtual(*JM_PRINT) return if name == FN_READ_LINE and len(params) == 0: code.load_static_field(_class_name, BUFF_READER_FIELD, ClassDesc(JC_BUFF_READER)) code.invoke_virtual(*JM_READLINE) # if result null, set the eof field to true and load empty string code.dup() cmp_pos = code.pos() code.if_non_null() code.const_int(1) code.store_static_field(_class_name, EOF_FIELD, BooleanDesc()) code.const_string('') end_pos = code.pos() code.update_jump(cmp_pos, end_pos) return if name == FN_EOF and len(params) == 0: code.load_static_field(_class_name, EOF_FIELD, BooleanDesc()) return # custom function name = PREFIX + name desc = _create_method_descriptor(params, ret) code.invoke_static(_class_name, name, desc)
def _exp_array_assign(code: Code, exp): name = exp['name'] index_exps = exp['indexes'] expression = exp['expression'] t = exp['type'] # top array load index = _locals[name] code.load_reference(index) # subarrays load if multidim for e in index_exps[:-1]: _expression(code, e) code.array_load_reference() # item store _expression(code, index_exps[-1]) _expression(code, expression) if isinstance(t.inner, TypeInt): code.dup_x1() code.array_store_int() elif isinstance(t.inner, TypeReal): code.dup2_x1() code.array_store_double() elif isinstance(t.inner, TypeBool): code.dup_x1() code.array_store_boolean() elif isinstance(t.inner, TypeStr): code.dup_x1() code.array_store_reference() elif isinstance(t.inner, TypeArray): code.dup_x1() code.array_store_reference() else: raise NotImplementedError()
def _exp_value_array(code: Code, exp): items = exp['items'] t = exp['type'] if t.dim > 1: desc = _create_field_descriptor(TypeArray(t.dim - 1, t.inner)) else: desc = _create_field_descriptor(t.inner) code.const_int(len(items)) code.new_array(desc) for (i, item) in enumerate(items): code.dup() code.const_int(i) item_type = item['type'] _expression(code, item) if isinstance(item_type, TypeInt): code.array_store_int() elif isinstance(item_type, TypeReal): code.array_store_double() elif isinstance(item_type, TypeBool): code.array_store_boolean() elif isinstance(item_type, TypeStr): code.array_store_reference() elif isinstance(item_type, TypeArray): code.array_store_reference() else: raise NotImplementedError()
def _exp_array_load(code: Code, exp): name = exp['name'] index_exps = exp['indexes'] t = exp['type'] index = _locals.get(name) if index is not None: code.load_reference(index) else: name = PREFIX + name field = _fields.get(name) code.load_static_field(field[0], field[1], field[2]) # subarrays load if multidim for e in index_exps[:-1]: _expression(code, e) code.array_load_reference() # item load _expression(code, index_exps[-1]) if isinstance(t, TypeInt): code.array_load_int() elif isinstance(t, TypeReal): code.array_load_double() elif isinstance(t, TypeBool): code.array_load_boolean() elif isinstance(t, TypeStr): code.array_load_reference() elif isinstance(t, TypeArray): code.array_load_reference() else: raise NotImplementedError()
def _exp_var_load(code: Code, exp): name = exp['name'] t = exp['type'] index = _locals.get(name) if index is not None: if isinstance(t, TypeInt): code.load_int(index) elif isinstance(t, TypeReal): code.load_double(index) elif isinstance(t, TypeBool): code.load_int(index) elif isinstance(t, TypeStr): code.load_reference(index) elif isinstance(t, TypeArray): code.load_reference(index) else: raise NotImplementedError() else: name = PREFIX + name field = _fields.get(name) code.load_static_field(field[0], field[1], field[2])
def _exp_or(code: Code, exp): left = exp['left'] right = exp['right'] t = exp['type'] _expression(code, left) _expression(code, right) if isinstance(t, TypeBool): cmp1_pos = code.pos() code.if_ne() cmp2_pos = code.pos() code.if_ne() code.const_int(0) goto_pos = code.pos() code.goto() true_pos = code.pos() code.const_int(1) end_pos = code.pos() code.update_jump(cmp1_pos, true_pos) code.update_jump(cmp2_pos, true_pos) code.update_jump(goto_pos, end_pos) else: raise NotImplementedError()
def _statement_while(code: Code, statement): condition = statement['condition'] statements = statement['statements'] start = code.pos() _expression(code, condition) cond_pos = code.pos() code.if_eq() breaks = [] for s in statements: _statement(code, s, start, breaks) code.goto(start) end_pos = code.pos() code.update_jump(cond_pos, end_pos) for b in breaks: code.update_jump(b, end_pos)
def _exp_and(code: Code, exp): left = exp['left'] right = exp['right'] left_type = exp['left']['type'] _expression(code, left) _expression(code, right) if isinstance(left_type, TypeBool): cmp1_pos = code.pos() code.if_eq() cmp2_pos = code.pos() code.if_eq() code.const_int(1) goto_pos = code.pos() code.goto() false_pos = code.pos() code.const_int(0) end_pos = code.pos() code.update_jump(cmp1_pos, false_pos) code.update_jump(cmp2_pos, false_pos) code.update_jump(goto_pos, end_pos) else: raise NotImplementedError()
def _exp_not(code: Code, exp): expression = exp['expression'] exp_type = exp['expression']['type'] _expression(code, expression) if isinstance(exp_type, TypeBool): cmp_pos = code.pos() code.if_eq() code.const_int(0) goto_pos = code.pos() code.goto() false_pos = code.pos() code.const_int(1) end_pos = code.pos() code.update_jump(cmp_pos, false_pos) code.update_jump(goto_pos, end_pos) else: raise NotImplementedError()
def _statement_if_else(code: Code, statement, loop_start: Optional[int] = None, breaks: Optional[List[int]] = None): condition = statement['condition'] if_statements = statement['if_statements'] else_statements = statement['else_statements'] _expression(code, condition) cond_pos = code.pos() code.if_eq() for s in if_statements: _statement(code, s, loop_start, breaks) goto_pos = code.pos() code.goto() else_pos = code.pos() for s in else_statements: _statement(code, s, loop_start, breaks) end_pos = code.pos() code.update_jump(cond_pos, else_pos) code.update_jump(goto_pos, end_pos)
def _exp_ne(code: Code, exp): left = exp['left'] right = exp['right'] left_type = exp['left']['type'] _expression(code, left) _expression(code, right) if isinstance(left_type, TypeInt) or isinstance( left_type, TypeBool) or isinstance(left_type, TypeReal): if isinstance(left_type, TypeReal): code.cmp_double_l() cmp_pos = code.pos() code.if_ne() else: cmp_pos = code.pos() code.if_cmp_int_ne() code.const_int(0) goto_pos = code.pos() code.goto() true_pos = code.pos() code.const_int(1) end_pos = code.pos() code.update_jump(cmp_pos, true_pos) code.update_jump(goto_pos, end_pos) elif isinstance(left_type, TypeStr): code.invoke_virtual(*JM_STRING_EQUALS) cmp_pos = code.pos() code.if_eq() code.const_int(0) goto_pos = code.pos() code.goto() false_pos = code.pos() code.const_int(1) end_pos = code.pos() code.update_jump(cmp_pos, false_pos) code.update_jump(goto_pos, end_pos) else: raise NotImplementedError()
def _statement_return(code: Code, statement): expression = statement['expression'] t = statement['type'] if expression: _expression(code, expression) if isinstance(t, TypeVoid): code.return_void() elif isinstance(t, TypeInt): code.return_int() elif isinstance(t, TypeReal): code.return_double() elif isinstance(t, TypeBool): code.return_int() elif isinstance(t, TypeStr): code.return_reference() elif isinstance(t, TypeArray): code.return_reference() else: raise NotImplementedError()
def _statement_var_def(code: Code, statement): name = statement['name'] t = statement['type'] expression = statement['expression'] _expression(code, expression) if isinstance(t, TypeInt): index = code.variable_int() code.store_int(index) elif isinstance(t, TypeReal): index = code.variable_double() code.store_double(index) elif isinstance(t, TypeBool): index = code.variable_int() code.store_int(index) elif isinstance(t, TypeStr): index = code.variable_reference() code.store_reference(index) elif isinstance(t, TypeArray): index = code.variable_reference() code.store_reference(index) else: raise NotImplementedError() _locals[name] = index