def preprocess_binop(self, expr): """ Several nml operators are not directly support by nfo so we have to work around that by implementing those operators in terms of others. @return: A pre-processed version of the expression. @rtype: L{Expression} """ assert isinstance(expr, expression.BinOp) if expr.op == nmlop.CMP_LT: # return value is 0, 1 or 2, we want to map 0 to 1 and the others to 0 expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) # reduce the problem to 0/1 expr = nmlop.MIN(expr, 1) # and invert the result expr = nmlop.XOR(expr, 1) elif expr.op == nmlop.CMP_GT: # return value is 0, 1 or 2, we want to map 2 to 1 and the others to 0 expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) # subtract one expr = nmlop.SUB(expr, 1) # map -1 and 0 to 0 expr = nmlop.MAX(expr, 0) elif expr.op == nmlop.CMP_LE: # return value is 0, 1 or 2, we want to map 2 to 0 and the others to 1 expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) # swap 0 and 2 expr = nmlop.XOR(expr, 2) # map 1/2 to 1 expr = nmlop.MIN(expr, 1) elif expr.op == nmlop.CMP_GE: # return value is 0, 1 or 2, we want to map 1/2 to 1 expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) expr = nmlop.MIN(expr, 1) elif expr.op == nmlop.CMP_EQ: # return value is 0, 1 or 2, we want to map 1 to 1, other to 0 expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) expr = nmlop.AND(expr, 1) elif expr.op == nmlop.CMP_NEQ: # same as CMP_EQ but invert the result expr = nmlop.VACT2_CMP(expr.expr1, expr.expr2) expr = nmlop.AND(expr, 1) expr = nmlop.XOR(expr, 1) elif expr.op == nmlop.HASBIT: # hasbit(x, n) ==> (x >> n) & 1 expr = nmlop.SHIFTU_RIGHT(expr.expr1, expr.expr2) expr = nmlop.AND(expr, 1) elif expr.op == nmlop.NOTHASBIT: # !hasbit(x, n) ==> ((x >> n) & 1) ^ 1 expr = nmlop.SHIFTU_RIGHT(expr.expr1, expr.expr2) expr = nmlop.AND(expr, 1) expr = nmlop.XOR(expr, 1) return expr.reduce()
def parse(self, expr): # Preprocess the expression if isinstance(expr, expression.SpecialParameter): # do this first, since it may evaluate to a BinOp expr = expr.to_reading() if isinstance(expr, expression.BinOp): expr = self.preprocess_binop(expr) elif isinstance(expr, expression.Boolean): expr = nmlop.MINU(expr.expr, 1) elif isinstance(expr, expression.BinNot): expr = nmlop.XOR(expr.expr, 0xFFFFFFFF) elif isinstance( expr, expression.TernaryOp) and not expr.supported_by_actionD(False): expr = self.preprocess_ternaryop(expr) elif isinstance(expr, expression.StorageOp): expr = self.preprocess_storageop(expr) # Try to parse the expression to a list of variables+operators if isinstance(expr, expression.ConstantNumeric): self.parse_constant(expr) elif isinstance(expr, expression.Parameter) and isinstance( expr.num, expression.ConstantNumeric): self.parse_param(expr) elif isinstance(expr, expression.Variable): self.parse_variable(expr) elif expr.supported_by_actionD(False): self.parse_via_actionD(expr) elif isinstance(expr, expression.BinOp): self.parse_binop(expr) elif isinstance(expr, expression.Not): self.parse_not(expr) elif isinstance(expr, expression.String): self.parse_string(expr) elif isinstance(expr, (VarAction2LoadTempVar, VarAction2LoadCallParam)): self.var_list.append(expr) self.var_list_size += expr.get_size() elif isinstance(expr, expression.SpriteGroupRef): self.parse_proc_call(expr) else: expr.supported_by_action2(True) raise AssertionError( "supported_by_action2 should have raised the correct error already" )
def builtin_getbits(name, args, pos): """ getbits(value, first, amount) builtin function. @return Extract C{amount} bits starting at C{first} from C{value}, that is (C{value} >> C{first}) & (1 << C{amount} - 1) """ if len(args) != 3: raise generic.ScriptError(name + "() must have exactly three parameters", pos) # getbits(value, first, amount) = (value >> first) & ((0xFFFFFFFF << amount) ^ 0xFFFFFFFF) part1 = nmlop.SHIFTU_RIGHT(args[0], args[1], pos) part2 = nmlop.SHIFT_LEFT(0xFFFFFFFF, args[2], pos) part3 = nmlop.XOR(part2, 0xFFFFFFFF, pos) return nmlop.AND(part1, part3, pos)
def parse_not(self, expr): self.parse_binop(nmlop.XOR(expr.expr, 1))
def value_sign_extend(var, info): #r = (x ^ m) - m; with m being (1 << (num_bits -1)) m = expression.ConstantNumeric(1 << (info['size'] - 1)) return nmlop.SUB(nmlop.XOR(var, m), m)