diff options
| author | Aymeric Vincent <aymeric.vincent@cea.fr> | 2017-12-11 16:56:12 +0100 |
|---|---|---|
| committer | Aymeric Vincent <aymeric.vincent@cea.fr> | 2017-12-12 09:17:03 +0100 |
| commit | a4fd3ad386ce159d4b653c7cdd3804ac98d9fc12 (patch) | |
| tree | b306e29ecd86dd091df8a5fa6884ef480a7a02df /miasm2/expression/expression.py | |
| parent | 08c831a627b0f0159276d2ca895cd8c8feb8bb21 (diff) | |
| download | miasm-a4fd3ad386ce159d4b653c7cdd3804ac98d9fc12.tar.gz miasm-a4fd3ad386ce159d4b653c7cdd3804ac98d9fc12.zip | |
Remove some unnecessary parentheses when str()'ing expressions
This patch removes quite a few useless parentheses from expressions thanks to the usual priorities between operators. It is conservative in the sense that not all such parentheses are removed when we felt the priorities won't be known by most users.
Diffstat (limited to 'miasm2/expression/expression.py')
| -rw-r--r-- | miasm2/expression/expression.py | 62 |
1 files changed, 46 insertions, 16 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py index 591dc024..d31c509c 100644 --- a/miasm2/expression/expression.py +++ b/miasm2/expression/expression.py @@ -56,6 +56,38 @@ EXPRSLICE = 7 EXPRCOMPOSE = 8 +priorities_list = [ + [ '+' ], + [ '*', '/', '%' ], + [ '**' ], + [ '-' ], # Unary '-', associativity with + not handled +] + +# dictionary from 'op' to priority, derived from above +priorities = dict((op, prio) + for prio, l in enumerate(priorities_list) + for op in l) +PRIORITY_MAX = len(priorities_list) - 1 + +def should_parenthesize_child(child, parent): + if (isinstance(child, ExprId) or isinstance(child, ExprInt) or + isinstance(child, ExprCompose) or isinstance(child, ExprMem) or + isinstance(child, ExprSlice)): + return False + elif isinstance(child, ExprOp) and not child.is_infix(): + return False + elif (isinstance(child, ExprCond) or isinstance(parent, ExprSlice)): + return True + elif (isinstance(child, ExprOp) and isinstance(parent, ExprOp)): + pri_child = priorities.get(child.op, -1) + pri_parent = priorities.get(parent.op, PRIORITY_MAX + 1) + return pri_child < pri_parent + else: + return True + +def str_protected_child(child, parent): + return ("(%s)" % child) if should_parenthesize_child(child, parent) else str(child) + def visit_chk(visitor): "Function decorator launching callback on Expression visit" def wrapped(expr, callback, test_visit=lambda x: True): @@ -687,7 +719,7 @@ class ExprCond(Expr): return Expr.get_object(cls, (cond, src1, src2)) def __str__(self): - return "(%s?(%s,%s))" % (str(self._cond), str(self._src1), str(self._src2)) + return "%s?(%s,%s)" % (str_protected_child(self._cond, self), str(self._src1), str(self._src2)) def get_r(self, mem_read=False, cst_read=False): out_src1 = self.src1.get_r(mem_read, cst_read) @@ -919,20 +951,13 @@ class ExprOp(Expr): return Expr.get_object(cls, (op, args)) def __str__(self): - if self.is_associative(): - return '(' + self._op.join([str(arg) for arg in self._args]) + ')' - if (self._op.startswith('call_func_') or - self._op == 'cpuid' or - len(self._args) > 2 or - self._op in ['parity', 'segm']): - return self._op + '(' + ', '.join([str(arg) for arg in self._args]) + ')' - if len(self._args) == 2: - return ('(' + str(self._args[0]) + - ' ' + self.op + ' ' + str(self._args[1]) + ')') - else: - return reduce(lambda x, y: x + ' ' + str(y), - self._args, - '(' + str(self._op)) + ')' + if self._op == '-': # Unary minus + return '-' + str_protected_child(self._args[0], self) + if self.is_associative() or self.is_infix(): + return (' ' + self._op + ' ').join([str_protected_child(arg, self) + for arg in self._args]) + return (self._op + '(' + + ', '.join([str(arg) for arg in self._args]) + ')') def get_r(self, mem_read=False, cst_read=False): return reduce(lambda elements, arg: @@ -960,6 +985,11 @@ class ExprOp(Expr): def is_function_call(self): return self._op.startswith('call') + def is_infix(self): + return self._op in [ '-', '+', '*', '^', '&', '|', '>>', '<<', + 'a>>', '>>>', '<<<', '/', '%', '**', + '<u', '<s', '<=u', '<=s', '==' ] + def is_associative(self): "Return True iff current operation is associative" return (self._op in ['+', '*', '^', '&', '|']) @@ -1026,7 +1056,7 @@ class ExprSlice(Expr): return Expr.get_object(cls, (arg, start, stop)) def __str__(self): - return "%s[%d:%d]" % (str(self._arg), self._start, self._stop) + return "%s[%d:%d]" % (str_protected_child(self._arg, self), self._start, self._stop) def get_r(self, mem_read=False, cst_read=False): return self._arg.get_r(mem_read, cst_read) |