-import collections
import contextlib
import functools
-import mdis.dispatcher
+
import mdis.visitor
import mdis.walker
-
-import openpower.oppc.pc_ast as pc_ast
+import mdis.dispatcher
class Hook(mdis.dispatcher.Hook):
return "\n".join(lines)
- def emit(self, stmt, level=0):
+ def emit(self, stmt="", level=0):
item = ((level + self.__level), stmt)
self.append(item)
-class PseudocodeVisitor(mdis.visitor.ContextVisitor):
+class Visitor(mdis.visitor.ContextVisitor):
def __init__(self, root):
- self.__root = root
- self.__code = collections.defaultdict(lambda: Code())
-
- return super().__init__()
-
- def __iter__(self):
- yield from self.__code.items()
-
- def __getitem__(self, node):
- return self.__code[node]
-
- @Hook(pc_ast.Scope)
- def Scope(self, node):
- yield node
- if node is not self.__root:
- with self[node]:
- for subnode in node:
- for (level, stmt) in self[subnode]:
- self[node].emit(stmt=stmt, level=level)
- else:
- for subnode in node:
- for (level, stmt) in self[subnode]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.Call)
- def Call(self, node):
- yield node
- args = []
- for subnode in node.args:
- for (level, stmt) in self[subnode]:
- assert level == 0
- args.append(stmt)
- args = ", ".join(args)
- stmt = f"{node.name}({args})"
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.Assign, pc_ast.AssignIEA)
- def Assign(self, node):
- mapping = {
- pc_ast.Assign: "<-",
- pc_ast.AssignIEA: "<-iea",
- }
- yield node
- lvalue = str(self[node.lvalue])
- if (isinstance(node.lvalue, (pc_ast.GPR, pc_ast.FPR)) or
- (isinstance(node.lvalue, (pc_ast.Subscript, pc_ast.RangeSubscript)) and
- isinstance(node.lvalue.subject, (pc_ast.GPR, pc_ast.FPR)))):
- lvalue = lvalue.replace("(", "").replace(")", "")
- rvalue = str(self[node.rvalue])
-
- if isinstance(node.rvalue, pc_ast.IfExpr):
- # All right, this deserves an explanation.
- # We basically convert T <- C ? A : B into this code:
- #
- # if C then
- # T <- A
- # else
- # T <- B
- #
- # To make things work, we must ensure that objects are unique.
- # Otherwise we'll reuse the bogus code already produced before.
- (body, orelse) = map(lambda node: node.clone(),
- (node.rvalue.body[0], node.rvalue.orelse[0]))
- body = pc_ast.Scope([node.__class__(lvalue=node.lvalue.clone(), rvalue=body)])
- orelse = pc_ast.Scope([node.__class__(lvalue=node.lvalue.clone(), rvalue=orelse)])
- tmpnode = node.rvalue.clone(body=body, orelse=orelse)
- walker = mdis.walker.Walker()
- traverse(root=tmpnode, visitor=self, walker=walker)
- for (level, stmt) in self[tmpnode]:
- self[node].emit(stmt=stmt, level=level)
- else:
- stmt = " ".join([
- lvalue,
- mapping[node.__class__],
- rvalue,
- ])
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.BinaryExpr)
- def BinaryExpr(self, node):
- yield node
- stmt = " ".join([
- str(self[node.left]),
- str(self[node.op]),
- str(self[node.right]),
- ])
- self[node].emit(stmt=f"({stmt})")
-
- @Hook(pc_ast.IfExpr)
- def IfExpr(self, node):
- yield node
- stmt = " ".join([
- "if",
- str(self[node.test]),
- "then",
- ])
- self[node].emit(stmt=stmt)
- for (level, stmt) in self[node.body]:
- self[node].emit(stmt=stmt, level=level)
- if node.orelse:
- self[node].emit("else")
- for (level, stmt) in self[node.orelse]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.ForExpr)
- def ForExpr(self, node):
- yield node
- stmt = " ".join([
- "for",
- str(self[node.subject]),
- "=",
- str(self[node.start]),
- "to",
- str(self[node.end]),
- ])
- self[node].emit(stmt=stmt)
- for (level, stmt) in self[node.body]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.WhileExpr)
- def WhileExpr(self, node):
- yield node
- stmt = " ".join([
- "do",
- "while",
- str(self[node.test]),
- ])
- self[node].emit(stmt=stmt)
- for (level, stmt) in self[node.body]:
- self[node].emit(stmt=stmt, level=level)
- if node.orelse:
- self[node].emit("else")
- for (level, stmt) in self[node.orelse]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.RepeatExpr)
- def RepeatExpr(self, node):
- yield node
- stmt = " ".join([
- f"[{str(self[node.subject])}]",
- "*",
- str(self[node.times]),
- ])
- self[node].emit(stmt=f"({stmt})")
-
- @Hook(pc_ast.SwitchExpr)
- def SwitchExpr(self, node):
- yield node
- self[node].emit(f"switch({str(self[node.subject])})")
- with self[node]:
- for (level, stmt) in self[node.cases]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.Cases)
- def Cases(self, node):
- yield node
- for subnode in node:
- for (level, stmt) in self[subnode]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.Case)
- def Case(self, node):
- yield node
- for (level, stmt) in self[node.labels]:
- self[node].emit(stmt=stmt, level=level)
- for (level, stmt) in self[node.body]:
- self[node].emit(stmt=stmt, level=level)
-
- @Hook(pc_ast.Labels)
- def Labels(self, node):
- yield node
- if ((len(node) == 1) and isinstance(node[-1], pc_ast.DefaultLabel)):
- stmt = "default:"
- else:
- labels = ", ".join(map(lambda label: str(self[label]), node))
- stmt = f"case ({labels}):"
- self[node].emit(stmt=stmt)
+ self.__walker = mdis.walker.Walker()
- @Hook(pc_ast.Label)
- def Label(self, node):
- yield node
- self[node].emit(stmt=str(node))
-
- @Hook(pc_ast.DefaultLabel)
- def DefaultLabel(self, node):
- yield node
- self[node].emit(stmt="default:")
-
- @Hook(pc_ast.UnaryExpr)
- def UnaryExpr(self, node):
- yield node
- stmt = "".join([
- str(self[node.op]),
- f"({str(self[node.value])})",
- ])
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.BinLiteral, pc_ast.DecLiteral, pc_ast.HexLiteral)
- def Integer(self, node):
- yield node
- self[node].emit(stmt=str(node))
-
- @Hook(pc_ast.StringLiteral)
- def StringLiteral(self, node):
- yield node
- self[node].emit(stmt=f"'{str(node)}'")
-
- @Hook(pc_ast.Symbol)
- def Symbol(self, node):
- yield node
- self[node].emit(stmt=str(node))
-
- @Hook(pc_ast.Attribute)
- def Attribute(self, node):
- yield node
- stmt = ".".join([
- str(self[node.subject]),
- str(self[node.name]),
- ])
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.Not, pc_ast.Add, pc_ast.Sub,
- pc_ast.Mul, pc_ast.MulS, pc_ast.MulU,
- pc_ast.Div, pc_ast.DivT, pc_ast.Mod,
- pc_ast.Sqrt,
- pc_ast.Eq, pc_ast.NotEq,
- pc_ast.Lt, pc_ast.Le, pc_ast.LtU,
- pc_ast.Gt, pc_ast.Ge, pc_ast.GtU,
- pc_ast.LShift, pc_ast.RShift,
- pc_ast.AssignOp, pc_ast.AssignIEAOp,
- pc_ast.BitAnd, pc_ast.BitOr, pc_ast.BitXor,
- pc_ast.BitConcat)
- def Op(self, node):
- yield node
- mapping = {
- pc_ast.Not: "¬",
- pc_ast.Add: "+",
- pc_ast.Sub: "-",
- pc_ast.Mul: "*",
- pc_ast.MulS: "*si",
- pc_ast.MulU: "*ui",
- pc_ast.Div: "/",
- pc_ast.DivT: "÷",
- pc_ast.Mod: "%",
- pc_ast.Sqrt: "√",
- pc_ast.Eq: "=",
- pc_ast.NotEq: "!=",
- pc_ast.Lt: "<",
- pc_ast.Le: "<=",
- pc_ast.LtU: "<u",
- pc_ast.Gt: ">",
- pc_ast.Ge: ">=",
- pc_ast.GtU: ">u",
- pc_ast.LShift: "<<",
- pc_ast.RShift: ">>",
- pc_ast.AssignOp: "<-",
- pc_ast.AssignIEAOp: "<-iea",
- pc_ast.BitAnd: "&",
- pc_ast.BitOr: "|",
- pc_ast.BitXor: "^",
- pc_ast.BitConcat: "||",
- }
- stmt = mapping[node.__class__]
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.LParenthesis, pc_ast.RParenthesis,
- pc_ast.LBracket, pc_ast.RBracket)
- def BracketOrParenthesis(self, node):
- yield node
- mapping = {
- pc_ast.LParenthesis: "(",
- pc_ast.RParenthesis: ")",
- pc_ast.LBracket: "[",
- pc_ast.RBracket: "]",
- }
- stmt = mapping[node.__class__]
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.Subscript)
- def Subscript(self, node):
- yield node
- stmt = "".join([
- str(self[node.subject]),
- "[",
- str(self[node.index]),
- "]",
- ])
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.RangeSubscript)
- def RangeSubscript(self, node):
- yield node
- stmt = "".join([
- str(self[node.subject]),
- "[",
- str(self[node.start]),
- ":",
- str(self[node.end]),
- "]",
- ])
- self[node].emit(stmt=stmt)
-
- @Hook(pc_ast.Colon)
- def Colon(self, node):
- yield node
- self[node].emit(stmt=":")
-
- @Hook(pc_ast.Linebreak, pc_ast.Endmarker)
- def Ignore(self, node):
- yield node
-
- @Hook(pc_ast.Keyword)
- def Keyword(self, node):
- yield node
- self[node].emit(stmt=node.__doc__)
-
- @Hook(pc_ast.Sequence)
- def Sequence(self, node):
- yield node
- stmt = ",".join(map(lambda subnode: str(self[subnode]), node))
- self[node].emit(stmt=f"({stmt})")
-
- @Hook(pc_ast.Literal)
- def Literal(self, node):
- yield node
- self[node].emit(stmt=str(node))
-
- @Hook(pc_ast.GPR, pc_ast.FPR, pc_ast.GPRZero)
- def Reg(self, node):
- yield node
- if isinstance(node, pc_ast.GPRZero):
- self[node].emit(stmt=f"({str(node)}|0)")
- else:
- self[node].emit(stmt=f"({str(node)})")
-
- @Hook(pc_ast.Node)
- def Node(self, node):
- raise NotImplementedError(type(node))
-
-
-def traverse(root, visitor, walker):
- with visitor(root):
- for node in walker(root):
- traverse(root=node, visitor=visitor, walker=walker)
+ self.traverse(root=root)
+ return super().__init__()
-def pseudocode(root):
- walker = mdis.walker.Walker()
- visitor = PseudocodeVisitor(root=root)
- traverse(root=root, visitor=visitor, walker=walker)
- for (level, stmt) in visitor[root]:
- yield (level, stmt)
+ def traverse(self, root):
+ with self(root):
+ for node in self.__walker(root):
+ self.traverse(root=node)