scanner15.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. # Copyright (c) 2016-2018, 2021-2023 by Rocky Bernstein
  2. """
  3. Python 1.5 bytecode decompiler massaging.
  4. This massages tokenized 1.5 bytecode to make it more amenable for
  5. grammar parsing.
  6. """
  7. import uncompyle6.scanners.scanner21 as scan
  8. # from uncompyle6.scanners.scanner26 import ingest as ingest26
  9. # bytecode verification, verify(), uses JUMP_OPs from here
  10. from xdis.opcodes import opcode_15
  11. JUMP_OPS = opcode_15.JUMP_OPS
  12. # We base this off of 2.2 instead of the other way around
  13. # because we cleaned things up this way.
  14. # The history is that 2.7 support is the cleanest,
  15. # then from that we got 2.6 and so on.
  16. class Scanner15(scan.Scanner21):
  17. def __init__(self, show_asm=False):
  18. scan.Scanner21.__init__(self, show_asm)
  19. self.opc = opcode_15
  20. self.opname = opcode_15.opname
  21. self.version = (1, 5)
  22. self.genexpr_name = "<generator expression>"
  23. return
  24. def ingest(self, co, classname=None, code_objects={}, show_asm=None):
  25. """
  26. Create "tokens" the bytecode of an Python code object. Largely these
  27. are the opcode name, but in some cases that has been modified to make parsing
  28. easier.
  29. returning a list of uncompyle6 Token's.
  30. Some transformations are made to assist the deparsing grammar:
  31. - various types of LOAD_CONST's are categorized in terms of what they load
  32. - COME_FROM instructions are added to assist parsing control structures
  33. - operands with stack argument counts or flag masks are appended to the
  34. opcode name, e.g.:
  35. * BUILD_LIST, BUILD_SET
  36. * MAKE_FUNCTION and FUNCTION_CALLS append the number of positional
  37. arguments
  38. - EXTENDED_ARGS instructions are removed
  39. Also, when we encounter certain tokens, we add them to a set which will cause
  40. custom grammar rules. Specifically, variable arg tokens like MAKE_FUNCTION or
  41. BUILD_LIST cause specific rules for the specific number of arguments they take.
  42. """
  43. tokens, customize = scan.Scanner21.ingest(
  44. self, co, classname, code_objects, show_asm
  45. )
  46. for t in tokens:
  47. if t.op == self.opc.UNPACK_LIST:
  48. t.kind = "UNPACK_LIST_%d" % t.attr
  49. pass
  50. return tokens, customize