restructure + syntactic sugar implementation
This commit is contained in:
118
de.churl.simple/disass.py
Normal file
118
de.churl.simple/disass.py
Normal file
@ -0,0 +1,118 @@
|
||||
import compile
|
||||
|
||||
def disassemble(bytecode, indent='', pc=-1):
|
||||
""" disassemble a bytecode object and print a readabable version of it"""
|
||||
assert isinstance(bytecode, compile.Bytecode)
|
||||
findlabeltargets = FindLabelTargets()
|
||||
findlabeltargets.disassemble(bytecode)
|
||||
disass = Disassembler(indent, findlabeltargets.targets)
|
||||
disass.disassemble(bytecode, pc)
|
||||
|
||||
|
||||
opcode2name = {}
|
||||
for name, value in list(compile.__dict__.items()):
|
||||
if name == name.upper() and isinstance(value, int):
|
||||
opcode2name[value] = name
|
||||
|
||||
|
||||
class AbstractDisassembler(object):
|
||||
|
||||
def read4(self, code, pc):
|
||||
highval = ord(code[pc+3])
|
||||
if highval >= 128:
|
||||
highval -= 256
|
||||
return (ord(code[pc]) |
|
||||
(ord(code[pc+1]) << 8) |
|
||||
(ord(code[pc+2]) << 16) |
|
||||
(highval << 24))
|
||||
|
||||
def disassemble(self, bytecode, currpc=-1):
|
||||
self.currpc = currpc
|
||||
self.bytecode = bytecode
|
||||
code = bytecode.code
|
||||
pc = 0
|
||||
while pc < len(code):
|
||||
self.start(pc)
|
||||
opcode = ord(code[pc])
|
||||
pc += 1
|
||||
if compile.isjump(opcode):
|
||||
oparg = self.read4(code, pc)
|
||||
pc += 4
|
||||
elif compile.hasarg(opcode):
|
||||
oparg = ord(code[pc])
|
||||
pc += 1
|
||||
if oparg >= 128:
|
||||
if oparg > 128:
|
||||
oparg -= 256
|
||||
else:
|
||||
oparg = self.read4(code, pc)
|
||||
pc += 4
|
||||
else:
|
||||
oparg = None
|
||||
self.pc = pc
|
||||
self.end(opcode, oparg)
|
||||
name = opcode2name[opcode]
|
||||
method = getattr(self, name, self.dummy)
|
||||
method(opcode, oparg)
|
||||
|
||||
def start(self, pc):
|
||||
pass
|
||||
|
||||
def end(self, opcode, oparg):
|
||||
pass
|
||||
|
||||
def dummy(self, opcode, oparg):
|
||||
pass
|
||||
|
||||
|
||||
class FindLabelTargets(AbstractDisassembler):
|
||||
|
||||
def __init__(self):
|
||||
self.targets = {}
|
||||
|
||||
def JUMP_IF_FALSE(self, opcode, oparg):
|
||||
self.targets[self.pc + oparg] = True
|
||||
|
||||
JUMP = JUMP_IF_FALSE
|
||||
|
||||
|
||||
class Disassembler(AbstractDisassembler):
|
||||
|
||||
def __init__(self, indent, targets):
|
||||
self.indent = indent
|
||||
self.targets = targets
|
||||
|
||||
def start(self, pc):
|
||||
if pc in self.targets:
|
||||
print(self.indent, '>>', pc)
|
||||
if pc == self.currpc:
|
||||
print(self.indent, '->', pc)
|
||||
|
||||
def end(self, opcode, oparg):
|
||||
print(self.indent, '\t', opcode2name[opcode], end=' ')
|
||||
|
||||
def JUMP_IF_FALSE(self, opcode, oparg):
|
||||
print('\t', '-->', self.pc + oparg)
|
||||
|
||||
JUMP = JUMP_IF_FALSE
|
||||
|
||||
def ASSIGNMENT(self, opcode, oparg):
|
||||
print('\t', repr(self.bytecode.symbols[oparg]))
|
||||
|
||||
METHOD_LOOKUP = ASSIGNMENT
|
||||
ASSIGNMENT_APPEND_PARENT = ASSIGNMENT
|
||||
GET_LOCAL = ASSIGNMENT
|
||||
SET_LOCAL = ASSIGNMENT
|
||||
|
||||
def PRIMITIVE_METHOD_CALL(self, opcode, oparg):
|
||||
import primitives
|
||||
func = primitives.all_primitives[oparg]
|
||||
print('\t', repr('$' + func.__qualname__))
|
||||
|
||||
def dummy(self, opcode, oparg):
|
||||
if oparg is None:
|
||||
print()
|
||||
else:
|
||||
print('\t', oparg)
|
||||
|
||||
|
Reference in New Issue
Block a user