Generates random Python functions using Markov chains
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

167 行
4.9 KiB

  1. from code import interact
  2. import imp
  3. import opcode
  4. import os
  5. import random
  6. import re
  7. import sys
  8. import types
  9. MARKOV_START = -1
  10. MARKOV_END = -2
  11. def make_chain(funcs):
  12. chain = {}
  13. for func in funcs:
  14. _parse_func(func, chain)
  15. return chain
  16. def make_function(chain, name, argcount=1):
  17. codes, constants, varnames = _make_codes(chain)
  18. names = ()
  19. codestring = "".join([chr(code) for code in codes])
  20. lnotab = ""
  21. code = types.CodeType(argcount, len(varnames), 1024, 0, codestring,
  22. constants, names, varnames, "<smash>", name, 1,
  23. lnotab)
  24. func = types.FunctionType(code, globals(), name)
  25. return func
  26. def print_chain(chain):
  27. print "{"
  28. for code in sorted(chain.keys()):
  29. name = _opcode_to_opname(code)
  30. target_counts = {}
  31. for tcode in chain[code]:
  32. target = _opcode_to_opname(tcode[0])
  33. if tcode[0] >= opcode.HAVE_ARGUMENT:
  34. target = "{0}({1})".format(target, tcode[1])
  35. try:
  36. target_counts[target] += 1
  37. except KeyError:
  38. target_counts[target] = 1
  39. targets = []
  40. for target, count in target_counts.iteritems():
  41. if count == 1:
  42. targets.append(target)
  43. else:
  44. targets.append("{0}x {1}".format(count, target))
  45. targets.sort()
  46. print name.rjust(20), "=> [{0}]".format(", ".join(targets))
  47. print "}"
  48. def print_function(func):
  49. codeobj = func.__code__
  50. codestring = codeobj.co_code
  51. length = len(codestring)
  52. i = 0
  53. while i < length:
  54. code = ord(codestring[i])
  55. i += 1
  56. print opcode.opname[code].rjust(20),
  57. if code >= opcode.HAVE_ARGUMENT:
  58. arg = _get_argument(codeobj, codestring, i, code)
  59. i += 2
  60. print " ({0})".format(arg)
  61. else:
  62. print
  63. def run():
  64. try:
  65. path, name = os.path.split(sys.argv[1])
  66. name = re.sub("\.pyc?$", "", name)
  67. except IndexError:
  68. raise RuntimeError("Needs a filename as a command-line argument")
  69. file_obj, path, desc = imp.find_module(name, [path])
  70. try:
  71. module = imp.load_module(name, file_obj, path, desc)
  72. finally:
  73. file_obj.close()
  74. _demo(module.corpus)
  75. def _parse_func(func, chain):
  76. codeobj = func.__code__
  77. codestring = codeobj.co_code
  78. length = len(codestring)
  79. i = 0
  80. prevcode = MARKOV_START
  81. while i < length:
  82. code = ord(codestring[i])
  83. i += 1
  84. if code >= opcode.HAVE_ARGUMENT:
  85. arg = _get_argument(codeobj, codestring, i, code)
  86. i += 2
  87. else:
  88. arg = None
  89. _chain_append(chain, prevcode, (code, arg))
  90. prevcode = code
  91. _chain_append(chain, code, (MARKOV_END, None))
  92. def _get_argument(codeobj, codestring, i, code):
  93. arg = ord(codestring[i]) + ord(codestring[i + 1]) * 256
  94. if code in opcode.hasconst:
  95. return codeobj.co_consts[arg]
  96. elif code in opcode.haslocal:
  97. return codeobj.co_varnames[arg]
  98. elif code in opcode.hascompare:
  99. return opcode.cmp_op[arg]
  100. raise NotImplementedError(code, opcode.opname[code])
  101. def _chain_append(chain, first, second):
  102. try:
  103. chain[first].append(second)
  104. except KeyError:
  105. chain[first] = [second]
  106. def _make_codes(chain):
  107. codes = []
  108. instruction = random.choice(chain[MARKOV_START])
  109. constants, varnames = [], []
  110. while 1:
  111. code, arg = instruction
  112. if code == MARKOV_END:
  113. break
  114. codes.append(code)
  115. if code >= opcode.HAVE_ARGUMENT:
  116. if code in opcode.hasconst:
  117. if arg not in constants:
  118. constants.append(arg)
  119. args = constants
  120. elif code in opcode.haslocal:
  121. if arg not in varnames:
  122. varnames.append(arg)
  123. args = varnames
  124. elif code in opcode.hascompare:
  125. args = opcode.cmp_op
  126. else:
  127. raise NotImplementedError(code, opcode.opname[code])
  128. codes.append(args.index(arg) % 256)
  129. codes.append(args.index(arg) // 256)
  130. instruction = random.choice(chain[code])
  131. return codes, tuple(constants), tuple(varnames)
  132. def _opcode_to_opname(code):
  133. if code == MARKOV_START:
  134. return "START"
  135. elif code == MARKOV_END:
  136. return "END"
  137. return opcode.opname[code]
  138. def _demo(corpus, arg=12.0):
  139. chain = make_chain(corpus)
  140. func = make_function(chain, "func")
  141. print "Using {0}-function corpus.".format(len(corpus))
  142. print "Smashed function disassembly:"
  143. print_function(func)
  144. print
  145. print "func({0}) =".format(arg), func(arg)
  146. if len(sys.argv) > 2 and sys.argv[2] == "-i":
  147. variables = dict(globals().items() + locals().items())
  148. interact(banner="", local=variables)
  149. if __name__ == "__main__":
  150. run()