More python2 -> python3 compatibility

This commit is contained in:
rocky
2015-12-11 17:54:30 -05:00
parent d3c732298c
commit b3c8cbb83f
19 changed files with 387 additions and 286 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
*.pyc *.pyc
*~ *~
/.python-version /.python-version
/uncompyle6.egg-info
build build

56
__pkginfo__.py Normal file
View File

@@ -0,0 +1,56 @@
"""uncompyle6 packaging information"""
# To the extent possible we make this file look more like a
# configuration file rather than code like setup.py. I find putting
# configuration stuff in the middle of a function call in setup.py,
# which for example requires commas in between parameters, is a little
# less elegant than having it here with reduced code, albeit there
# still is some room for improvement.
# Things that change more often go here.
copyright = """
Copyright (C) 2015 Rocky Bernstein <rocky@gnu.org>.
"""
# classifiers = ['Development Status :: 5 - Production/Stable',
# 'Environment :: Console',
# 'Intended Audience :: Developers',
# 'License :: OSI Approved :: GNU General Public License (GPL)',
# 'Operating System :: OS Independent',
# 'Programming Language :: Python',
# 'Topic :: Software Development :: Debuggers',
# 'Topic :: Software Development :: Libraries :: Python Modules',
# ]
# The rest in alphabetic order
author = "Rocky Bernstein"
author_email = "rocky@gnu.org"
ftp_url = None
# license = 'GPL'
mailing_list = 'python-debugger@googlegroups.com'
modname = 'uncompyle6'
packages = ['uncompyle6', 'uncompyle6.opcodes']
py_modules = None
short_desc = 'Python byte-code to source-code converter'
import os
import os.path, sys
def get_srcdir():
filename = os.path.normcase(os.path.dirname(os.path.abspath(__file__)))
return os.path.realpath(filename)
# VERSION.py sets variable VERSION.
ns = {}
version = '2.0'
web = 'https://github.com/rocky/uncompyle6/'
# tracebacks in zip files are funky and not debuggable
zip_safe = False
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
long_description = ( read("README.rst") + '\n' )

View File

@@ -1,15 +1,38 @@
#! python #! python
"""Setup script for the 'uncompyle' distribution.""" """Setup script for the 'uncompyle6' distribution."""
from distutils.core import setup, Extension from distutils.core import setup, Extension
setup (name = "uncompyle6", # Get the package information used in setup().
version = "2.0", # from __pkginfo__ import \
description = "Python byte-code to source-code converter", # author, author_email, classifiers, \
author = "Mysterie", # install_requires, license, long_description, \
author_email = "kajusska@gmail.com", # modname, packages, py_modules, \
url = "http://github.com/Mysterie/uncompyle2", # short_desc, version, web, zip_safe
packages=['uncompyle6', 'uncompyle6.opcode'],
scripts=['scripts/uncompyle6'] from __pkginfo__ import \
) author, author_email, \
long_description, \
modname, packages, py_modules, \
short_desc, version, web, zip_safe
__import__('pkg_resources')
from setuptools import setup
setup(
author = author,
author_email = author_email,
# classifiers = classifiers,
description = short_desc,
# install_requires = install_requires,
# license = license,
long_description = long_description,
py_modules = py_modules,
name = modname,
packages = packages,
test_suite = 'nose.collector',
url = web,
setup_requires = ['nose>=1.0'],
version = version,
zip_safe = zip_safe)

View File

@@ -1,4 +1,6 @@
#! python #!/usr/bin/env python
from __future__ import print_function
""" """
compile_tests -- compile test patterns for the decompyle test suite compile_tests -- compile test patterns for the decompyle test suite
""" """
@@ -20,8 +22,8 @@ for opt, val in opts:
if args: if args:
raise 'This tool does not want any arguments' raise 'This tool does not want any arguments'
print "Using files in dir %s" % src_dir print("Using files in dir %s" % src_dir)
print "Compiling into dir %s" % work_dir print("Compiling into dir %s" % work_dir)
tests = {} tests = {}
@@ -46,6 +48,7 @@ tests['2.3'] = tests['2.2']
tests['2.5'] = tests['2.3'] tests['2.5'] = tests['2.3']
tests['2.6'] = tests['2.5'] tests['2.6'] = tests['2.5']
tests['2.7'] = ['mine'] + tests['2.6'] tests['2.7'] = ['mine'] + tests['2.6']
tests['3.4'] = ['mine']
total_tests = len(tests['2.7']) total_tests = len(tests['2.7'])
#tests['2.2'].sort(); print tests['2.2'] #tests['2.2'].sort(); print tests['2.2']
@@ -62,13 +65,13 @@ def compile_for_version(version):
os.mkdir(target_dir) os.mkdir(target_dir)
for file in tests[version]: for file in tests[version]:
compile(file, target_dir) compile(file, target_dir)
try: try:
version = '%i.%i' % sys.version_info[:2] version = '%i.%i' % sys.version_info[:2]
except AttributeError: except AttributeError:
version = sys.version[:3] version = sys.version[:3]
print 'Compiling test files for Python', version, print('Compiling test files for Python', version)
print '(%i/%i files)' % (len(tests[version]), total_tests) print('(%i/%i files)' % (len(tests[version]), total_tests))
compile_for_version(version) compile_for_version(version)
print 'Done.' print('Done.')

View File

@@ -1,4 +1,5 @@
#! python #!/usr/bin/env python
from __future__ import print_function
''' '''
test_pythonlib -- uncompyle and verify Python libraries test_pythonlib -- uncompyle and verify Python libraries
@@ -19,7 +20,7 @@ Step 2: Run the test:
test_pythonlib --mylib --verify # decompile verify 'mylib' test_pythonlib --mylib --verify # decompile verify 'mylib'
''' '''
from uncompyle2 import main, verify from uncompyle6 import main, verify
import getopt, sys import getopt, sys
import os, time, shutil import os, time, shutil
from fnmatch import fnmatch from fnmatch import fnmatch
@@ -44,11 +45,11 @@ test_options = {
#----- #-----
def help(): def help():
print 'Usage-Examples:' print('Usage-Examples:')
print 'test_pythonlib --all # decompile all tests (suite + libs)' print('test_pythonlib --all # decompile all tests (suite + libs)')
print 'test_pythonlib --all --verify # decomyile all tests and verify results' print('test_pythonlib --all --verify # decomyile all tests and verify results')
print 'test_pythonlib --test # decompile only the testsuite' print('test_pythonlib --test # decompile only the testsuite')
print 'test_pythonlib --2.2 --verify # decompile and verify python lib 2.2' print('test_pythonlib --2.2 --verify # decompile and verify python lib 2.2')
def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=0): def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=0):
def visitor(files, dirname, names): def visitor(files, dirname, names):
@@ -69,18 +70,18 @@ def do_tests(src_dir, patterns, target_dir, start_with=None, do_verify=0):
try: try:
start_with = files.index(start_with) start_with = files.index(start_with)
files = files[start_with:] files = files[start_with:]
print '>>> starting with file', files[0] print('>>> starting with file', files[0])
except ValueError: except ValueError:
pass pass
print time.ctime() print(time.ctime())
print 'Working directory: ', src_dir print('Working directory: ', src_dir)
try: try:
main(src_dir, target_dir, files, [], do_verify=do_verify) main(src_dir, target_dir, files, [], do_verify=do_verify)
except (KeyboardInterrupt, OSError): except (KeyboardInterrupt, OSError):
print print
exit(1) exit(1)
if __name__ == '__main__': if __name__ == '__main__':
do_verify = 0 do_verify = 0
test_dirs = [] test_dirs = []

View File

