PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/cpython.py

https://github.com/albertz/PyCPython
Python | 201 lines | 159 code | 21 blank | 21 comment | 9 complexity | 417fa4f2a2079d77c4f58b22f6e63df3 MD5 | raw file
  1. #!/usr/bin/env python3
  2. # PyCPython - interpret CPython in Python
  3. # by Albert Zeyer, 2011
  4. # code under BSD 2-Clause License
  5. from __future__ import print_function
  6. import argparse
  7. import os
  8. import sys
  9. if __name__ == '__main__':
  10. MyDir = os.path.dirname(sys.argv[0])
  11. else:
  12. MyDir = "."
  13. CPythonDir = MyDir + "/CPython"
  14. import cparser
  15. import cparser.interpreter
  16. class CPythonState(cparser.State):
  17. def __init__(self):
  18. super(CPythonState, self).__init__()
  19. self.autoSetupSystemMacros()
  20. self.autoSetupGlobalIncludeWrappers()
  21. def findIncludeFullFilename(self, filename, local):
  22. fullfn = CPythonDir + "/Include/" + filename
  23. if os.path.exists(fullfn): return fullfn
  24. return super(CPythonState, self).findIncludeFullFilename(filename, local)
  25. def readLocalInclude(self, filename):
  26. #print " ", filename, "..."
  27. if filename == "pyconfig.h":
  28. def reader():
  29. # see CPython/pyconfig.h.in for reference
  30. import ctypes
  31. sizeofMacro = lambda t: cparser.Macro(rightside=str(ctypes.sizeof(t)))
  32. self.macros["SIZEOF_SHORT"] = sizeofMacro(ctypes.c_short)
  33. self.macros["SIZEOF_INT"] = sizeofMacro(ctypes.c_int)
  34. self.macros["SIZEOF_LONG"] = sizeofMacro(ctypes.c_long)
  35. self.macros["SIZEOF_LONG_LONG"] = sizeofMacro(ctypes.c_longlong)
  36. self.macros["SIZEOF_DOUBLE"] = sizeofMacro(ctypes.c_double)
  37. self.macros["SIZEOF_FLOAT"] = sizeofMacro(ctypes.c_float)
  38. self.macros["SIZEOF_VOID_P"] = sizeofMacro(ctypes.c_void_p)
  39. self.macros["SIZEOF_SIZE_T"] = sizeofMacro(ctypes.c_size_t)
  40. self.macros["SIZEOF_UINTPTR_T"] = sizeofMacro(ctypes.POINTER(ctypes.c_uint))
  41. self.macros["SIZEOF_PTHREAD_T"] = self.macros["SIZEOF_LONG"]
  42. self.macros["SIZEOF_WCHAR_T"] = sizeofMacro(ctypes.c_wchar)
  43. self.macros["SIZEOF_PID_T"] = self.macros["SIZEOF_INT"]
  44. self.macros["SIZEOF_TIME_T"] = self.macros["SIZEOF_LONG"]
  45. self.macros["SIZEOF__BOOL"] = cparser.Macro(rightside="1")
  46. self.macros["HAVE_SIGNAL_H"] = cparser.Macro(rightside="1")
  47. self.macros["HAVE_STDARG_PROTOTYPES"] = cparser.Macro(rightside="1")
  48. self.macros["HAVE_STD_ATOMIC"] = cparser.Macro(rightside="1")
  49. self.macros["HAVE_WCHAR_H"] = cparser.Macro(rightside="1")
  50. self.macros["_POSIX_THREADS"] = cparser.Macro(rightside="1")
  51. # _GNU_SOURCE, _POSIX_C_SOURCE or so?
  52. return
  53. yield None # make it a generator
  54. return reader(), None
  55. return super(CPythonState, self).readLocalInclude(filename)
  56. def parse_cpython(self):
  57. # We keep all in the same state, i.e. the same static space.
  58. # This also means that we don't reset macro definitions. This speeds up header includes.
  59. # Usually this is not a problem.
  60. self.macros["Py_BUILD_CORE"] = cparser.Macro(rightside="1") # Makefile
  61. self.macros["Py_BUILD_CORE_BUILTIN"] = cparser.Macro(rightside="1") # Makefile
  62. cparser.parse(CPythonDir + "/Modules/main.c", self) # Py_Main
  63. self.macros["FAST_LOOPS"] = cparser.Macro(rightside="0") # not sure where this would come from
  64. cparser.parse(CPythonDir + "/Python/ceval.c", self) # PyEval_EvalFrameEx etc
  65. del self.macros["EMPTY"] # will be redefined later
  66. cparser.parse(CPythonDir + "/Python/getopt.c", self) # _PyOS_GetOpt
  67. cparser.parse(CPythonDir + "/Python/pythonrun.c", self) # Py_Initialize
  68. cparser.parse(CPythonDir + "/Python/pystate.c", self) # PyInterpreterState_New
  69. cparser.parse(CPythonDir + "/Python/sysmodule.c", self) # PySys_ResetWarnOptions
  70. cparser.parse(CPythonDir + "/Python/random.c", self) # _PyRandom_Init
  71. cparser.parse(CPythonDir + "/Objects/object.c", self) # _Py_ReadyTypes etc
  72. cparser.parse(CPythonDir + "/Objects/typeobject.c", self) # PyType_Ready
  73. cparser.parse(CPythonDir + "/Objects/tupleobject.c", self) # PyTuple_New
  74. del self.macros["Return"] # will be used differently
  75. # We need these macro hacks because dictobject.c will use the same vars.
  76. self.macros["length_hint_doc"] = cparser.Macro(rightside="length_hint_doc__dict")
  77. self.macros["numfree"] = cparser.Macro(rightside="numfree__dict")
  78. self.macros["free_list"] = cparser.Macro(rightside="free_list__dict")
  79. cparser.parse(CPythonDir + "/Objects/dictobject.c", self) # PyDict_New
  80. # We need this macro hack because stringobject.c will use the same var.
  81. self.macros["sizeof__doc__"] = cparser.Macro(rightside="sizeof__doc__str")
  82. cparser.parse(CPythonDir + "/Objects/stringobject.c", self) # PyString_FromString
  83. cparser.parse(CPythonDir + "/Objects/obmalloc.c", self) # PyObject_Free
  84. cparser.parse(CPythonDir + "/Modules/gcmodule.c", self) # _PyObject_GC_NewVar
  85. cparser.parse(CPythonDir + "/Objects/descrobject.c", self) # PyDescr_NewWrapper
  86. # We need these macro hacks because methodobject.c will use the same vars.
  87. self.macros["numfree"] = cparser.Macro(rightside="numfree__methodobj")
  88. self.macros["free_list"] = cparser.Macro(rightside="free_list__methodobj")
  89. cparser.parse(CPythonDir + "/Objects/methodobject.c", self) # PyCFunction_NewEx
  90. # We need these macro hacks because methodobject.c will use the same vars.
  91. self.macros["numfree"] = cparser.Macro(rightside="numfree__list")
  92. self.macros["free_list"] = cparser.Macro(rightside="free_list__list")
  93. self.macros["sizeof_doc"] = cparser.Macro(rightside="sizeof_doc__list")
  94. self.macros["length_hint_doc"] = cparser.Macro(rightside="length_hint_doc__list")
  95. self.macros["index_doc"] = cparser.Macro(rightside="index_doc__list")
  96. self.macros["count_doc"] = cparser.Macro(rightside="count__list")
  97. cparser.parse(CPythonDir + "/Objects/listobject.c", self) # PyList_New
  98. cparser.parse(CPythonDir + "/Objects/abstract.c", self) # PySequence_List
  99. cparser.parse(CPythonDir + "/Python/modsupport.c", self) # Py_BuildValue
  100. def init_faulthandler(sigusr1_chain=False):
  101. """
  102. :param bool sigusr1_chain: whether the default SIGUSR1 handler should also be called.
  103. """
  104. try:
  105. import faulthandler
  106. except ImportError as e:
  107. print("faulthandler import error. %s" % e)
  108. return
  109. # Only enable if not yet enabled -- otherwise, leave it in its current state.
  110. if not faulthandler.is_enabled():
  111. faulthandler.enable()
  112. if os.name != 'nt':
  113. import signal
  114. # This will print a backtrace on SIGUSR1.
  115. # Note that this also works when Python is hanging,
  116. # i.e. in cases where register_sigusr1_print_backtrace() will not work.
  117. faulthandler.register(signal.SIGUSR1, all_threads=True, chain=sigusr1_chain)
  118. def register_sigusr1_print_backtrace():
  119. if os.name == "nt":
  120. return
  121. def sigusr1_handler(sig, frame):
  122. print("--- SIGUSR1 handler")
  123. better_exchook.print_tb(tb=frame)
  124. import signal
  125. signal.signal(signal.SIGUSR1, sigusr1_handler)
  126. def main(argv):
  127. argparser = argparse.ArgumentParser(
  128. usage="%s [PyCPython options, see below] [CPython options, see via --help]" % argv[0],
  129. description="Emulate CPython by interpreting its C code via PyCParser.",
  130. epilog="All other options are passed on to CPython. Use --help to see them.",
  131. add_help=False # we will add our own
  132. )
  133. argparser.add_argument(
  134. '--pycpython-help', action='help', help='show this help message and exit')
  135. argparser.add_argument(
  136. '--dump-python', action='store', nargs=1,
  137. help="Dumps the converted Python code of the specified function, e.g. Py_Main.")
  138. argparser.add_argument(
  139. '--verbose-jit', action='store_true',
  140. help="Prints what functions and global vars we are going to translate.")
  141. args_ns, argv_rest = argparser.parse_known_args(argv[1:])
  142. argv = argv[:1] + argv_rest
  143. print("PyCPython -", argparser.description,)
  144. print("(use --pycpython-help for help)")
  145. state = CPythonState()
  146. print("Parsing CPython...", end="")
  147. state.parse_cpython()
  148. if state._errors:
  149. print("finished, parse errors:")
  150. for m in state._errors:
  151. print(m)
  152. else:
  153. print("finished, no parse errors.")
  154. interpreter = cparser.interpreter.Interpreter()
  155. interpreter.register(state)
  156. if args_ns.dump_python:
  157. for fn in args_ns.dump_python:
  158. print()
  159. print("PyAST of %s:" % fn)
  160. interpreter.dumpFunc(fn)
  161. sys.exit()
  162. if args_ns.verbose_jit:
  163. interpreter.debug_print_getFunc = True
  164. interpreter.debug_print_getVar = True
  165. args = ("Py_Main", len(argv), argv + [None])
  166. print("Run", args, ":")
  167. interpreter.runFunc(*args)
  168. if __name__ == '__main__':
  169. import better_exchook
  170. better_exchook.install()
  171. register_sigusr1_print_backtrace()
  172. init_faulthandler(sigusr1_chain=True)
  173. main(sys.argv)