94
|
NullUserException Mark Roddy · 技术社区 · 15 年前 |
![]() |
1
123
我一直 building tools (DMS Software Reengineering Toolkit) 自1995年以来,在强大的计算机科学家团队的支持下,从事通用程序操作(语言翻译是一个特例)。DMS提供通用解析、AST构建、符号表、控制和数据流分析、翻译规则应用、带注释的源文本再生等,所有这些都由计算机语言的显式定义参数化。 好 是巨大的(特别是如果您希望能够以一种通用的方式对多种语言执行此操作),那么您就需要为具有不可靠定义的语言提供可靠的解析器(PHP就是一个很好的例子)。
人们常常试图从他们熟悉的某项技术入手来制造某种通用机械,而这正是工作的一部分(Python AST就是一个很好的例子)。好消息是,部分工作已经完成。坏消息是机器内置了无数的假设,其中大多数假设只有在你试图强迫它做其他事情时才能发现。在这一点上,你会发现机器是按照它原来的功能来工作的,并且会非常非常抵制你让它做其他事情的企图(我怀疑尝试让Python AST为PHP建模会很有趣)。 我开始构建DMS的原因最初是为了建立很少有这样的假设的基础。有些东西让我们头痛。到目前为止,还没有黑洞(在过去的15年里,我工作中最困难的部分就是努力防止这种假设的蔓延)。 很多人还错误地认为,如果他们能解析(也许还能得到一个AST),他们就能很好地完成一些复杂的事情。其中一个困难的教训是,您需要符号表和流分析来进行良好的程序分析或转换。AST是必要的,但还不够。这就是为什么;乌尔曼的编译器之书并没有停留在第二章(OP有这个权利,因为他计划在AST之外建造更多的机器。有关此主题的详细信息,请参阅 Life After Parsing . “我不需要完美的翻译”这句话很麻烦。薄弱的翻译人员所做的是将80%的代码转换成“简单的”,而将20%的困难代码留给手工完成。如果要转换的应用程序非常小,并且只需要转换一次,那么20%就可以了。如果您想转换许多应用程序(甚至是同一个应用程序,随着时间的推移会有一些小的变化),这是不好的。如果您试图转换100K SLOC,那么20%是20000行原始代码,这些代码很难在您已经不理解的80000行已翻译程序的上下文中进行翻译、理解和修改。这需要付出巨大的努力。在百万线级别,这在实践中根本不可能(令人惊讶的是,有人不信任自动化工具,坚持用手工翻译百万行系统;这是公平的 更努力 翻译大型系统所需要的是90%的高转换率,或者很可能无法完成翻译活动的手动部分。 另一个关键考虑因素是要翻译的代码的大小。即使使用好的工具,也需要花费大量的精力来构建一个工作的、健壮的翻译程序。虽然构建一个转换器而不是简单地进行手动转换看起来既性感又酷,但是对于小的代码库(例如,根据我们的经验,高达10万SLOC)来说,经济性并不能证明这一点。没有人喜欢这个答案,但是如果你真的只需要翻译10K的SLOC代码,你最好咬紧牙关去做。是的,那很痛苦。 |
![]() |
2
13
我的答案将解决解析Python的具体任务,以便将其翻译成另一种语言,而不是Ira在他的答案中很好地解决的更高层次的方面。 简而言之: 不要使用解析器模块,有一个更简单的方法。
这个
|
![]() |
3
5
例如:
需要一个 C++代码复制(OK,你可以用一些循环构造来做得相当短,但仍然)。 我想这有点旁敲侧击。 你有没有写过基于语言语法的标记器/解析器?如果没有,你可能会想学习如何去做,因为这是这个项目的主要部分。我要做的是提出一个基本的图灵完整语法-一些相当类似于Python的东西 bytecode . 然后创建一个lexer/解析器,它接受一种语言语法(可能使用 BNF ),并根据语法将语言编译为中间语言。然后你要做的是反向操作——根据语法从你的语言创建一个解析器到目标语言。 可怕的 低效的代码,尤其是在像Python这样功能更强大的*语言中。
*我的意思是这需要4行代码:
|
![]() |
4
3
有几个答案告诉你不要麻烦。好吧,那有多有用?你想学习吗?你可以学习。这是汇编。碰巧你的目标语言不是机器代码,而是另一种高级语言。一直都是这样。 http://sourceforge.net/projects/lime-php/ 使用PHP和Python是幸运的,因为在许多方面,它们是彼此相同的语言,但语法不同。难点在于克服语法形式和数据结构之间的语义差异。例如,Python有列表和字典,而PHP只有assoc数组。 “学习者”的方法是建立一些适合语言的有限子集的东西(例如只打印语句、简单的数学和变量赋值),然后逐步消除这些限制。这基本上就是这个领域的“大”们都做的。
很明显,如果你让它变大的话。 |
![]() |
5
2
我将支持@EliBendersky关于使用ast.parse 而不是解析器(我以前不知道)。我也热情地推荐你去看看他的博客。我曾经ast.parse 执行Python->JavaScript转换器(@ https://bitbucket.org/amirouche/pythonium 有点 回顾其他实现并自己尝试。我用叉子叉起蟒蛇 https://github.com/PythonJS/PythonJS 我也开始了,这实际上是一个完整的重写。整体设计灵感来自PyPy和 http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-89-1.pdf 纸张。 我尝试过的一切,从一开始到最好的解决方案,即使看起来像蟒蛇营销它真的不是(不要犹豫,告诉我,如果有些事情似乎不正确的网络礼仪):
我从来没有真正成功地运行过睡衣失败,也从来没有尝试过再次阅读失败的代码。但在我看来,睡衣是在做API->API转换(或框架到框架),而不是Python到JavaScript的转换。JavaScript框架使用页面中已有的数据或来自服务器的数据。Python代码只是“管道”。之后,我发现睡衣其实是一条真正的蟒蛇->js翻译。 我仍然认为可以使用API->API(或框架->框架)翻译,这是我在Pythonium的基本工作,但在较低的层次。可能睡衣和Pythonium的算法一样。。。
由于在这个项目的过程中写的第一行,我知道PyPy,甚至PyPy的JavaScript后端。是的,如果找到它,可以直接从PyPy生成JavaScript中的Python解释器。人们说,这是一场灾难。我不知道为什么。但我认为原因是他们用来实现解释器的中间语言RPython是Python的一个子集,专门翻译成C(也许还有asm)。Ira Baxter说,当你构建一个东西的时候,你总是会做出假设,也许你会对它进行微调,使之在PyPy:Python的情况下达到最佳效果->C翻译。这些假设在另一个上下文中可能不相关,更糟的是,它们可以推断开销,否则直接翻译很可能总是更好。 用Python编写解释器听起来是个(非常)好的主意。但出于性能原因,我对编译器更感兴趣,而且实际上将Python编译成JavaScript比解释它更容易。 我开始使用PythonJS的想法是将Python的一个子集放在一起,我可以很容易地将其翻译成JavaScript。因为过去的经验,一开始我甚至都懒得去实现OO系统。我实现了将Python的子集转换为JavaScript:
这看起来很多,但实际上与Python的完整语义相比非常狭窄。它实际上是带有Python语法的JavaScript。 生成的JS是完美的ie,没有开销,不能通过进一步编辑来提高性能。如果可以改进生成的代码,也可以从Python源文件中进行。此外,编译器不依赖于任何可以在.JS中找到的JS技巧 http://superherojs.com/ https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/veloce/veloce.py?at=master 793 SLOC+大约100 SLOC与其他转换器共享代码。 经改编的pystones.py 可在Veloce模式下转换。 https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pystone/?at=master 安装基本Python后->JavaScript翻译我选择了另一条路径将完整的Python翻译成JavaScript。除了目标语言之外,glib编写面向对象的基于类的代码的方法是JS,这样您就可以访问数组、类映射对象和许多其他技巧,所有这些都是用Python编写的。IIRC Pythonium翻译程序中没有javascript代码。获得单一继承并不困难,以下是使Pythonium完全符合Python的困难部分:
https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/runtime.py?at=master 它是用与Python-Veloce兼容的Python编写的。 https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/compliant.py?at=master 不直接生成JavaScript代码,最重要的是不执行ast->ast转换。我试过ast->ast和ast即使比cst好也不好用ast.NodeTransformer 更重要的是,我不需要做ast->阿斯特。 在我的例子中,对python ast执行python ast至少可能是一种性能改进,因为有时我会在生成与块相关联的代码之前检查块的内容,例如:
所以在翻译的每一个阶段,我并不真正访问每个节点一次。 整个过程可以描述为:
Python内置代码是用Python代码(!)编写的,IIRC有一些与引导类型相关的限制,但是您可以访问所有可以在兼容模式下翻译Pythonium的内容。看一看 https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master 阅读pythonium兼容的JS代码是可以理解的,但是源代码映射会有很大帮助。
只有Python-Veloce模式,我很高兴!但一路上我发现我真正想要的是从Javascript中解放我和其他人,但更重要的是能够 创造 以舒适的方式。这让我想到了Scheme、DSL、模型以及最终的领域特定模型(参见。 http://dsmforum.org/
当有人说某件事很难或更经常是不可能的时候,我的回答是“只需要时间就可以找到一个不可能的问题的解决方案”,否则说没有什么是不可能的,除非在这种情况下证明它是不可能的一个数学证明。。。
和
或
大多数人说一件事“难”或“不可能”,并没有提供理由。C++难以解析?我知道,它们仍然是(免费的)C++解析器。邪恶在细节中?我知道。单独说不可能是没有帮助的,甚至比“没有帮助”更糟糕,这是令人沮丧的,有些人是想让别人泄气。关于这个问题我是通过 https://stackoverflow.com/questions/22621164/how-to-automatically-generate-a-parser-code-to-code-translator-from-a-corpus . 什么是完美
我认为没有一种模式不能从一种语言翻译成另一种语言,至少以一种不那么完美的方式。既然语言对语言的翻译是可能的,你最好先瞄准这一点。因为,我认为根据 http://en.wikipedia.org/wiki/Graph_isomorphism_problem 框架->我最好将其可视化为API的框架->API翻译可能仍然是您需要记住的一种改进生成代码的方法。例如:Prolog是一种非常特殊的语法,但是你仍然可以通过用Python描述同一个图来进行类似Prolog的计算。。。如果我要实现一个Prolog到Python的转换器,我不会在Python中实现统一,而是在一个C库中实现统一,并提出了一个Pythonist非常可读的“Python语法”。最后,语法只是我们赋予其意义的“绘画”(这就是为什么我开始使用scheme)。邪恶在于语言的细节,我不是说语法。语言中使用的概念 获取属性 钩子(你可以不使用它)但是必需的VM特性,比如尾部递归优化,可能很难处理。不管初始程序是否使用尾部递归,即使目标语言中没有尾部递归,也可以使用greenlet/event循环来模拟它。
您还可能知道什么将被翻译成快速和慢速代码。 还有stdlib或任何库的问题,但没有明确的答案,这取决于你的目标。
针对PHP这样的平台要比针对浏览器容易得多,因为您可以提供慢路径和/或关键路径的C实现。 第一个项目是将Python转换为PHP,至少对于我所知道的PHP3子集,是定制的veloce.py 是你最好的选择。如果你能实现veloce.py 对于PHP,您可能可以运行兼容模式。。。如果你能把PHP翻译成PHP的子集,你就可以用PHP生成_veloce.py 这意味着您可以将PHP翻译成veloce.py 这意味着你可以将PHP翻译成Javascript。只是说。。。 您还可以查看这些库: https://www.rfk.id.au/blog/entry/pypy-js-poc-jit/
|
![]() |
6
0
Vala compiler ,将Vala(一种类似C的语言)翻译成C。 |