我明白了吗?PyPy解释器实际上是自己解释自己,然后自己翻译吗?
我现在的理解是:
如果这是真的,那么这是我所见过的最令人难以置信的事情之一。
发布于 2011-12-19 17:54:18
实际上,PyPy的翻译过程在概念上没有听上去那么递归。
实际上,它只是一个处理Python函数/类/其他对象(而不是 Python源代码)并输出C代码的Python程序。当然,它不只是处理任何对象;它只能处理特定的表单,如果用RPython编写要翻译的代码,就会得到特定的表单。
因为翻译工具链是Python程序,所以可以在任何Python解释器之上运行它,这显然包括PyPy的python解释器。所以这没什么特别的。
因为它翻译了RPython对象,所以可以使用它来翻译PyPy的python解释器,该解释器是用RPython编写的。
但是您不能在翻译框架本身上运行它,即而不是 RPython。只有PyPy的python解释器本身是RPython。
事情之所以有趣,只是因为RPython代码也是Python (但不是相反的),而且因为RPython从来没有在源文件中“真正存在”,而是只存在于运行中的Python进程中,该进程必然包括其他非RPython代码(例如,没有“纯-RPython”导入或函数定义,例如,因为转换器对已经定义和导入的函数进行操作)。
请记住,转换工具链对内存中的Python代码对象进行操作。Python的执行模型意味着在某些Python代码运行之前这些代码是不存在的。您可以想象,如果高度简化翻译过程,那么开始翻译过程就会有点像这样:
from my_interpreter import main
from pypy import translate
translate(main)
众所周知,只要导入main
,就会运行大量的Python代码,包括所有其他模块my_interpreter
导入。但是,翻译过程开始分析函数对象main
;它从未看到、也不关心执行了什么代码来生成main
。
考虑这一点的一种方法是,“RPython中的编程”意味着“编写一个生成RPython程序的Python程序,然后将其提供给翻译过程”。这相对容易理解,并且有点类似于其他编译器的工作方式(例如,用C编写编程的一种方法是编写C预处理器程序,生成C程序,然后将C程序输入C编译器)。
在PyPy情况下,事情只会变得混乱,因为所有三个组件(生成RPython程序、RPython程序和翻译过程的Python程序)都被加载到中--相同的解释器。这意味着很可能有一些参数调用的函数是RPython,而不是其他参数调用的函数,从翻译框架调用助手函数是生成RPython程序的一部分,还有很多其他奇怪的事情。因此,情况变得相当模糊,而且您不一定要将源行清晰地划分为“要翻译的RPython”、"Python生成我的RPython程序“和”将RPython程序交给翻译框架“。
运行在PyPy之上的CPython解释器执行以部分解释自身。
我认为你在这里暗示的是PyPy在翻译过程中使用了流对象空间来做抽象的解释。就连这也不像一开始看上去那么疯狂和扭曲。我对PyPy的这一部分知之甚少,但据我所知:
PyPy通过将它们委托给一个“对象空间”来实现Python解释器的所有操作,该对象空间包含所有基本内置操作的实现。但是您可以插入不同的对象空间以获得不同的效果,只要它们实现相同的“对象空间”接口,解释器仍然能够“执行”Python代码。
RPython转换工具链处理的PyPy代码对象是PyPy代码,可以由解释器执行。因此,通过插入流对象空间,PyPy重新使用了部分Python解释器作为翻译工具链的一部分。当使用这个对象空间“执行”代码时,解释器实际上并不执行代码的操作,而是生成流程图,类似于许多其他编译器使用的中间表示形式;它只是一个简单的机器可操作的代码表示,需要进一步处理。这就是如何将常规(R)Python代码对象转换为翻译过程的其余部分的输入。
由于翻译过程中通常要翻译的东西是PyPy的Python解释器,所以它确实用流对象空间“解释自己”。但这实际上意味着,您有一个正在处理Python函数的Python程序,包括那些执行处理的函数。它本身并不比将装饰器应用到自己,或者让包装类包装自己的实例(或者包装类本身)更令人费解。
嗯,有点乱七八糟的。我希望这能帮上忙,我希望我没有说错什么,如果我说了,请纠正我。
发布于 2011-12-09 14:37:27
免责声明:我不是PyPy方面的专家--特别是,我不理解RPython翻译的细节,我只是引用我以前读过的东西。有关RPython翻译如何工作的更具体的文章,请查看此回答。
答案是,是的,它可以(但只有在第一次使用CPython编译之后)。
较长的描述:
起初,它似乎高度弯曲和自相矛盾,但一旦你理解它,这是容易的。在维基百科上查看答案。
程序开发中的引导开始于20世纪50年代,当时每个程序都是用十进制代码或二进制代码,一点一点地(1s和0)构建的,因为没有高级计算机语言,没有编译器,没有汇编程序,也没有链接器。一个小型汇编程序是为一台新计算机(例如IBM 650)编写的,它将一些指令转换成二进制或十进制代码: A1。然后,这个简单的汇编程序用它定义的汇编语言重新编写,但是有了扩展,可以使用一些额外的助记符来处理更复杂的操作代码。
这个过程被称为软件引导。基本上,您构建了一个工具,比如一个C++编译器,它使用的是一种已经生成的较低的语言(所有的东西都必须从二进制中编码),比如ASM。既然已经有了C++,现在可以在C++中编写C++编译器,然后使用ASM C++编译器编译新的编译器。一旦编译了新编译器,现在就可以使用它来编译自己了。
所以基本上,用手工编写第一个计算机工具,用那个解释器再做一个稍微好一点的,用那个来做一个更好的,最终你会得到今天所有复杂的软件!:)
另一个有趣的例子是CoffeeScript语言,它是用.CoffeeScript。(虽然这个用例仍然需要使用外部解释器,即Node.js)
--运行在CPython之上的PyPy解释器执行以部分解释自己,此时它将控制权交给它的RPython一半,后者执行翻译?。
您可以使用已经编译的PyPy解释器来编译PyPy,也可以使用CPython来编译它。但是,由于PyPy现在有一个JIT,所以使用自己而不是CPython来编译PyPy会更快。(多数情况下为PyPy现在比CPython快)
https://stackoverflow.com/questions/8452396
复制相似问题