@@ -1,6 +1,6 @@
import uncompyle2 import uncompyle6
from uncompyle2 import uncompyle, walker, verify, magics from uncompyle6 import uncompyle, walker, verify, magics
from uncompyle2.spark import GenericASTTraversal, GenericASTTraversalPruningException from uncompyle6.spark import GenericASTTraversal, GenericASTTraversalPruningException
import sys, inspect, types, cStringIO import sys, inspect, types, cStringIO
from collections import namedtuple from collections import namedtuple
@@ -137,7 +137,7 @@ def uncompyle_find(version, co, find_offset, out=sys.stdout, showasm=0, showast=
# store final output stream for case of error # store final output stream for case of error
__real_out = out or sys.stdout __real_out = out or sys.stdout
if version == 2.7: if version == 2.7:
import uncompyle2.scanner27 as scan import uncompyle6.scanner27 as scan
scanner = scan.Scanner27() scanner = scan.Scanner27()
elif version == 2.6: elif version == 2.6:
import scanner26 as scan import scanner26 as scan

View File

@@ -1,3 +1,6 @@
from __future__ import print_function
''' '''
Copyright (c) 1999 John Aycock Copyright (c) 1999 John Aycock
Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com> Copyright (c) 2000 by hartmut Goebel <h.goebel@crazy-compilers.com>
@@ -68,9 +71,9 @@ def _load_module(filename):
try: try:
version = float(magics.versions[magic]) version = float(magics.versions[magic])
except KeyError: except KeyError:
raise ImportError, "Unknown magic number %s in %s" % (ord(magic[0])+256*ord(magic[1]), filename) raise ImportError("Unknown magic number %s in %s" % (ord(magic[0])+256*ord(magic[1]), filename))
if (version > 2.7) or (version < 2.5): if (version > 2.7) or (version < 2.5):
raise ImportError, "This is a Python %s file! Only Python 2.5 to 2.7 files are supported." % version raise ImportError("This is a Python %s file! Only Python 2.5 to 2.7 files are supported." % version)
#print version #print version
fp.read(4) # timestamp fp.read(4) # timestamp
co = dis.marshalLoad(fp) co = dis.marshalLoad(fp)
@@ -105,7 +108,7 @@ def uncompyle(version, co, out=None, showasm=0, showast=0):
walk = walker.Walker(out, scanner, showast=showast) walk = walker.Walker(out, scanner, showast=showast)
try: try:
ast = walk.build_ast(tokens, customize) ast = walk.build_ast(tokens, customize)
except walker.ParserError, e : # parser failed, dump disassembly except walker.ParserError as e : # parser failed, dump disassembly
print >>__real_out, e print >>__real_out, e
raise raise
del tokens # save memory del tokens # save memory
@@ -223,9 +226,9 @@ def main(in_base, out_base, files, codes, outfile=None,
if do_verify: if do_verify:
try: try:
verify.compare_code_with_srcfile(infile, outfile) verify.compare_code_with_srcfile(infile, outfile)
if not outfile: print '\n# okay decompyling', infile, __memUsage() if not outfile: print('\n# okay decompyling', infile, __memUsage())
okay_files += 1 okay_files += 1
except verify.VerifyCmpError, e: except verify.VerifyCmpError as e:
verify_failed_files += 1 verify_failed_files += 1
os.rename(outfile, outfile + '_unverified') os.rename(outfile, outfile + '_unverified')
if not outfile: if not outfile:
@@ -233,7 +236,7 @@ def main(in_base, out_base, files, codes, outfile=None,
print >>sys.stderr, e print >>sys.stderr, e
else: else:
okay_files += 1 okay_files += 1
if not outfile: print '\n# okay decompyling', infile, __memUsage() if not outfile: print('\n# okay decompyling', infile, __memUsage())
if outfile: if outfile:
sys.stdout.write("decompiled %i files: %i okay, %i failed, %i verify failed\r" % (tot_files, okay_files, failed_files, verify_failed_files)) sys.stdout.write("decompiled %i files: %i okay, %i failed, %i verify failed\r" % (tot_files, okay_files, failed_files, verify_failed_files))
sys.stdout.flush() sys.stdout.flush()

View File

@@ -1,16 +1,20 @@
from __future__ import print_function from __future__ import print_function
import struct
import struct, sys
__all__ = ['magics', 'versions'] __all__ = ['magics', 'versions']
def __build_magic(magic): def __build_magic(magic):
return struct.pack('Hcc', magic, '\r', '\n') if (sys.version_info > (3, 0)):
return struct.pack('Hcc', magic, bytes('\r', 'utf-8'), bytes('\n', 'utf-8'))
else:
return struct.pack('Hcc', magic, '\r', '\n')
by_magic = {} by_magic = {}
by_version = {} by_version = {}
def __by_version(magics): def __by_version(magics):
for m, v in magics.items(): for m, v in list(magics.items()):
by_magic[m] = v by_magic[m] = v
by_version[v] = m by_version[v] = m
return by_version return by_version
@@ -77,6 +81,7 @@ def test():
magic_20 = magics['2.0'] magic_20 = magics['2.0']
current = imp.get_magic() current = imp.get_magic()
current_version = struct.unpack('HBB', current)[0] current_version = struct.unpack('HBB', current)[0]
from trepan.api import debug; debug()
magic_current = by_magic[ current ] magic_current = by_magic[ current ]
print(type(magic_20), len(magic_20), repr(magic_20)) print(type(magic_20), len(magic_20), repr(magic_20))
print() print()

View File

@@ -1,3 +1,5 @@
from __future__ import print_function
''' '''
Copyright (c) 1999 John Aycock Copyright (c) 1999 John Aycock
Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com> Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
@@ -9,8 +11,13 @@
__all__ = ['parse', 'AST', 'ParserError', 'Parser'] __all__ = ['parse', 'AST', 'ParserError', 'Parser']
from spark import GenericASTBuilder from spark import GenericASTBuilder
import string, exceptions, sys import string, sys
from UserList import UserList
if (sys.version_info > (3, 0)):
intern = sys.intern
from collections import UserList
else:
from UserList import UserList
from scanner import Token from scanner import Token
@@ -44,9 +51,10 @@ class ParserError(Exception):
def __str__(self): def __str__(self):
return "Syntax error at or near `%r' token at offset %s\n" % \ return "Syntax error at or near `%r' token at offset %s\n" % \
(self.token, self.offset) (self.token, self.offset)
class Parser(GenericASTBuilder): class Parser(GenericASTBuilder):
def __init__(self): def __init__(self):
GenericASTBuilder.__init__(self, AST, 'stmts') GenericASTBuilder.__init__(self, AST, 'stmts')
self.customized = {} self.customized = {}
@@ -57,7 +65,7 @@ class Parser(GenericASTBuilder):
collector to collect this object. collector to collect this object.
""" """
for dict in (self.rule2func, self.rules, self.rule2name): for dict in (self.rule2func, self.rules, self.rule2name):
for i in dict.keys(): for i in list(dict.keys()):
dict[i] = None dict[i] = None
for i in dir(self): for i in dir(self):
setattr(self, i, None) setattr(self, i, None)
@@ -67,7 +75,7 @@ class Parser(GenericASTBuilder):
def typestring(self, token): def typestring(self, token):
return token.type return token.type
def p_funcdef(self, args): def p_funcdef(self, args):
''' '''
stmt ::= funcdef stmt ::= funcdef
@@ -92,26 +100,26 @@ class Parser(GenericASTBuilder):
list_iter ::= lc_body list_iter ::= lc_body
_come_from ::= COME_FROM _come_from ::= COME_FROM
_come_from ::= _come_from ::=
list_for ::= expr _for designator list_iter JUMP_BACK list_for ::= expr _for designator list_iter JUMP_BACK
list_if ::= expr jmp_false list_iter list_if ::= expr jmp_false list_iter
list_if_not ::= expr jmp_true list_iter list_if_not ::= expr jmp_true list_iter
lc_body ::= expr LIST_APPEND lc_body ::= expr LIST_APPEND
''' '''
def p_setcomp(self, args): def p_setcomp(self, args):
''' '''
expr ::= setcomp expr ::= setcomp
setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 setcomp ::= LOAD_SETCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= setcomp_func stmt ::= setcomp_func
setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter setcomp_func ::= BUILD_SET_0 LOAD_FAST FOR_ITER designator comp_iter
JUMP_BACK RETURN_VALUE RETURN_LAST JUMP_BACK RETURN_VALUE RETURN_LAST
comp_iter ::= comp_if comp_iter ::= comp_if
comp_iter ::= comp_ifnot comp_iter ::= comp_ifnot
comp_iter ::= comp_for comp_iter ::= comp_for
@@ -131,11 +139,11 @@ class Parser(GenericASTBuilder):
def p_genexpr(self, args): def p_genexpr(self, args):
''' '''
expr ::= genexpr expr ::= genexpr
genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= genexpr_func stmt ::= genexpr_func
genexpr_func ::= LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK genexpr_func ::= LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK
''' '''
@@ -145,7 +153,7 @@ class Parser(GenericASTBuilder):
expr ::= dictcomp expr ::= dictcomp
dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
stmt ::= dictcomp_func stmt ::= dictcomp_func
dictcomp_func ::= BUILD_MAP LOAD_FAST FOR_ITER designator dictcomp_func ::= BUILD_MAP LOAD_FAST FOR_ITER designator
comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST
@@ -177,7 +185,7 @@ class Parser(GenericASTBuilder):
inplace_op ::= INPLACE_RSHIFT inplace_op ::= INPLACE_RSHIFT
inplace_op ::= INPLACE_AND inplace_op ::= INPLACE_AND
inplace_op ::= INPLACE_XOR inplace_op ::= INPLACE_XOR
inplace_op ::= INPLACE_OR inplace_op ::= INPLACE_OR
''' '''
def p_assign(self, args): def p_assign(self, args):
@@ -197,11 +205,11 @@ class Parser(GenericASTBuilder):
stmt ::= print_items_stmt stmt ::= print_items_stmt
stmt ::= print_nl stmt ::= print_nl
stmt ::= print_items_nl_stmt stmt ::= print_items_nl_stmt
print_items_stmt ::= expr PRINT_ITEM print_items_opt print_items_stmt ::= expr PRINT_ITEM print_items_opt
print_items_nl_stmt ::= expr PRINT_ITEM print_items_opt PRINT_NEWLINE_CONT print_items_nl_stmt ::= expr PRINT_ITEM print_items_opt PRINT_NEWLINE_CONT
print_items_opt ::= print_items print_items_opt ::= print_items
print_items_opt ::= print_items_opt ::=
print_items ::= print_items print_item print_items ::= print_items print_item
print_items ::= print_item print_items ::= print_item
print_item ::= expr PRINT_ITEM_CONT print_item ::= expr PRINT_ITEM_CONT
@@ -222,7 +230,7 @@ class Parser(GenericASTBuilder):
''' '''
def p_import20(self, args): def p_import20(self, args):
''' '''
stmt ::= importstmt stmt ::= importstmt
stmt ::= importfrom stmt ::= importfrom
stmt ::= importstar stmt ::= importstar
@@ -234,20 +242,20 @@ class Parser(GenericASTBuilder):
import_as ::= IMPORT_NAME load_attrs designator import_as ::= IMPORT_NAME load_attrs designator
import_as ::= IMPORT_FROM designator import_as ::= IMPORT_FROM designator
importstmt ::= LOAD_CONST LOAD_CONST import_as importstmt ::= LOAD_CONST LOAD_CONST import_as
importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME IMPORT_STAR importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME IMPORT_STAR
importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist2 POP_TOP importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME importlist2 POP_TOP
importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT IMPORT_STAR importstar ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT IMPORT_STAR
importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT importlist2 POP_TOP importfrom ::= LOAD_CONST LOAD_CONST IMPORT_NAME_CONT importlist2 POP_TOP
importmultiple ::= LOAD_CONST LOAD_CONST import_as imports_cont importmultiple ::= LOAD_CONST LOAD_CONST import_as imports_cont
imports_cont ::= imports_cont import_cont imports_cont ::= imports_cont import_cont
imports_cont ::= import_cont imports_cont ::= import_cont
import_cont ::= LOAD_CONST LOAD_CONST import_as_cont import_cont ::= LOAD_CONST LOAD_CONST import_as_cont
import_as_cont ::= IMPORT_NAME_CONT designator import_as_cont ::= IMPORT_NAME_CONT designator
import_as_cont ::= IMPORT_NAME_CONT load_attrs designator import_as_cont ::= IMPORT_NAME_CONT load_attrs designator
import_as_cont ::= IMPORT_FROM designator import_as_cont ::= IMPORT_FROM designator
load_attrs ::= LOAD_ATTR load_attrs ::= LOAD_ATTR
load_attrs ::= load_attrs LOAD_ATTR load_attrs ::= load_attrs LOAD_ATTR
''' '''
@@ -259,11 +267,11 @@ class Parser(GenericASTBuilder):
sstmt ::= stmt sstmt ::= stmt
sstmt ::= ifelsestmtr sstmt ::= ifelsestmtr
sstmt ::= return_stmt RETURN_LAST sstmt ::= return_stmt RETURN_LAST
stmts_opt ::= stmts stmts_opt ::= stmts
stmts_opt ::= passstmt stmts_opt ::= passstmt
passstmt ::= passstmt ::=
_stmts ::= _stmts stmt _stmts ::= _stmts stmt
_stmts ::= stmt _stmts ::= stmt
@@ -271,7 +279,7 @@ class Parser(GenericASTBuilder):
c_stmts ::= _stmts lastc_stmt c_stmts ::= _stmts lastc_stmt
c_stmts ::= lastc_stmt c_stmts ::= lastc_stmt
c_stmts ::= continue_stmts c_stmts ::= continue_stmts
lastc_stmt ::= iflaststmt lastc_stmt ::= iflaststmt
lastc_stmt ::= whileelselaststmt lastc_stmt ::= whileelselaststmt
lastc_stmt ::= forelselaststmt lastc_stmt ::= forelselaststmt
@@ -281,28 +289,28 @@ class Parser(GenericASTBuilder):
c_stmts_opt ::= c_stmts c_stmts_opt ::= c_stmts
c_stmts_opt ::= passstmt c_stmts_opt ::= passstmt
l_stmts ::= _stmts l_stmts ::= _stmts
l_stmts ::= return_stmts l_stmts ::= return_stmts
l_stmts ::= continue_stmts l_stmts ::= continue_stmts
l_stmts ::= _stmts lastl_stmt l_stmts ::= _stmts lastl_stmt
l_stmts ::= lastl_stmt l_stmts ::= lastl_stmt
lastl_stmt ::= iflaststmtl lastl_stmt ::= iflaststmtl
lastl_stmt ::= ifelsestmtl lastl_stmt ::= ifelsestmtl
lastl_stmt ::= forelselaststmtl lastl_stmt ::= forelselaststmtl
lastl_stmt ::= tryelsestmtl lastl_stmt ::= tryelsestmtl
l_stmts_opt ::= l_stmts l_stmts_opt ::= l_stmts
l_stmts_opt ::= passstmt l_stmts_opt ::= passstmt
suite_stmts ::= _stmts suite_stmts ::= _stmts
suite_stmts ::= return_stmts suite_stmts ::= return_stmts
suite_stmts ::= continue_stmts suite_stmts ::= continue_stmts
suite_stmts_opt ::= suite_stmts suite_stmts_opt ::= suite_stmts
suite_stmts_opt ::= passstmt suite_stmts_opt ::= passstmt
else_suite ::= suite_stmts else_suite ::= suite_stmts
else_suitel ::= l_stmts else_suitel ::= l_stmts
else_suitec ::= c_stmts else_suitec ::= c_stmts
@@ -324,7 +332,7 @@ class Parser(GenericASTBuilder):
store_subscr ::= expr expr STORE_SUBSCR store_subscr ::= expr expr STORE_SUBSCR
designator ::= unpack designator ::= unpack
designator ::= unpack_list designator ::= unpack_list
stmt ::= classdef stmt ::= classdef
stmt ::= call_stmt stmt ::= call_stmt
call_stmt ::= expr POP_TOP call_stmt ::= expr POP_TOP
@@ -333,21 +341,21 @@ class Parser(GenericASTBuilder):
return_stmt ::= ret_expr RETURN_VALUE return_stmt ::= ret_expr RETURN_VALUE
return_stmts ::= return_stmt return_stmts ::= return_stmt
return_stmts ::= _stmts return_stmt return_stmts ::= _stmts return_stmt
return_if_stmts ::= return_if_stmt return_if_stmts ::= return_if_stmt
return_if_stmts ::= _stmts return_if_stmt return_if_stmts ::= _stmts return_if_stmt
return_if_stmt ::= ret_expr RETURN_END_IF return_if_stmt ::= ret_expr RETURN_END_IF
stmt ::= break_stmt stmt ::= break_stmt
break_stmt ::= BREAK_LOOP break_stmt ::= BREAK_LOOP
stmt ::= continue_stmt stmt ::= continue_stmt
continue_stmt ::= CONTINUE continue_stmt ::= CONTINUE
continue_stmt ::= CONTINUE_LOOP continue_stmt ::= CONTINUE_LOOP
continue_stmts ::= _stmts lastl_stmt continue_stmt continue_stmts ::= _stmts lastl_stmt continue_stmt
continue_stmts ::= lastl_stmt continue_stmt continue_stmts ::= lastl_stmt continue_stmt
continue_stmts ::= continue_stmt continue_stmts ::= continue_stmt
stmt ::= raise_stmt0 stmt ::= raise_stmt0
stmt ::= raise_stmt1 stmt ::= raise_stmt1
stmt ::= raise_stmt2 stmt ::= raise_stmt2
@@ -357,16 +365,16 @@ class Parser(GenericASTBuilder):
raise_stmt1 ::= expr RAISE_VARARGS_1 raise_stmt1 ::= expr RAISE_VARARGS_1
raise_stmt2 ::= expr expr RAISE_VARARGS_2 raise_stmt2 ::= expr expr RAISE_VARARGS_2
raise_stmt3 ::= expr expr expr RAISE_VARARGS_3 raise_stmt3 ::= expr expr expr RAISE_VARARGS_3
stmt ::= exec_stmt stmt ::= exec_stmt
exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT exec_stmt ::= expr exprlist DUP_TOP EXEC_STMT
exec_stmt ::= expr exprlist EXEC_STMT exec_stmt ::= expr exprlist EXEC_STMT
stmt ::= assert stmt ::= assert
stmt ::= assert2 stmt ::= assert2
stmt ::= ifstmt stmt ::= ifstmt
stmt ::= ifelsestmt stmt ::= ifelsestmt
stmt ::= whilestmt stmt ::= whilestmt
stmt ::= whilenotstmt stmt ::= whilenotstmt
stmt ::= while1stmt stmt ::= while1stmt
@@ -379,7 +387,7 @@ class Parser(GenericASTBuilder):
stmt ::= tryfinallystmt stmt ::= tryfinallystmt
stmt ::= withstmt stmt ::= withstmt
stmt ::= withasstmt stmt ::= withasstmt
stmt ::= del_stmt stmt ::= del_stmt
del_stmt ::= DELETE_FAST del_stmt ::= DELETE_FAST
del_stmt ::= DELETE_NAME del_stmt ::= DELETE_NAME
@@ -391,12 +399,12 @@ class Parser(GenericASTBuilder):
del_stmt ::= delete_subscr del_stmt ::= delete_subscr
delete_subscr ::= expr expr DELETE_SUBSCR delete_subscr ::= expr expr DELETE_SUBSCR
del_stmt ::= expr DELETE_ATTR del_stmt ::= expr DELETE_ATTR
kwarg ::= LOAD_CONST expr kwarg ::= LOAD_CONST expr
classdef ::= LOAD_CONST expr mkfunc classdef ::= LOAD_CONST expr mkfunc
CALL_FUNCTION_0 BUILD_CLASS designator CALL_FUNCTION_0 BUILD_CLASS designator
stmt ::= classdefdeco stmt ::= classdefdeco
classdefdeco ::= classdefdeco1 designator classdefdeco ::= classdefdeco1 designator
classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1 classdefdeco1 ::= expr classdefdeco1 CALL_FUNCTION_1
@@ -411,11 +419,11 @@ class Parser(GenericASTBuilder):
jmp_false ::= JUMP_IF_FALSE jmp_false ::= JUMP_IF_FALSE
jmp_true ::= POP_JUMP_IF_TRUE jmp_true ::= POP_JUMP_IF_TRUE
jmp_true ::= JUMP_IF_TRUE jmp_true ::= JUMP_IF_TRUE
assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr CALL_FUNCTION_1 RAISE_VARARGS_1
assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2 assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2
assert_expr ::= expr assert_expr ::= expr
assert_expr ::= assert_expr_or assert_expr ::= assert_expr_or
assert_expr ::= assert_expr_and assert_expr ::= assert_expr_and
@@ -423,17 +431,17 @@ class Parser(GenericASTBuilder):
assert_expr_and ::= assert_expr jmp_false expr assert_expr_and ::= assert_expr jmp_false expr
ifstmt ::= testexpr _ifstmts_jump ifstmt ::= testexpr _ifstmts_jump
testexpr ::= testfalse testexpr ::= testfalse
testexpr ::= testtrue testexpr ::= testtrue
testfalse ::= expr jmp_false testfalse ::= expr jmp_false
testtrue ::= expr jmp_true testtrue ::= expr jmp_true
_ifstmts_jump ::= return_if_stmts _ifstmts_jump ::= return_if_stmts
_ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM
iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE
iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK iflaststmtl ::= testexpr c_stmts_opt JUMP_BACK
ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite COME_FROM ifelsestmt ::= testexpr c_stmts_opt JUMP_FORWARD else_suite COME_FROM
@@ -443,8 +451,8 @@ class Parser(GenericASTBuilder):
ifelsestmtr ::= testexpr return_if_stmts return_stmts ifelsestmtr ::= testexpr return_if_stmts return_stmts
ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel
trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
try_middle COME_FROM try_middle COME_FROM
@@ -461,12 +469,12 @@ class Parser(GenericASTBuilder):
END_FINALLY END_FINALLY
try_middle ::= JUMP_FORWARD COME_FROM except_stmts try_middle ::= JUMP_FORWARD COME_FROM except_stmts
END_FINALLY COME_FROM END_FINALLY COME_FROM
except_stmts ::= except_stmts except_stmt except_stmts ::= except_stmts except_stmt
except_stmts ::= except_stmt except_stmts ::= except_stmt
except_stmt ::= except_cond1 except_suite except_stmt ::= except_cond1 except_suite
except_stmt ::= except_cond2 except_suite except_stmt ::= except_cond2 except_suite
except_stmt ::= except except_stmt ::= except
except_suite ::= c_stmts_opt JUMP_FORWARD except_suite ::= c_stmts_opt JUMP_FORWARD
@@ -474,22 +482,22 @@ class Parser(GenericASTBuilder):
except_suite ::= return_stmts except_suite ::= return_stmts
except_cond1 ::= DUP_TOP expr COMPARE_OP except_cond1 ::= DUP_TOP expr COMPARE_OP
jmp_false POP_TOP POP_TOP POP_TOP jmp_false POP_TOP POP_TOP POP_TOP
except_cond2 ::= DUP_TOP expr COMPARE_OP except_cond2 ::= DUP_TOP expr COMPARE_OP
jmp_false POP_TOP designator POP_TOP jmp_false POP_TOP designator POP_TOP
except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt JUMP_FORWARD except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt JUMP_FORWARD
except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt jmp_abs except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt jmp_abs
except ::= POP_TOP POP_TOP POP_TOP return_stmts except ::= POP_TOP POP_TOP POP_TOP return_stmts
jmp_abs ::= JUMP_ABSOLUTE jmp_abs ::= JUMP_ABSOLUTE
jmp_abs ::= JUMP_BACK jmp_abs ::= JUMP_BACK
tryfinallystmt ::= SETUP_FINALLY suite_stmts tryfinallystmt ::= SETUP_FINALLY suite_stmts
POP_BLOCK LOAD_CONST POP_BLOCK LOAD_CONST
COME_FROM suite_stmts_opt END_FINALLY COME_FROM suite_stmts_opt END_FINALLY
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt
POP_BLOCK LOAD_CONST COME_FROM POP_BLOCK LOAD_CONST COME_FROM
WITH_CLEANUP END_FINALLY WITH_CLEANUP END_FINALLY
@@ -527,7 +535,7 @@ class Parser(GenericASTBuilder):
for_block ::= l_stmts_opt JUMP_BACK for_block ::= l_stmts_opt JUMP_BACK
for_block ::= return_stmts _come_from for_block ::= return_stmts _come_from
forstmt ::= SETUP_LOOP expr _for designator forstmt ::= SETUP_LOOP expr _for designator
for_block POP_BLOCK COME_FROM for_block POP_BLOCK COME_FROM
@@ -577,7 +585,7 @@ class Parser(GenericASTBuilder):
expr ::= buildslice2 expr ::= buildslice2
expr ::= buildslice3 expr ::= buildslice3
expr ::= yield expr ::= yield
binary_expr ::= expr expr binary_op binary_expr ::= expr expr binary_op
binary_op ::= BINARY_ADD binary_op ::= BINARY_ADD
binary_op ::= BINARY_MULTIPLY binary_op ::= BINARY_MULTIPLY
@@ -616,7 +624,7 @@ class Parser(GenericASTBuilder):
slice3 ::= expr expr expr DUP_TOPX_3 SLICE+3 slice3 ::= expr expr expr DUP_TOPX_3 SLICE+3
buildslice3 ::= expr expr expr BUILD_SLICE_3 buildslice3 ::= expr expr expr BUILD_SLICE_3
buildslice2 ::= expr expr BUILD_SLICE_2 buildslice2 ::= expr expr BUILD_SLICE_2
yield ::= expr YIELD_VALUE yield ::= expr YIELD_VALUE
_mklambda ::= load_closure mklambda _mklambda ::= load_closure mklambda
@@ -627,17 +635,17 @@ class Parser(GenericASTBuilder):
and ::= expr jmp_false expr _come_from and ::= expr jmp_false expr _come_from
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
and2 ::= _jump jmp_false COME_FROM expr COME_FROM and2 ::= _jump jmp_false COME_FROM expr COME_FROM
expr ::= conditional expr ::= conditional
conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM conditional ::= expr jmp_false expr JUMP_FORWARD expr COME_FROM
conditional ::= expr jmp_false expr JUMP_ABSOLUTE expr conditional ::= expr jmp_false expr JUMP_ABSOLUTE expr
expr ::= conditionalnot expr ::= conditionalnot
conditionalnot ::= expr jmp_true expr _jump expr COME_FROM conditionalnot ::= expr jmp_true expr _jump expr COME_FROM
ret_expr ::= expr ret_expr ::= expr
ret_expr ::= ret_and ret_expr ::= ret_and
ret_expr ::= ret_or ret_expr ::= ret_or
ret_expr_or_cond ::= ret_expr ret_expr_or_cond ::= ret_expr
ret_expr_or_cond ::= ret_cond ret_expr_or_cond ::= ret_cond
ret_expr_or_cond ::= ret_cond_not ret_expr_or_cond ::= ret_cond_not
@@ -649,9 +657,9 @@ class Parser(GenericASTBuilder):
stmt ::= return_lambda stmt ::= return_lambda
stmt ::= conditional_lambda stmt ::= conditional_lambda
return_lambda ::= ret_expr RETURN_VALUE LAMBDA_MARKER return_lambda ::= ret_expr RETURN_VALUE LAMBDA_MARKER
conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER conditional_lambda ::= expr jmp_false return_if_stmt return_stmt LAMBDA_MARKER
cmp ::= cmp_list cmp ::= cmp_list
cmp ::= compare cmp ::= compare
@@ -704,7 +712,7 @@ class Parser(GenericASTBuilder):
def __ambiguity(self, children): def __ambiguity(self, children):
# only for debugging! to be removed hG/2000-10-15 # only for debugging! to be removed hG/2000-10-15
print children print(children)
return GenericASTBuilder.ambiguity(self, children) return GenericASTBuilder.ambiguity(self, children)
def resolve(self, list): def resolve(self, list):
@@ -737,9 +745,9 @@ def parse(tokens, customize):
# expr ::= expr {expr}^n CALL_FUNCTION_KW_n POP_TOP # expr ::= expr {expr}^n CALL_FUNCTION_KW_n POP_TOP
# #
global p global p
for k, v in customize.items(): for k, v in list(customize.items()):
# avoid adding the same rule twice to this parser # avoid adding the same rule twice to this parser
if p.customized.has_key(k): if k in p.customized:
continue continue
p.customized[k] = None p.customized[k] = None

View File

@@ -12,14 +12,14 @@ from array import array
from operator import itemgetter from operator import itemgetter
from struct import * from struct import *
from uncompyle2.opcode.opcode_25 import * from uncompyle6.opcodes.opcode_25 import *
import disas as dis import disas as dis
import scanner as scan import scanner as scan
class Scanner25(scan.Scanner): class Scanner25(scan.Scanner):
def __init__(self): def __init__(self):
self.Token = scan.Scanner.__init__(self, 2.5) self.Token = scan.Scanner.__init__(self, 2.5)
def disassemble(self, co, classname=None): def disassemble(self, co, classname=None):
''' '''
Disassemble a code object, returning a list of 'Token'. Disassemble a code object, returning a list of 'Token'.
@@ -38,7 +38,7 @@ class Scanner25(scan.Scanner):
# linestarts contains bloc code adresse (addr,block) # linestarts contains bloc code adresse (addr,block)
self.linestarts = list(dis.findlinestarts(co)) self.linestarts = list(dis.findlinestarts(co))
self.prev = [0] self.prev = [0]
# class and names # class and names
if classname: if classname:
classname = '_' + classname.lstrip('_') + '__' classname = '_' + classname.lstrip('_') + '__'
@@ -46,7 +46,7 @@ class Scanner25(scan.Scanner):
if name.startswith(classname) and name[-2:] != '__': if name.startswith(classname) and name[-2:] != '__':
return name[len(classname) - 2:] return name[len(classname) - 2:]
return name return name
free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ] free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ]
names = [ unmangle(name) for name in co.co_names ] names = [ unmangle(name) for name in co.co_names ]
varnames = [ unmangle(name) for name in co.co_varnames ] varnames = [ unmangle(name) for name in co.co_varnames ]
@@ -82,13 +82,13 @@ class Scanner25(scan.Scanner):
while j < codelen: while j < codelen:
self.lines.append(linetuple(prev_line_no, codelen)) self.lines.append(linetuple(prev_line_no, codelen))
j+=1 j+=1
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, codelen): for i in self.op_range(0, codelen):
if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL: if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL:
if names[self.get_argument(i+3)] == 'AssertionError': if names[self.get_argument(i+3)] == 'AssertionError':
self.load_asserts.add(i+3) self.load_asserts.add(i+3)
# self.lines contains (block,addrLastInstr) # self.lines contains (block,addrLastInstr)
cf = self.find_jump_targets(self.code) cf = self.find_jump_targets(self.code)
# contains (code, [addrRefToCode]) # contains (code, [addrRefToCode])
@@ -104,7 +104,7 @@ class Scanner25(scan.Scanner):
replace[i] = 'PRINT_NEWLINE_CONT' replace[i] = 'PRINT_NEWLINE_CONT'
last_stmt = i last_stmt = i
i = self.next_stmt[i] i = self.next_stmt[i]
imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR)) imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
if len(imports) > 1: if len(imports) > 1:
last_import = imports[0] last_import = imports[0]
@@ -220,10 +220,10 @@ class Scanner25(scan.Scanner):
''' '''
opcode = self.code[i] opcode = self.code[i]
opsize = self.op_size(opcode) opsize = self.op_size(opcode)
if i+opsize >= len(self.code): if i+opsize >= len(self.code):
return None return None
if opcode == EXTENDED_ARG: if opcode == EXTENDED_ARG:
raise NotImplementedError raise NotImplementedError
# del POP_TOP # del POP_TOP
@@ -283,7 +283,7 @@ class Scanner25(scan.Scanner):
target = self.get_target(target-3) target = self.get_target(target-3)
self.restructJump(start, target) self.restructJump(start, target)
start += self.op_size(PJIF) start += self.op_size(PJIF)
# del DELETE_NAME x # del DELETE_NAME x
start = end start = end
while end < len(self.code): while end < len(self.code):
end = self.first_instr(end, len(self.code), (DELETE_NAME,DELETE_FAST)) end = self.first_instr(end, len(self.code), (DELETE_NAME,DELETE_FAST))
@@ -297,7 +297,7 @@ class Scanner25(scan.Scanner):
return toDel return toDel
# change join(for..) struct # change join(for..) struct
if opcode == SETUP_LOOP: if opcode == SETUP_LOOP:
if self.code[i+3] == LOAD_FAST and self.code[i+6] == FOR_ITER: if self.code[i+3] == LOAD_FAST and self.code[i+6] == FOR_ITER:
end = self.first_instr(i, len(self.code), RETURN_VALUE) end = self.first_instr(i, len(self.code), RETURN_VALUE)
end = self.first_instr(i, end, YIELD_VALUE) end = self.first_instr(i, end, YIELD_VALUE)
if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK: if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK:
@@ -357,7 +357,7 @@ class Scanner25(scan.Scanner):
i+=2 i+=2
i+=1 i+=1
return listExp return listExp
def restructCode(self, listDel, listExp): def restructCode(self, listDel, listExp):
''' '''
restruct linestarts and jump destination restruct linestarts and jump destination
@@ -389,7 +389,7 @@ class Scanner25(scan.Scanner):
if listDel: if listDel:
for jmp in self.op_range(0, len(self.code)): for jmp in self.op_range(0, len(self.code)):
op = self.code[jmp] op = self.code[jmp]
if op in hasjrel+hasjabs: if op in hasjrel+hasjabs:
offset = 0 offset = 0
jmpTarget = self.get_target(jmp) jmpTarget = self.get_target(jmp)
for toDel in listDel: for toDel in listDel:
@@ -412,7 +412,7 @@ class Scanner25(scan.Scanner):
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended: if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
jmp += 3 jmp += 3
else: jmp += 1 else: jmp += 1
def restructBytecode(self): def restructBytecode(self):
''' '''
add/change/delete bytecode for suiting bytecode 2.7 add/change/delete bytecode for suiting bytecode 2.7
@@ -420,9 +420,9 @@ class Scanner25(scan.Scanner):
# we can't use op_range for the moment # we can't use op_range for the moment
# convert jump opcode to 2.7 # convert jump opcode to 2.7
self.restructRelativeJump() self.restructRelativeJump()
listExp = self.getOpcodeToExp() listExp = self.getOpcodeToExp()
# change code structure # change code structure
if listExp: if listExp:
listExp = sorted(list(set(listExp))) listExp = sorted(list(set(listExp)))
self.restructCode([], listExp) self.restructCode([], listExp)
@@ -439,7 +439,7 @@ class Scanner25(scan.Scanner):
ret = self.getOpcodeToDel(i) ret = self.getOpcodeToDel(i)
if ret != None: if ret != None:
listDel += ret listDel += ret
# change code structure after deleting byte # change code structure after deleting byte
if listDel: if listDel:
listDel = sorted(list(set(listDel))) listDel = sorted(list(set(listDel)))
@@ -455,7 +455,7 @@ class Scanner25(scan.Scanner):
else: else:
self.code.pop(x-delta) self.code.pop(x-delta)
delta += 1 delta += 1
def restructRelativeJump(self): def restructRelativeJump(self):
''' '''
change relative JUMP_IF_FALSE/TRUE to absolut jump change relative JUMP_IF_FALSE/TRUE to absolut jump
@@ -495,7 +495,7 @@ class Scanner25(scan.Scanner):
raise NotImplementedError raise NotImplementedError
self.code[pos+2] = (target >> 8) & 0xFF self.code[pos+2] = (target >> 8) & 0xFF
self.code[pos+1] = target & 0xFF self.code[pos+1] = target & 0xFF
def build_stmt_indices(self): def build_stmt_indices(self):
code = self.code code = self.code
start = 0; start = 0;
@@ -513,9 +513,9 @@ class Scanner25(scan.Scanner):
} }
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)]
designator_ops = { designator_ops = {
STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} }
@@ -532,17 +532,17 @@ class Scanner25(scan.Scanner):
match = False match = False
break break
i += self.op_size(code[i]) i += self.op_size(code[i])
if match: if match:
i = self.prev[i] i = self.prev[i]
stmts.add(i) stmts.add(i)
pass_stmts.add(i) pass_stmts.add(i)
if pass_stmts: if pass_stmts:
stmt_list = list(stmts) stmt_list = list(stmts)
stmt_list.sort() stmt_list.sort()
else: else:
stmt_list = prelim stmt_list = prelim
last_stmt = -1 last_stmt = -1
self.next_stmt = [] self.next_stmt = []
slist = self.next_stmt = [] slist = self.next_stmt = []
@@ -573,7 +573,7 @@ class Scanner25(scan.Scanner):
slist += [s] * (s-i) slist += [s] * (s-i)
i = s i = s
slist += [end] * (end-len(slist)) slist += [end] * (end-len(slist))
def next_except_jump(self, start): def next_except_jump(self, start):
''' '''
Return the next jump that was generated by an except SomeException: Return the next jump that was generated by an except SomeException:
@@ -602,7 +602,7 @@ class Scanner25(scan.Scanner):
elif op in (SETUP_EXCEPT, SETUP_FINALLY): elif op in (SETUP_EXCEPT, SETUP_FINALLY):
count_SETUP_ += 1 count_SETUP_ += 1
#return self.lines[start].next #return self.lines[start].next
def detect_structure(self, pos, op=None): def detect_structure(self, pos, op=None):
''' '''
Detect type of block structures and their boundaries to fix optimizied jumps Detect type of block structures and their boundaries to fix optimizied jumps
@@ -635,7 +635,7 @@ class Scanner25(scan.Scanner):
if target != end: if target != end:
self.fixed_jumps[pos] = end self.fixed_jumps[pos] = end
(line_no, next_line_byte) = self.lines[pos] (line_no, next_line_byte) = self.lines[pos]
jump_back = self.last_instr(start, end, JA, jump_back = self.last_instr(start, end, JA,
next_line_byte, False) next_line_byte, False)
@@ -645,7 +645,7 @@ class Scanner25(scan.Scanner):
jump_back = None jump_back = None
if not jump_back: # loop suite ends in return. wtf right? if not jump_back: # loop suite ends in return. wtf right?
jump_back = self.last_instr(start, end, RETURN_VALUE) jump_back = self.last_instr(start, end, RETURN_VALUE)
if not jump_back: if not jump_back:
return return
jump_back += 1 jump_back += 1
if code[self.prev[next_line_byte]] not in (PJIF, PJIT): if code[self.prev[next_line_byte]] not in (PJIF, PJIT):
@@ -667,7 +667,7 @@ class Scanner25(scan.Scanner):
elif target < pos: elif target < pos:
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
end = jump_back+4 end = jump_back+4
target = self.get_target(jump_back, JA) target = self.get_target(jump_back, JA)
if code[target] in (FOR_ITER, GET_ITER): if code[target] in (FOR_ITER, GET_ITER):
@@ -677,7 +677,7 @@ class Scanner25(scan.Scanner):
test = self.prev[next_line_byte] test = self.prev[next_line_byte]
if test == pos: if test == pos:
loop_type = 'while 1' loop_type = 'while 1'
elif self.code[test] in hasjabs+hasjrel: elif self.code[test] in hasjabs+hasjrel:
self.ignore_if.add(test) self.ignore_if.add(test)
test_target = self.get_target(test) test_target = self.get_target(test)
if test_target > (jump_back+3): if test_target > (jump_back+3):
@@ -725,7 +725,7 @@ class Scanner25(scan.Scanner):
self.structs.append({'type': 'except', self.structs.append({'type': 'except',
'start': i, 'start': i,
'end': jmp}) 'end': jmp})
i = jmp + 3 i = jmp + 3
## Add the try-else block ## Add the try-else block
if end_else != start_else: if end_else != start_else:
@@ -754,7 +754,7 @@ class Scanner25(scan.Scanner):
'start': start, 'start': start,
'end': pre[target]}) 'end': pre[target]})
return return
# is this an if and # is this an if and
if op == PJIF: if op == PJIF:
match = self.rem_or(start, self.next_stmt[pos], PJIF, target) match = self.rem_or(start, self.next_stmt[pos], PJIF, target)
@@ -790,7 +790,7 @@ class Scanner25(scan.Scanner):
self.fixed_jumps[pos] = fix or match[-1] self.fixed_jumps[pos] = fix or match[-1]
return return
elif pos < rtarget and code[target] == ROT_TWO: elif pos < rtarget and code[target] == ROT_TWO:
self.fixed_jumps[pos] = target self.fixed_jumps[pos] = target
return return
else: else:
self.fixed_jumps[pos] = match[-1] self.fixed_jumps[pos] = match[-1]
@@ -800,7 +800,7 @@ class Scanner25(scan.Scanner):
if code[pre[rtarget]] == RAISE_VARARGS: if code[pre[rtarget]] == RAISE_VARARGS:
return return
self.load_asserts.remove(pos+3) self.load_asserts.remove(pos+3)
next = self.next_stmt[pos] next = self.next_stmt[pos]
if pre[next] == pos: if pre[next] == pos:
pass pass
@@ -816,7 +816,7 @@ class Scanner25(scan.Scanner):
#don't add a struct for a while test, it's already taken care of #don't add a struct for a while test, it's already taken care of
if pos in self.ignore_if: if pos in self.ignore_if:
return return
if code[pre[rtarget]] == JA and pre[rtarget] in self.stmts \ if code[pre[rtarget]] == JA and pre[rtarget] in self.stmts \
and pre[rtarget] != pos and pre[pre[rtarget]] != pos \ and pre[rtarget] != pos and pre[pre[rtarget]] != pos \
and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA): and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA):
@@ -824,19 +824,19 @@ class Scanner25(scan.Scanner):
#does the if jump just beyond a jump op, then this is probably an if statement #does the if jump just beyond a jump op, then this is probably an if statement
if code[pre[rtarget]] in (JA, JF): if code[pre[rtarget]] in (JA, JF):
if_end = self.get_target(pre[rtarget]) if_end = self.get_target(pre[rtarget])
#is this a loop not an if? #is this a loop not an if?
if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP): if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return
end = self.restrict_to_parent(if_end, parent) end = self.restrict_to_parent(if_end, parent)
self.structs.append({'type': 'if-then', self.structs.append({'type': 'if-then',
'start': start, 'start': start,
'end': pre[rtarget]}) 'end': pre[rtarget]})
self.not_continue.add(pre[rtarget]) self.not_continue.add(pre[rtarget])
if rtarget < end: if rtarget < end:
self.structs.append({'type': 'if-else', self.structs.append({'type': 'if-else',
'start': rtarget, 'start': rtarget,
@@ -867,7 +867,7 @@ class Scanner25(scan.Scanner):
self.loops = [] ## All loop entry points self.loops = [] ## All loop entry points
self.fixed_jumps = {} ## Map fixed jumps to their real destination self.fixed_jumps = {} ## Map fixed jumps to their real destination
self.ignore_if = set() self.ignore_if = set()
self.build_stmt_indices() self.build_stmt_indices()
self.not_continue = set() self.not_continue = set()
self.return_end_ifs = set() self.return_end_ifs = set()
@@ -880,7 +880,7 @@ class Scanner25(scan.Scanner):
if self.op_hasArgument(op): if self.op_hasArgument(op):
label = self.fixed_jumps.get(i) label = self.fixed_jumps.get(i)
oparg = self.get_argument(i) oparg = self.get_argument(i)
if label is None: if label is None:
if op in hasjrel and op != FOR_ITER: if op in hasjrel and op != FOR_ITER:
label = i + 3 + oparg label = i + 3 + oparg

View File

@@ -12,14 +12,14 @@ from array import array
from operator import itemgetter from operator import itemgetter
from struct import * from struct import *
from uncompyle2.opcode.opcode_26 import * from uncompyle6.opcodes.opcode_26 import *
import disas as dis import disas as dis
import scanner as scan import scanner as scan
class Scanner26(scan.Scanner): class Scanner26(scan.Scanner):
def __init__(self): def __init__(self):
self.Token = scan.Scanner.__init__(self, 2.6) self.Token = scan.Scanner.__init__(self, 2.6)
def disassemble(self, co, classname=None): def disassemble(self, co, classname=None):
''' '''
Disassemble a code object, returning a list of 'Token'. Disassemble a code object, returning a list of 'Token'.
@@ -27,7 +27,7 @@ class Scanner26(scan.Scanner):
The main part of this procedure is modelled after The main part of this procedure is modelled after
dis.disassemble(). dis.disassemble().
''' '''
rv = [] rv = []
customize = {} customize = {}
Token = self.Token # shortcut Token = self.Token # shortcut
@@ -46,7 +46,7 @@ class Scanner26(scan.Scanner):
if name.startswith(classname) and name[-2:] != '__': if name.startswith(classname) and name[-2:] != '__':
return name[len(classname) - 2:] return name[len(classname) - 2:]
return name return name
free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ] free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ]
names = [ unmangle(name) for name in co.co_names ] names = [ unmangle(name) for name in co.co_names ]
varnames = [ unmangle(name) for name in co.co_varnames ] varnames = [ unmangle(name) for name in co.co_varnames ]
@@ -60,7 +60,7 @@ class Scanner26(scan.Scanner):
self.toChange = [] self.toChange = []
self.restructBytecode() self.restructBytecode()
codelen = len(self.code) codelen = len(self.code)
# mapping adresses of prev instru # mapping adresses of prev instru
for i in self.op_range(0, codelen): for i in self.op_range(0, codelen):
op = self.code[i] op = self.code[i]
self.prev.append(i) self.prev.append(i)
@@ -83,13 +83,13 @@ class Scanner26(scan.Scanner):
self.lines.append(linetuple(prev_line_no, codelen)) self.lines.append(linetuple(prev_line_no, codelen))
j+=1 j+=1
# self.lines contains (block,addrLastInstr) # self.lines contains (block,addrLastInstr)
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, codelen): for i in self.op_range(0, codelen):
if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL: if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL:
if names[self.get_argument(i+3)] == 'AssertionError': if names[self.get_argument(i+3)] == 'AssertionError':
self.load_asserts.add(i+3) self.load_asserts.add(i+3)
cf = self.find_jump_targets(self.code) cf = self.find_jump_targets(self.code)
# contains (code, [addrRefToCode]) # contains (code, [addrRefToCode])
@@ -105,7 +105,7 @@ class Scanner26(scan.Scanner):
replace[i] = 'PRINT_NEWLINE_CONT' replace[i] = 'PRINT_NEWLINE_CONT'
last_stmt = i last_stmt = i
i = self.next_stmt[i] i = self.next_stmt[i]
imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR)) imports = self.all_instr(0, codelen, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
if len(imports) > 1: if len(imports) > 1:
last_import = imports[0] last_import = imports[0]
@@ -248,10 +248,10 @@ class Scanner26(scan.Scanner):
if destFor == i+opsize+4: if destFor == i+opsize+4:
setupLoop = self.last_instr(0, jmpabs1target, SETUP_LOOP) setupLoop = self.last_instr(0, jmpabs1target, SETUP_LOOP)
standarFor = self.last_instr(setupLoop, jmpabs1target, GET_ITER) standarFor = self.last_instr(setupLoop, jmpabs1target, GET_ITER)
if standarFor == None: if standarFor == None:
self.restructJump(jmpabs1target, destFor+self.op_size(POP_BLOCK)) self.restructJump(jmpabs1target, destFor+self.op_size(POP_BLOCK))
toDel += [setupLoop, i+opsize+1, i+opsize+4] toDel += [setupLoop, i+opsize+1, i+opsize+4]
if len(toDel) > 0: if len(toDel) > 0:
return toDel return toDel
return None return None
@@ -288,7 +288,7 @@ class Scanner26(scan.Scanner):
target = self.get_target(target-3) target = self.get_target(target-3)
self.restructJump(start, target) self.restructJump(start, target)
start += self.op_size(PJIF) start += self.op_size(PJIF)
# del DELETE_NAME x # del DELETE_NAME x
start = end start = end
while end < len(self.code): while end < len(self.code):
end = self.first_instr(end, len(self.code), (DELETE_NAME,DELETE_FAST)) end = self.first_instr(end, len(self.code), (DELETE_NAME,DELETE_FAST))
@@ -303,7 +303,7 @@ class Scanner26(scan.Scanner):
# for / while struct # for / while struct
if opcode == SETUP_LOOP: if opcode == SETUP_LOOP:
# change join(for..) struct # change join(for..) struct
if self.code[i+3] == LOAD_FAST and self.code[i+6] == FOR_ITER: if self.code[i+3] == LOAD_FAST and self.code[i+6] == FOR_ITER:
end = self.first_instr(i, len(self.code), RETURN_VALUE) end = self.first_instr(i, len(self.code), RETURN_VALUE)
end = self.first_instr(i, end, YIELD_VALUE) end = self.first_instr(i, end, YIELD_VALUE)
if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK: if end and self.code[end+1] == POP_TOP and self.code[end+2] == JA and self.code[end+5] == POP_BLOCK:
@@ -385,7 +385,7 @@ class Scanner26(scan.Scanner):
if listDel: if listDel:
for jmp in self.op_range(0, len(self.code)): for jmp in self.op_range(0, len(self.code)):
op = self.code[jmp] op = self.code[jmp]
if op in hasjrel+hasjabs: if op in hasjrel+hasjabs:
offset = 0 offset = 0
jmpTarget = self.get_target(jmp) jmpTarget = self.get_target(jmp)
for toDel in listDel: for toDel in listDel:
@@ -416,9 +416,9 @@ class Scanner26(scan.Scanner):
# we can't use op_range for the moment # we can't use op_range for the moment
# convert jump opcode to 2.7 # convert jump opcode to 2.7
self.restructRelativeJump() self.restructRelativeJump()
listExp = self.getOpcodeToExp() listExp = self.getOpcodeToExp()
# change code structure # change code structure
if listExp: if listExp:
listExp = sorted(list(set(listExp))) listExp = sorted(list(set(listExp)))
self.restructCode([], listExp) self.restructCode([], listExp)
@@ -435,7 +435,7 @@ class Scanner26(scan.Scanner):
ret = self.getOpcodeToDel(i) ret = self.getOpcodeToDel(i)
if ret != None: if ret != None:
listDel += ret listDel += ret
# change code structure after deleting byte # change code structure after deleting byte
if listDel: if listDel:
listDel = sorted(list(set(listDel))) listDel = sorted(list(set(listDel)))
@@ -479,7 +479,7 @@ class Scanner26(scan.Scanner):
if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended: if self.op_hasArgument(op) and op not in self.opc.hasArgumentExtended:
i += 3 i += 3
else: i += 1 else: i += 1
def restructJump(self, pos, newTarget): def restructJump(self, pos, newTarget):
if not (self.code[pos] in hasjabs+hasjrel): if not (self.code[pos] in hasjabs+hasjrel):
raise 'Can t change this argument. Opcode is not a jump' raise 'Can t change this argument. Opcode is not a jump'
@@ -491,7 +491,7 @@ class Scanner26(scan.Scanner):
raise NotImplementedError raise NotImplementedError
self.code[pos+2] = (target >> 8) & 0xFF self.code[pos+2] = (target >> 8) & 0xFF
self.code[pos+1] = target & 0xFF self.code[pos+1] = target & 0xFF
def build_stmt_indices(self): def build_stmt_indices(self):
code = self.code code = self.code
start = 0; start = 0;
@@ -509,9 +509,9 @@ class Scanner26(scan.Scanner):
} }
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)]
designator_ops = { designator_ops = {
STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} }
@@ -528,17 +528,17 @@ class Scanner26(scan.Scanner):
match = False match = False
break break
i += self.op_size(code[i]) i += self.op_size(code[i])
if match: if match:
i = self.prev[i] i = self.prev[i]
stmts.add(i) stmts.add(i)
pass_stmts.add(i) pass_stmts.add(i)
if pass_stmts: if pass_stmts:
stmt_list = list(stmts) stmt_list = list(stmts)
stmt_list.sort() stmt_list.sort()
else: else:
stmt_list = prelim stmt_list = prelim
last_stmt = -1 last_stmt = -1
self.next_stmt = [] self.next_stmt = []
slist = self.next_stmt = [] slist = self.next_stmt = []
@@ -634,7 +634,7 @@ class Scanner26(scan.Scanner):
if target != end: if target != end:
self.fixed_jumps[pos] = end self.fixed_jumps[pos] = end
(line_no, next_line_byte) = self.lines[pos] (line_no, next_line_byte) = self.lines[pos]
jump_back = self.last_instr(start, end, JA, jump_back = self.last_instr(start, end, JA,
next_line_byte, False) next_line_byte, False)
@@ -644,7 +644,7 @@ class Scanner26(scan.Scanner):
jump_back = None jump_back = None
if not jump_back: # loop suite ends in return. wtf right? if not jump_back: # loop suite ends in return. wtf right?
jump_back = self.last_instr(start, end, RETURN_VALUE) jump_back = self.last_instr(start, end, RETURN_VALUE)
if not jump_back: if not jump_back:
return return
jump_back += 1 jump_back += 1
if code[self.prev[next_line_byte]] not in (PJIF, PJIT): if code[self.prev[next_line_byte]] not in (PJIF, PJIT):
@@ -666,7 +666,7 @@ class Scanner26(scan.Scanner):
elif target < pos: elif target < pos:
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
end = jump_back+4 end = jump_back+4
target = self.get_target(jump_back, JA) target = self.get_target(jump_back, JA)
if code[target] in (FOR_ITER, GET_ITER): if code[target] in (FOR_ITER, GET_ITER):
@@ -676,7 +676,7 @@ class Scanner26(scan.Scanner):
test = self.prev[next_line_byte] test = self.prev[next_line_byte]
if test == pos: if test == pos:
loop_type = 'while 1' loop_type = 'while 1'
elif self.code[test] in hasjabs+hasjrel: elif self.code[test] in hasjabs+hasjrel:
self.ignore_if.add(test) self.ignore_if.add(test)
test_target = self.get_target(test) test_target = self.get_target(test)
if test_target > (jump_back+3): if test_target > (jump_back+3):
@@ -725,7 +725,7 @@ class Scanner26(scan.Scanner):
self.structs.append({'type': 'except', self.structs.append({'type': 'except',
'start': i, 'start': i,
'end': jmp}) 'end': jmp})
i = jmp + 3 i = jmp + 3
## Add the try-else block ## Add the try-else block
if end_else != start_else: if end_else != start_else:
@@ -754,7 +754,7 @@ class Scanner26(scan.Scanner):
'start': start, 'start': start,
'end': pre[target]}) 'end': pre[target]})
return return
# is this an if and # is this an if and
if op == PJIF: if op == PJIF:
match = self.rem_or(start, self.next_stmt[pos], PJIF, target) match = self.rem_or(start, self.next_stmt[pos], PJIF, target)
@@ -790,7 +790,7 @@ class Scanner26(scan.Scanner):
self.fixed_jumps[pos] = fix or match[-1] self.fixed_jumps[pos] = fix or match[-1]
return return
elif pos < rtarget and code[target] == ROT_TWO: elif pos < rtarget and code[target] == ROT_TWO:
self.fixed_jumps[pos] = target self.fixed_jumps[pos] = target
return return
else: else:
self.fixed_jumps[pos] = match[-1] self.fixed_jumps[pos] = match[-1]
@@ -800,7 +800,7 @@ class Scanner26(scan.Scanner):
if code[pre[rtarget]] == RAISE_VARARGS: if code[pre[rtarget]] == RAISE_VARARGS:
return return
self.load_asserts.remove(pos+3) self.load_asserts.remove(pos+3)
next = self.next_stmt[pos] next = self.next_stmt[pos]
if pre[next] == pos: if pre[next] == pos:
pass pass
@@ -816,7 +816,7 @@ class Scanner26(scan.Scanner):
#don't add a struct for a while test, it's already taken care of #don't add a struct for a while test, it's already taken care of
if pos in self.ignore_if: if pos in self.ignore_if:
return return
if code[pre[rtarget]] == JA and pre[rtarget] in self.stmts \ if code[pre[rtarget]] == JA and pre[rtarget] in self.stmts \
and pre[rtarget] != pos and pre[pre[rtarget]] != pos \ and pre[rtarget] != pos and pre[pre[rtarget]] != pos \
and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA): and not (code[rtarget] == JA and code[rtarget+3] == POP_BLOCK and code[pre[pre[rtarget]]] != JA):
@@ -824,19 +824,19 @@ class Scanner26(scan.Scanner):
#does the if jump just beyond a jump op, then this is probably an if statement #does the if jump just beyond a jump op, then this is probably an if statement
if code[pre[rtarget]] in (JA, JF): if code[pre[rtarget]] in (JA, JF):
if_end = self.get_target(pre[rtarget]) if_end = self.get_target(pre[rtarget])
#is this a loop not an if? #is this a loop not an if?
if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP): if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return
end = self.restrict_to_parent(if_end, parent) end = self.restrict_to_parent(if_end, parent)
self.structs.append({'type': 'if-then', self.structs.append({'type': 'if-then',
'start': start, 'start': start,
'end': pre[rtarget]}) 'end': pre[rtarget]})
self.not_continue.add(pre[rtarget]) self.not_continue.add(pre[rtarget])
if rtarget < end: if rtarget < end:
self.structs.append({'type': 'if-else', self.structs.append({'type': 'if-else',
'start': rtarget, 'start': rtarget,
@@ -867,7 +867,7 @@ class Scanner26(scan.Scanner):
self.loops = [] ## All loop entry points self.loops = [] ## All loop entry points
self.fixed_jumps = {} ## Map fixed jumps to their real destination self.fixed_jumps = {} ## Map fixed jumps to their real destination
self.ignore_if = set() self.ignore_if = set()
self.build_stmt_indices() self.build_stmt_indices()
self.not_continue = set() self.not_continue = set()
self.return_end_ifs = set() self.return_end_ifs = set()
@@ -880,7 +880,7 @@ class Scanner26(scan.Scanner):
if self.op_hasArgument(op): if self.op_hasArgument(op):
label = self.fixed_jumps.get(i) label = self.fixed_jumps.get(i)
oparg = self.get_argument(i) oparg = self.get_argument(i)
if label is None: if label is None:
if op in hasjrel and op != FOR_ITER: if op in hasjrel and op != FOR_ITER:
label = i + 3 + oparg label = i + 3 + oparg
@@ -894,4 +894,3 @@ class Scanner26(scan.Scanner):
label = self.fixed_jumps[i] label = self.fixed_jumps[i]
targets[label] = targets.get(label, []) + [i] targets[label] = targets.get(label, []) + [i]
return targets return targets

View File

@@ -11,14 +11,14 @@ from collections import namedtuple
from array import array from array import array
from operator import itemgetter from operator import itemgetter
from uncompyle2.opcode.opcode_27 import * from uncompyle6.opcodes.opcode_27 import *
import disas as dis import disas as dis
import scanner as scan import scanner as scan
class Scanner27(scan.Scanner): class Scanner27(scan.Scanner):
def __init__(self): def __init__(self):
self.Token = scan.Scanner.__init__(self, 2.7) # check self.Token = scan.Scanner.__init__(self, 2.7) # check
def disassemble(self, co, classname=None): def disassemble(self, co, classname=None):
''' '''
Disassemble a code object, returning a list of 'Token'. Disassemble a code object, returning a list of 'Token'.
@@ -33,7 +33,7 @@ class Scanner27(scan.Scanner):
if self.code[i] in (RETURN_VALUE, END_FINALLY): if self.code[i] in (RETURN_VALUE, END_FINALLY):
n = i + 1 n = i + 1
self.code = array('B', co.co_code[:n]) self.code = array('B', co.co_code[:n])
self.prev = [0] self.prev = [0]
# mapping adresses of instru & arg # mapping adresses of instru & arg
for i in self.op_range(0, n): for i in self.op_range(0, n):
@@ -42,7 +42,7 @@ class Scanner27(scan.Scanner):
if op >= HAVE_ARGUMENT: if op >= HAVE_ARGUMENT:
self.prev.append(i) self.prev.append(i)
self.prev.append(i) self.prev.append(i)
self.lines = [] self.lines = []
linetuple = namedtuple('linetuple', ['l_no', 'next']) linetuple = namedtuple('linetuple', ['l_no', 'next'])
j = 0 j = 0
@@ -66,7 +66,7 @@ class Scanner27(scan.Scanner):
if name.startswith(classname) and name[-2:] != '__': if name.startswith(classname) and name[-2:] != '__':
return name[len(classname) - 2:] return name[len(classname) - 2:]
return name return name
free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ] free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ]
names = [ unmangle(name) for name in co.co_names ] names = [ unmangle(name) for name in co.co_names ]
varnames = [ unmangle(name) for name in co.co_varnames ] varnames = [ unmangle(name) for name in co.co_varnames ]
@@ -80,7 +80,7 @@ class Scanner27(scan.Scanner):
if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL: if self.code[i] == PJIT and self.code[i+3] == LOAD_GLOBAL:
if names[self.get_argument(i+3)] == 'AssertionError': if names[self.get_argument(i+3)] == 'AssertionError':
self.load_asserts.add(i+3) self.load_asserts.add(i+3)
cf = self.find_jump_targets(self.code) cf = self.find_jump_targets(self.code)
# contains (code, [addrRefToCode]) # contains (code, [addrRefToCode])
last_stmt = self.next_stmt[0] last_stmt = self.next_stmt[0]
@@ -95,7 +95,7 @@ class Scanner27(scan.Scanner):
replace[i] = 'PRINT_NEWLINE_CONT' replace[i] = 'PRINT_NEWLINE_CONT'
last_stmt = i last_stmt = i
i = self.next_stmt[i] i = self.next_stmt[i]
imports = self.all_instr(0, n, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR)) imports = self.all_instr(0, n, (IMPORT_NAME, IMPORT_FROM, IMPORT_STAR))
if len(imports) > 1: if len(imports) > 1:
last_import = imports[0] last_import = imports[0]
@@ -104,7 +104,7 @@ class Scanner27(scan.Scanner):
if self.code[last_import] == IMPORT_NAME == self.code[i]: if self.code[last_import] == IMPORT_NAME == self.code[i]:
replace[i] = 'IMPORT_NAME_CONT' replace[i] = 'IMPORT_NAME_CONT'
last_import = i last_import = i
extended_arg = 0 extended_arg = 0
for offset in self.op_range(0, n): for offset in self.op_range(0, n):
if offset in cf: if offset in cf:
@@ -113,7 +113,7 @@ class Scanner27(scan.Scanner):
rv.append(Token('COME_FROM', None, repr(j), rv.append(Token('COME_FROM', None, repr(j),
offset="%s_%d" % (offset, k))) offset="%s_%d" % (offset, k)))
k += 1 k += 1
op = self.code[offset] op = self.code[offset]
op_name = opname[op] op_name = opname[op]
oparg = None; pattr = None oparg = None; pattr = None
@@ -193,7 +193,7 @@ class Scanner27(scan.Scanner):
rv.append(Token(op_name, oparg, pattr, offset, linestart = offset in linestartoffsets)) rv.append(Token(op_name, oparg, pattr, offset, linestart = offset in linestartoffsets))
else: else:
rv.append(Token(replace[offset], oparg, pattr, offset, linestart = offset in linestartoffsets)) rv.append(Token(replace[offset], oparg, pattr, offset, linestart = offset in linestartoffsets))
if self.showasm: if self.showasm:
out = self.out # shortcut out = self.out # shortcut
for t in rv: for t in rv:
@@ -206,12 +206,12 @@ class Scanner27(scan.Scanner):
return 1 return 1
else: else:
return 3 return 3
def build_stmt_indices(self): def build_stmt_indices(self):
code = self.code code = self.code
start = 0; start = 0;
end = len(code) end = len(code)
stmt_opcodes = { stmt_opcodes = {
SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP,
SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_WITH, SETUP_FINALLY, END_FINALLY, SETUP_EXCEPT, SETUP_WITH,
@@ -226,9 +226,9 @@ class Scanner27(scan.Scanner):
} }
stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)] stmt_opcode_seqs = [(PJIF, JF), (PJIF, JA), (PJIT, JF), (PJIT, JA)]
designator_ops = { designator_ops = {
STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR, STORE_FAST, STORE_NAME, STORE_GLOBAL, STORE_DEREF, STORE_ATTR,
STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3, STORE_SLICE_0, STORE_SLICE_1, STORE_SLICE_2, STORE_SLICE_3,
STORE_SUBSCR, UNPACK_SEQUENCE, JA STORE_SUBSCR, UNPACK_SEQUENCE, JA
} }
@@ -245,12 +245,12 @@ class Scanner27(scan.Scanner):
match = False match = False
break break
i += self.op_size(code[i]) i += self.op_size(code[i])
if match: if match:
i = self.prev[i] i = self.prev[i]
stmts.add(i) stmts.add(i)
pass_stmts.add(i) pass_stmts.add(i)
if pass_stmts: if pass_stmts:
stmt_list = list(stmts) stmt_list = list(stmts)
stmt_list.sort() stmt_list.sort()
@@ -286,7 +286,7 @@ class Scanner27(scan.Scanner):
slist += [s] * (s-i) slist += [s] * (s-i)
i = s i = s
slist += [end] * (end-len(slist)) slist += [end] * (end-len(slist))
def remove_mid_line_ifs(self, ifs): def remove_mid_line_ifs(self, ifs):
filtered = [] filtered = []
for i in ifs: for i in ifs:
@@ -309,7 +309,7 @@ class Scanner27(scan.Scanner):
self.ignore_if.add(except_match) self.ignore_if.add(except_match)
self.not_continue.add(jmp) self.not_continue.add(jmp)
return jmp return jmp
count_END_FINALLY = 0 count_END_FINALLY = 0
count_SETUP_ = 0 count_SETUP_ = 0
for i in self.op_range(start, len(self.code)): for i in self.op_range(start, len(self.code)):
@@ -367,7 +367,7 @@ class Scanner27(scan.Scanner):
jump_back = None jump_back = None
if not jump_back: # loop suite ends in return. wtf right? if not jump_back: # loop suite ends in return. wtf right?
jump_back = self.last_instr(start, end, RETURN_VALUE) + 1 jump_back = self.last_instr(start, end, RETURN_VALUE) + 1
if not jump_back: if not jump_back:
return return
if code[self.prev[next_line_byte]] not in (PJIF, PJIT): if code[self.prev[next_line_byte]] not in (PJIF, PJIT):
loop_type = 'for' loop_type = 'for'
@@ -388,7 +388,7 @@ class Scanner27(scan.Scanner):
self.fixed_jumps[pos] = jump_back+4 self.fixed_jumps[pos] = jump_back+4
end = jump_back+4 end = jump_back+4
target = self.get_target(jump_back, JA) target = self.get_target(jump_back, JA)
if code[target] in (FOR_ITER, GET_ITER): if code[target] in (FOR_ITER, GET_ITER):
loop_type = 'for' loop_type = 'for'
else: else:
@@ -396,7 +396,7 @@ class Scanner27(scan.Scanner):
test = self.prev[next_line_byte] test = self.prev[next_line_byte]
if test == pos: if test == pos:
loop_type = 'while 1' loop_type = 'while 1'
elif self.code[test] in hasjabs+hasjrel: elif self.code[test] in hasjabs+hasjrel:
self.ignore_if.add(test) self.ignore_if.add(test)
test_target = self.get_target(test) test_target = self.get_target(test)
if test_target > (jump_back+3): if test_target > (jump_back+3):
@@ -441,7 +441,7 @@ class Scanner27(scan.Scanner):
self.structs.append({'type': 'except', self.structs.append({'type': 'except',
'start': i, 'start': i,
'end': jmp}) 'end': jmp})
i = jmp + 3 i = jmp + 3
## Add the try-else block ## Add the try-else block
if end_else != start_else: if end_else != start_else:
@@ -452,14 +452,14 @@ class Scanner27(scan.Scanner):
self.fixed_jumps[i] = r_end_else self.fixed_jumps[i] = r_end_else
else: else:
self.fixed_jumps[i] = i+1 self.fixed_jumps[i] = i+1
elif op in (PJIF, PJIT): elif op in (PJIF, PJIT):
start = pos+3 start = pos+3
target = self.get_target(pos, op) target = self.get_target(pos, op)
rtarget = self.restrict_to_parent(target, parent) rtarget = self.restrict_to_parent(target, parent)
pre = self.prev pre = self.prev
if target != rtarget and parent['type'] == 'and/or': if target != rtarget and parent['type'] == 'and/or':
self.fixed_jumps[pos] = rtarget self.fixed_jumps[pos] = rtarget
return return
@@ -472,7 +472,7 @@ class Scanner27(scan.Scanner):
'start': start, 'start': start,
'end': pre[target]}) 'end': pre[target]})
return return
# is this an if and # is this an if and
if op == PJIF: if op == PJIF:
match = self.rem_or(start, self.next_stmt[pos], PJIF, target) match = self.rem_or(start, self.next_stmt[pos], PJIF, target)
@@ -516,7 +516,7 @@ class Scanner27(scan.Scanner):
if code[pre[rtarget]] == RAISE_VARARGS: if code[pre[rtarget]] == RAISE_VARARGS:
return return
self.load_asserts.remove(pos+3) self.load_asserts.remove(pos+3)
next = self.next_stmt[pos] next = self.next_stmt[pos]
if pre[next] == pos: if pre[next] == pos:
pass pass
@@ -533,7 +533,7 @@ class Scanner27(scan.Scanner):
elif code[next_target] in (JA, JF) and self.get_target(next_target) == self.get_target(target): elif code[next_target] in (JA, JF) and self.get_target(next_target) == self.get_target(target):
self.fixed_jumps[pos] = pre[next] self.fixed_jumps[pos] = pre[next]
return return
#don't add a struct for a while test, it's already taken care of #don't add a struct for a while test, it's already taken care of
if pos in self.ignore_if: if pos in self.ignore_if:
return return
@@ -552,19 +552,19 @@ class Scanner27(scan.Scanner):
#does the if jump just beyond a jump op, then this is probably an if statement #does the if jump just beyond a jump op, then this is probably an if statement
if code[pre[rtarget]] in (JA, JF): if code[pre[rtarget]] in (JA, JF):
if_end = self.get_target(pre[rtarget]) if_end = self.get_target(pre[rtarget])
#is this a loop not an if? #is this a loop not an if?
if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP): if (if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return
end = self.restrict_to_parent(if_end, parent) end = self.restrict_to_parent(if_end, parent)
self.structs.append({'type': 'if-then', self.structs.append({'type': 'if-then',
'start': start, 'start': start,
'end': pre[rtarget]}) 'end': pre[rtarget]})
self.not_continue.add(pre[rtarget]) self.not_continue.add(pre[rtarget])
if rtarget < end: if rtarget < end:
self.structs.append({'type': 'if-else', self.structs.append({'type': 'if-else',
'start': rtarget, 'start': rtarget,
@@ -617,7 +617,7 @@ class Scanner27(scan.Scanner):
if op in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP): if op in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP):
if (oparg > i): if (oparg > i):
label = oparg label = oparg
if label is not None and label != -1: if label is not None and label != -1:
targets[label] = targets.get(label, []) + [i] targets[label] = targets.get(label, []) + [i]
elif op == END_FINALLY and i in self.fixed_jumps: elif op == END_FINALLY and i in self.fixed_jumps:

View File

@@ -1,6 +1,7 @@
''' from __future__ import print_function
'''
Copyright (c) 1998-2002 John Aycock Copyright (c) 1998-2002 John Aycock
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including "Software"), to deal in the Software without restriction, including
@@ -8,17 +9,17 @@ Copyright (c) 1998-2002 John Aycock
distribute, sublicense, and/or sell copies of the Software, and to distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to permit persons to whom the Software is furnished to do so, subject to
the following conditions: the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
''' '''
__version__ = 'SPARK-0.7 (pre-alpha-7) uncompyle trim' __version__ = 'SPARK-0.7 (pre-alpha-7) uncompyle trim'
@@ -28,31 +29,31 @@ def _namelist(instance):
for c in classlist: for c in classlist:
for b in c.__bases__: for b in c.__bases__:
classlist.append(b) classlist.append(b)
for name in c.__dict__.keys(): for name in list(c.__dict__.keys()):
if not namedict.has_key(name): if name not in namedict:
namelist.append(name) namelist.append(name)
namedict[name] = 1 namedict[name] = 1
return namelist return namelist
#
# Extracted from GenericParser and made global so that [un]picking works.
#
class _State: class _State:
'''
Extracted from GenericParser and made global so that [un]picking works.
'''
def __init__(self, stateno, items): def __init__(self, stateno, items):
self.T, self.complete, self.items = [], [], items self.T, self.complete, self.items = [], [], items
self.stateno = stateno self.stateno = stateno
class GenericParser: class GenericParser:
# '''
# An Earley parser, as per J. Earley, "An Efficient Context-Free An Earley parser, as per J. Earley, "An Efficient Context-Free
# Parsing Algorithm", CACM 13(2), pp. 94-102. Also J. C. Earley, Parsing Algorithm", CACM 13(2), pp. 94-102. Also J. C. Earley,
# "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis, "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis,
# Carnegie-Mellon University, August 1968. New formulation of Carnegie-Mellon University, August 1968. New formulation of
# the parser according to J. Aycock, "Practical Earley Parsing the parser according to J. Aycock, "Practical Earley Parsing
# and the SPARK Toolkit", Ph.D. thesis, University of Victoria, and the SPARK Toolkit", Ph.D. thesis, University of Victoria,
# 2001, and J. Aycock and R. N. Horspool, "Practical Earley 2001, and J. Aycock and R. N. Horspool, "Practical Earley
# Parsing", unpublished paper, 2001. Parsing", unpublished paper, 2001.
# '''
def __init__(self, start): def __init__(self, start):
self.rules = {} self.rules = {}
@@ -90,7 +91,7 @@ class GenericParser:
changes = 1 changes = 1
while changes: while changes:
changes = 0 changes = 0
for k, v in self.edges.items(): for k, v in list(self.edges.items()):
if v is None: if v is None:
state, sym = k state, sym = k
if self.states.has_key(state): if self.states.has_key(state):
@@ -127,12 +128,12 @@ class GenericParser:
rules = doc.split() rules = doc.split()
index = [] index = []
for i in xrange(len(rules)): for i in range(len(rules)):
if rules[i] == '::=': if rules[i] == '::=':
index.append(i-1) index.append(i-1)
index.append(len(rules)) index.append(len(rules))
for i in xrange(len(index)-1): for i in range(len(index)-1):
lhs = rules[index[i]] lhs = rules[index[i]]
rhs = rules[index[i]+2:index[i+1]] rhs = rules[index[i]+2:index[i+1]]
rule = (lhs, tuple(rhs)) rule = (lhs, tuple(rhs))
@@ -140,7 +141,7 @@ class GenericParser:
if _preprocess: if _preprocess:
rule, fn = self.preprocess(rule, func) rule, fn = self.preprocess(rule, func)
if self.rules.has_key(lhs): if lhs in self.rules:
self.rules[lhs].append(rule) self.rules[lhs].append(rule)
else: else:
self.rules[lhs] = [ rule ] self.rules[lhs] = [ rule ]
@@ -163,7 +164,7 @@ class GenericParser:
self.nullable = {} self.nullable = {}
tbd = [] tbd = []
for rulelist in self.rules.values(): for rulelist in list(self.rules.values()):
lhs = rulelist[0][0] lhs = rulelist[0][0]
self.nullable[lhs] = 0 self.nullable[lhs] = 0
for rule in rulelist: for rule in rulelist:
@@ -178,7 +179,7 @@ class GenericParser:
# grammars. # grammars.
# #
for sym in rhs: for sym in rhs:
if not self.rules.has_key(sym): if sym not in self.rules:
break break
else: else:
tbd.append(rule) tbd.append(rule)
@@ -212,7 +213,7 @@ class GenericParser:
def makeNewRules(self): def makeNewRules(self):
worklist = [] worklist = []
for rulelist in self.rules.values(): for rulelist in list(self.rules.values()):
for rule in rulelist: for rule in rulelist:
worklist.append((rule, 0, 1, rule)) worklist.append((rule, 0, 1, rule))
@@ -221,7 +222,7 @@ class GenericParser:
n = len(rhs) n = len(rhs)
while i < n: while i < n:
sym = rhs[i] sym = rhs[i]
if not self.rules.has_key(sym) or \ if sym not in self.rules or \
not self.nullable[sym]: not self.nullable[sym]:
candidate = 0 candidate = 0
i = i + 1 i = i + 1
@@ -238,7 +239,7 @@ class GenericParser:
if candidate: if candidate:
lhs = self._NULLABLE+lhs lhs = self._NULLABLE+lhs
rule = (lhs, rhs) rule = (lhs, rhs)
if self.newrules.has_key(lhs): if lhs in self.newrules:
self.newrules[lhs].append(rule) self.newrules[lhs].append(rule)
else: else:
self.newrules[lhs] = [ rule ] self.newrules[lhs] = [ rule ]
@@ -248,7 +249,7 @@ class GenericParser:
return None return None
def error(self, token): def error(self, token):
print "Syntax error at or near `%s' token" % token print("Syntax error at or near `%s' token" % token)
raise SystemExit raise SystemExit
def parse(self, tokens): def parse(self, tokens):
@@ -274,7 +275,7 @@ class GenericParser:
else: else:
sets.append([]) sets.append([])
self.makeSet(None, sets, len(tokens)) self.makeSet(None, sets, len(tokens))
finalitem = (self.finalState(tokens), 0) finalitem = (self.finalState(tokens), 0)
if finalitem not in sets[-2]: if finalitem not in sets[-2]:
if len(tokens) > 0: if len(tokens) > 0:
@@ -292,7 +293,8 @@ class GenericParser:
# #
return self._NULLABLE == sym[0:len(self._NULLABLE)] return self._NULLABLE == sym[0:len(self._NULLABLE)]
def skip(self, (lhs, rhs), pos=0): def skip(self, xxx_todo_changeme, pos=0):
(lhs, rhs) = xxx_todo_changeme
n = len(rhs) n = len(rhs)
while pos < n: while pos < n:
if not self.isnullable(rhs[pos]): if not self.isnullable(rhs[pos]):
@@ -551,12 +553,12 @@ class GenericParser:
rule = self.ambiguity(self.newrules[nt]) rule = self.ambiguity(self.newrules[nt])
else: else:
rule = self.newrules[nt][0] rule = self.newrules[nt][0]
#print rule # print(rule)
rhs = rule[1] rhs = rule[1]
attr = [None] * len(rhs) attr = [None] * len(rhs)
for i in xrange(len(rhs)-1, -1, -1): for i in range(len(rhs)-1, -1, -1):
attr[i] = self.deriveEpsilon(rhs[i]) attr[i] = self.deriveEpsilon(rhs[i])
return self.rule2func[self.new2old[rule]](attr) return self.rule2func[self.new2old[rule]](attr)
@@ -570,12 +572,12 @@ class GenericParser:
rule = choices[0] rule = choices[0]
if len(choices) > 1: if len(choices) > 1:
rule = self.ambiguity(choices) rule = self.ambiguity(choices)
#print rule # print(rule)
rhs = rule[1] rhs = rule[1]
attr = [None] * len(rhs) attr = [None] * len(rhs)
for i in xrange(len(rhs)-1, -1, -1): for i in range(len(rhs)-1, -1, -1):
sym = rhs[i] sym = rhs[i]
if not self.newrules.has_key(sym): if not self.newrules.has_key(sym):
if sym != self._BOF: if sym != self._BOF:
@@ -599,24 +601,23 @@ class GenericParser:
# appears in >1 method. Also undefined results if rules # appears in >1 method. Also undefined results if rules
# causing the ambiguity appear in the same method. # causing the ambiguity appear in the same method.
# #
sortlist = [] sortlist = []
name2index = {} name2index = {}
for i in xrange(len(rules)): for i in range(len(rules)):
lhs, rhs = rule = rules[i] lhs, rhs = rule = rules[i]
name = self.rule2name[self.new2old[rule]] name = self.rule2name[self.new2old[rule]]
sortlist.append((len(rhs), name)) sortlist.append((len(rhs), name))
name2index[name] = i name2index[name] = i
sortlist.sort() sortlist.sort()
list = map(lambda (a,b): b, sortlist) list = [a_b[1] for a_b in sortlist]
return rules[name2index[self.resolve(list)]] return rules[name2index[self.resolve(list)]]
def resolve(self, list): def resolve(self, list):
# '''
# Resolve ambiguity in favor of the shortest RHS. Resolve ambiguity in favor of the shortest RHS.
# Since we walk the tree from the top down, this Since we walk the tree from the top down, this
# should effectively resolve in favor of a "shift". should effectively resolve in favor of a "shift".
# '''
return list[0] return list[0]
# #
@@ -645,28 +646,29 @@ class GenericASTBuilder(GenericParser):
if isinstance(arg, self.AST): if isinstance(arg, self.AST):
children.append(arg) children.append(arg)
else: else:
children.append(arg) children.append(self.terminal(arg))
return self.nonterminal(lhs, children) return self.nonterminal(lhs, children)
def terminal(self, token): return token
def nonterminal(self, type, args): def nonterminal(self, type, args):
rv = self.AST(type) rv = self.AST(type)
rv[:len(args)] = args rv[:len(args)] = args
return rv return rv
#
# GenericASTTraversal is a Visitor pattern according to Design Patterns. For
# each node it attempts to invoke the method n_<node type>, falling
# back onto the default() method if the n_* can't be found. The preorder
# traversal also looks for an exit hook named n_<node type>_exit (no default
# routine is called if it's not found). To prematurely halt traversal
# of a subtree, call the prune() method -- this only makes sense for a
# preorder traversal. Node type is determined via the typestring() method.
#
class GenericASTTraversalPruningException: class GenericASTTraversalPruningException:
pass pass
class GenericASTTraversal: class GenericASTTraversal:
'''
GenericASTTraversal is a Visitor pattern according to Design Patterns. For
each node it attempts to invoke the method n_<node type>, falling
back onto the default() method if the n_* can't be found. The preorder
traversal also looks for an exit hook named n_<node type>_exit (no default
routine is called if it's not found). To prematurely halt traversal
of a subtree, call the prune() method -- this only makes sense for a
preorder traversal. Node type is determined via the typestring() method.
'''
def __init__(self, ast): def __init__(self, ast):
self.ast = ast self.ast = ast