def parse_binop(self, expr): if expr.op.act2_num is None: expr.supported_by_action2(True) if (isinstance(expr.expr2, (expression.ConstantNumeric, expression.Variable)) or isinstance(expr.expr2, (VarAction2LoadTempVar, VarAction2LoadCallParam)) or (isinstance(expr.expr2, expression.Parameter) and isinstance(expr.expr2.num, expression.ConstantNumeric)) or expr.op == nmlop.VAL2): expr2 = expr.expr2 elif expr.expr2.supported_by_actionD(False): tmp_param, tmp_param_actions = actionD.get_tmp_parameter( expr.expr2) self.extra_actions.extend(tmp_param_actions) expr2 = expression.Parameter(expression.ConstantNumeric(tmp_param)) else: # The expression is so complex we need to compute it first, store the # result and load it back later. self.parse(expr.expr2) tmp_var = VarAction2StoreTempVar() self.var_list.append(nmlop.STO_TMP) self.var_list.append(tmp_var) self.var_list.append(nmlop.VAL2) # the +2 is for both operators self.var_list_size += tmp_var.get_size() + 2 expr2 = VarAction2LoadTempVar(tmp_var) # parse expr1 self.parse(expr.expr1) self.var_list.append(expr.op) self.var_list_size += 1 self.parse(expr2)
def parse_subexpression(expr, action_list): if isinstance(expr, expression.ConstantNumeric) or \ (isinstance(expr, expression.Parameter) and isinstance(expr.num, expression.ConstantNumeric)): return expr else: tmp_param, tmp_param_actions = get_tmp_parameter(expr) action_list.extend(tmp_param_actions) return expression.Parameter(expression.ConstantNumeric(tmp_param))
def parse_actionD(assignment): assignment.value.supported_by_actionD(True) if isinstance(assignment.param, expression.SpecialParameter): assignment.param, assignment.value = assignment.param.to_assignment(assignment.value) elif isinstance(assignment.param, expression.Identifier): if global_constants.identifier_refcount[assignment.param.value] == 0: # Named parameter is not referenced, ignoring return [] assignment.param = expression.Parameter( expression.ConstantNumeric(global_constants.named_parameters[assignment.param.value]), assignment.param.pos ) assert isinstance(assignment.param, expression.Parameter) if isinstance(assignment.value, expression.SpecialParameter): assignment.value = assignment.value.to_reading() if isinstance(assignment.value, expression.TernaryOp): return parse_ternary_op(assignment) if isinstance(assignment.value, expression.AbsOp): return parse_abs_op(assignment) if isinstance(assignment.value, expression.SpecialCheck): return parse_special_check(assignment) if isinstance(assignment.value, expression.GRMOp): return parse_grm(assignment) if isinstance(assignment.value, expression.BinOp): op = assignment.value.op if op == nmlop.HASBIT or op == nmlop.NOTHASBIT: return parse_hasbit(assignment) elif op == nmlop.MIN or op == nmlop.MAX: return parse_min_max(assignment) if isinstance(assignment.value, expression.Boolean): return parse_boolean(assignment) if isinstance(assignment.value, expression.Not): expr = nmlop.SUB(1, assignment.value.expr) assignment = ParameterAssignment(assignment.param, expr) if isinstance(assignment.value, expression.BinNot): expr = nmlop.SUB(0xFFFFFFFF, assignment.value.expr) assignment = ParameterAssignment(assignment.param, expr) action6.free_parameters.save() action_list = [] act6 = action6.Action6() assert isinstance(assignment.param, expression.Parameter) target = assignment.param.num if isinstance(target, expression.Parameter) and isinstance(target.num, expression.ConstantNumeric): act6.modify_bytes(target.num.value, 1, 1) target = expression.ConstantNumeric(0) elif not isinstance(target, expression.ConstantNumeric): tmp_param, tmp_param_actions = get_tmp_parameter(target) act6.modify_bytes(tmp_param, 1, 1) target = expression.ConstantNumeric(0) action_list.extend(tmp_param_actions) data = None # print assignment.value if isinstance(assignment.value, expression.ConstantNumeric): op = nmlop.ASSIGN param1 = expression.ConstantNumeric(0xFF) param2 = expression.ConstantNumeric(0) data = assignment.value elif isinstance(assignment.value, expression.Parameter): if isinstance(assignment.value.num, expression.ConstantNumeric): op = nmlop.ASSIGN param1 = assignment.value.num else: tmp_param, tmp_param_actions = get_tmp_parameter(assignment.value.num) act6.modify_bytes(tmp_param, 1, 3) action_list.extend(tmp_param_actions) op = nmlop.ASSIGN param1 = expression.ConstantNumeric(0) param2 = expression.ConstantNumeric(0) elif isinstance(assignment.value, expression.OtherGRFParameter): op = nmlop.ASSIGN if isinstance(assignment.value.num, expression.ConstantNumeric): param1 = assignment.value.num else: tmp_param, tmp_param_actions = get_tmp_parameter(assignment.value.num) act6.modify_bytes(tmp_param, 1, 3) action_list.extend(tmp_param_actions) param1 = expression.ConstantNumeric(0) param2 = expression.ConstantNumeric(0xFE) data = expression.ConstantNumeric(expression.parse_string_to_dword(assignment.value.grfid)) elif isinstance(assignment.value, expression.PatchVariable): op = nmlop.ASSIGN param1 = expression.ConstantNumeric(assignment.value.num) param2 = expression.ConstantNumeric(0xFE) data = expression.ConstantNumeric(0xFFFF) elif isinstance(assignment.value, expression.BinOp): op, expr1, expr2, extra_actions = transform_bin_op(assignment) action_list.extend(extra_actions) if isinstance(expr1, expression.ConstantNumeric): param1 = expression.ConstantNumeric(0xFF) data = expr1 elif isinstance(expr1, expression.Parameter) and isinstance(expr1.num, expression.ConstantNumeric): param1 = expr1.num else: tmp_param, tmp_param_actions = get_tmp_parameter(expr1) action_list.extend(tmp_param_actions) param1 = expression.ConstantNumeric(tmp_param) # We can use the data only for one for the parameters. # If the first parameter uses "data" we need a temp parameter for this one if isinstance(expr2, expression.ConstantNumeric) and data is None: param2 = expression.ConstantNumeric(0xFF) data = expr2 elif isinstance(expr2, expression.Parameter) and isinstance(expr2.num, expression.ConstantNumeric): param2 = expr2.num else: tmp_param, tmp_param_actions = get_tmp_parameter(expr2) action_list.extend(tmp_param_actions) param2 = expression.ConstantNumeric(tmp_param) else: raise generic.ScriptError("Invalid expression in argument assignment", assignment.value.pos) if len(act6.modifications) > 0: action_list.append(act6) action_list.append(ActionD(target, param1, op, param2, data)) action6.free_parameters.restore() return action_list
def transform_bin_op(assignment): op = assignment.value.op expr1 = assignment.value.expr1 expr2 = assignment.value.expr2 extra_actions = [] if op == nmlop.CMP_GE: expr1, expr2 = expr2, expr1 op = nmlop.CMP_LE if op == nmlop.CMP_LE: extra_actions.extend(parse_actionD(ParameterAssignment(assignment.param, nmlop.SUB(expr1, expr2)))) op = nmlop.CMP_LT expr1 = assignment.param expr2 = expression.ConstantNumeric(1) if op == nmlop.CMP_GT: expr1, expr2 = expr2, expr1 op = nmlop.CMP_LT if op == nmlop.CMP_LT: extra_actions.extend(parse_actionD(ParameterAssignment(assignment.param, nmlop.SUB(expr1, expr2)))) op = nmlop.SHIFTU_LEFT # shift left by negative number = shift right expr1 = assignment.param expr2 = expression.ConstantNumeric(-31) elif op == nmlop.CMP_NEQ: extra_actions.extend(parse_actionD(ParameterAssignment(assignment.param, nmlop.SUB(expr1, expr2)))) op = nmlop.DIV # We rely here on the (ondocumented) behavior of both OpenTTD and TTDPatch # that expr/0==expr. What we do is compute A/A, which will result in 1 if # A != 0 and in 0 if A == 0 expr1 = assignment.param expr2 = assignment.param elif op == nmlop.CMP_EQ: # We compute A==B by doing not(A - B) which will result in a value != 0 # if A is equal to B extra_actions.extend(parse_actionD(ParameterAssignment(assignment.param, nmlop.SUB(expr1, expr2)))) # Clamp the value to 0/1, see above for details extra_actions.extend( parse_actionD(ParameterAssignment(assignment.param, nmlop.DIV(assignment.param, assignment.param))) ) op = nmlop.SUB expr1 = expression.ConstantNumeric(1) expr2 = assignment.param if op == nmlop.SHIFT_RIGHT or op == nmlop.SHIFTU_RIGHT: if isinstance(expr2, expression.ConstantNumeric): expr2.value *= -1 else: expr2 = nmlop.SUB(0, expr2) op = nmlop.SHIFT_LEFT if op == nmlop.SHIFT_RIGHT else nmlop.SHIFTU_LEFT elif op == nmlop.XOR: # a ^ b ==> (a | b) - (a & b) expr1 = parse_subexpression(expr1, extra_actions) expr2 = parse_subexpression(expr2, extra_actions) tmp_param1, tmp_action_list1 = get_tmp_parameter(nmlop.OR(expr1, expr2)) tmp_param2, tmp_action_list2 = get_tmp_parameter(nmlop.AND(expr1, expr2)) extra_actions.extend(tmp_action_list1) extra_actions.extend(tmp_action_list2) expr1 = expression.Parameter(expression.ConstantNumeric(tmp_param1)) expr2 = expression.Parameter(expression.ConstantNumeric(tmp_param2)) op = nmlop.SUB return op, expr1, expr2, extra_actions
def get_tmp_parameter(expr): param = action6.free_parameters.pop(expr.pos) actions = parse_actionD(ParameterAssignment(expression.Parameter(expression.ConstantNumeric(param)), expr)) return (param, actions)
def p_parameter(self, t): "param : PARAMETER LBRACKET expression RBRACKET" t[0] = expression.Parameter(t[3], t.lineno(1), True)
def parse_via_actionD(self, expr): tmp_param, tmp_param_actions = actionD.get_tmp_parameter(expr) self.extra_actions.extend(tmp_param_actions) num = expression.ConstantNumeric(tmp_param) self.parse(expression.Parameter(num))