代码之家  ›  专栏  ›  技术社区  ›  NullUserException Mark Roddy

我可以在代码上实施什么样的模式,以使代码更容易翻译成另一种编程语言[[关闭]

  •  94
  • NullUserException Mark Roddy  · 技术社区  · 15 年前

    我打算做一个附带项目,目标是将代码从一种编程语言翻译成另一种编程语言。我开始使用的语言是PHP和Python(Python到PHP应该更容易开始使用),但理想情况下,我可以相对轻松地添加其他语言。计划是:

    • 我还研究了IOC和依赖注入,因为它们可能使翻译过程更容易,更不容易出错。

    • 我会利用Python的 parser module token_get_all() ,这是一个开始。

    • 从那时起,我可以构建AST、symbol表和控制流。

    我不需要完美的翻译 . 我仍然需要检查生成的代码并修复问题。理想情况下,译者应该标记有问题的翻译。

    在你问“这到底是什么意思”之前,答案是。。。这将是一次有趣的学习经历。如果你有任何见解,如何使这不那么令人生畏,请让我知道。


    我更感兴趣的是知道我可以在代码上实施什么样的模式以使代码更易于翻译(即:IoC、SOA?),而不是如何翻译。

    6 回复  |  直到 5 年前
        1
  •  123
  •   mana    11 年前

    我一直 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代码,你最好咬紧牙关去做。是的,那很痛苦。

    succeed

        2
  •  13
  •   Eli Bendersky    15 年前

    我的答案将解决解析Python的具体任务,以便将其翻译成另一种语言,而不是Ira在他的答案中很好地解决的更高层次的方面。

    简而言之: 不要使用解析器模块,有一个更简单的方法。

    这个 ast article on this 去年,但简而言之,使用 parse 方法 将Python源代码解析为AST。这个 parser 模块将为您提供一个解析树,而不是AST。 Be wary of the difference .

    2to3 由Python开发人员创建的工具,用于将python2代码转换为python3代码。就前端而言,它包含了您需要将Python转换为的大多数元素 某物 . 但是,由于python2和python3的核心是相似的,因此不需要任何仿真机制。

        3
  •  5
  •   Wayne Werner    15 年前

    did it over a summer.

    例如:

    word = 'This is not a word'
    print word[::-2]
    

    需要一个 C++代码复制(OK,你可以用一些循环构造来做得相当短,但仍然)。

    我想这有点旁敲侧击。

    你有没有写过基于语言语法的标记器/解析器?如果没有,你可能会想学习如何去做,因为这是这个项目的主要部分。我要做的是提出一个基本的图灵完整语法-一些相当类似于Python的东西 bytecode . 然后创建一个lexer/解析器,它接受一种语言语法(可能使用 BNF ),并根据语法将语言编译为中间语言。然后你要做的是反向操作——根据语法从你的语言创建一个解析器到目标语言。

    可怕的 低效的代码,尤其是在像Python这样功能更强大的*语言中。

    • 阅读提供的语法
    • 将程序编译成中间(但也是图灵完整)语法
    • ...?
    • 利润!(?)

    *我的意思是这需要4行代码:

    myinput = raw_input("Enter something: ")
    print myinput.replace('a', 'A')
    print sum(ord(c) for c in myinput)
    print myinput[::-1]
    

        4
  •  3
  •   Ian    15 年前

    有几个答案告诉你不要麻烦。好吧,那有多有用?你想学习吗?你可以学习。这是汇编。碰巧你的目标语言不是机器代码,而是另一种高级语言。一直都是这样。

    http://sourceforge.net/projects/lime-php/

    使用PHP和Python是幸运的,因为在许多方面,它们是彼此相同的语言,但语法不同。难点在于克服语法形式和数据结构之间的语义差异。例如,Python有列表和字典,而PHP只有assoc数组。

    “学习者”的方法是建立一些适合语言的有限子集的东西(例如只打印语句、简单的数学和变量赋值),然后逐步消除这些限制。这基本上就是这个领域的“大”们都做的。

    很明显,如果你让它变大的话。

        5
  •  2
  •   Community CDub    8 年前

    我将支持@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 纸张。

    我尝试过的一切,从一开始到最好的解决方案,即使看起来像蟒蛇营销它真的不是(不要犹豫,告诉我,如果有些事情似乎不正确的网络礼仪):

    • 使用原型继承在普通的老JavaScript中实现Python语义:AFAIK使用JS原型对象系统实现Python多重继承是不可能的。后来我确实尝试过使用其他技巧(参见getattribute)。据我所知,在JavaScript中没有Python多重继承的实现,最好的是singleinhertance+mixins,我不确定它们是否能处理diamond继承。有点像Skulpt,但是没有googleclojure。

    • 我试着使用googleclojure,就像Skulpt(编译器)一样,而不是实际读取Skulpt代码。反正因为基于JS原型的对象系统还是不可能的。创建绑定非常困难,需要编写JavaScript和大量样板代码(cf。 https://github.com/skulpt/skulpt/issues/50 在那里我是鬼)。当时没有明确的方法将绑定集成到构建系统中。我认为Skulpt是一个库,您只需在html中包含.py文件即可执行,不需要开发人员完成编译阶段。

    我从来没有真正成功地运行过睡衣失败,也从来没有尝试过再次阅读失败的代码。但在我看来,睡衣是在做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:

    • while/if/elif/else
    • Python类型已转换为JavaScript类型(没有任何类型的Python类型)
    • for只能迭代Javascript数组(对于in数组)
    • 对JavaScript的透明访问:如果用Python代码编写数组,它将被翻译成JavaScript中的数组。在可用性方面,这是其竞争对手的最大成就。
    • 您可以将Python源代码中定义的函数传递给javascript函数。将考虑默认参数。
    • 它添加了一个名为new的特殊函数,该函数被翻译成JavaScript new,例如:new(Python)(1,2,spam,“egg”)被翻译成“new Python(1,2,spam,“egg”)。
    • “var”由翻译程序自动处理(非常好的发现从布雷特(蟒蛇贡献者)。
    • 全局关键字
    • 闭包
    • 通过requirejs支持导入

    这看起来很多,但实际上与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的困难部分:

    • spam.egg 在Python中总是翻译成 getattribute(spam, "egg")
    • 方法解析顺序:即使使用Python编写的算法,将其转换为Python-Veloce兼容的代码也是一项艰巨的任务。
    • 获取属性 :实际的getattribute解析算法有点棘手,它仍然不支持数据描述符
    • 最后一点:some_callable(…)总是转换为“call(some_callable)”。因为译者根本不使用推理,所以每次你做一个调用时,你需要检查它是哪种类型的对象来调用它,它们的调用方式是它的本意。

    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至少可能是一种性能改进,因为有时我会在生成与块相关联的代码之前检查块的内容,例如:

    • var/global:为了能够var一些东西,我必须知道我需要什么,而不是var。不是生成一个块跟踪哪个变量是在给定的块中创建的,并将其插入到生成的函数块的顶部,我只是在实际访问子节点生成变量之前,在进入块时寻找相关的变量赋值关联代码。

    所以在翻译的每一个阶段,我并不真正访问每个节点一次。

    整个过程可以描述为:

    Python source code -> Python ast -> Python source code compatible with Veloce mode -> Python ast -> JavaScript source code
    

    Python内置代码是用Python代码(!)编写的,IIRC有一些与引导类型相关的限制,但是您可以访问所有可以在兼容模式下翻译Pythonium的内容。看一看 https://bitbucket.org/amirouche/pythonium/src/33898da731ee2d768ced392f1c369afd746c25d7/pythonium/compliant/builtins/?at=master

    阅读pythonium兼容的JS代码是可以理解的,但是源代码映射会有很大帮助。

    • 问问题!如果我事先知道PyPy后端是无用的,因为C/Javascript语义不匹配导致了开销。我可能在6个月前或者3年前就有了蟒蛇的想法。
    • 知道你想做什么,有个目标。对于这个项目,我有不同的目标:练习一点javascript,学习更多的Python,并且能够编写在浏览器中运行的Python代码(更多和更多)。
    • 失败就是经验
    • 一小步就是一小步
    • 从小处着手
    • 梦想远大
    • 进行演示

    只有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 .

    什么是完美

    我更感兴趣的是知道我可以实施什么样的模式 使代码更易于翻译(即:IoC、SOA?)的代码

    我认为没有一种模式不能从一种语言翻译成另一种语言,至少以一种不那么完美的方式。既然语言对语言的翻译是可能的,你最好先瞄准这一点。因为,我认为根据 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
  •   ptomato    15 年前

    Vala compiler ,将Vala(一种类似C的语言)翻译成C。