我可以在代码中施加什么样的模式以便更容易翻译成另一种编程语言?

98 投票
6 回答
24039 浏览
提问于 2025-04-16 02:37

我正在着手做一个副项目,目标是把一种编程语言的代码翻译成另一种。最开始我会从PHP和Python入手(从Python翻译到PHP应该比较简单),但理想情况下,我希望能相对容易地添加其他语言。我的计划是:

  • 这个项目主要是针对网页开发的。原始代码和目标代码会基于一些框架(我也需要自己编写这些框架)。这些框架会采用MVC设计模式,并遵循严格的编码规范。这样应该能让翻译过程简单一些。

  • 我还在考虑使用IOC和依赖注入,因为它们可能会让翻译过程更简单,出错的可能性也会减少。

  • 我会利用Python的解析模块,这个模块可以让我操作抽象语法树(AST)。听说在PHP中最接近的功能是token_get_all(),这算是一个开始。

  • 接下来,我可以构建AST、符号表和控制流。

然后我相信我可以开始输出代码。我不需要完美的翻译。我仍然需要检查生成的代码并修复问题。理想情况下,翻译器应该能标记出有问题的翻译。

在你问“这到底有什么意义?”之前,答案是……这将是一个有趣的学习经历。如果你有任何建议,能让我觉得这个项目不那么令人畏惧,请告诉我。


编辑:

我更想知道我可以在代码中强制执行哪些模式,以便让翻译变得更容易(比如:IoC、SOA?),而不是具体怎么进行翻译。

6 个回答

4

写一个翻译器并不是不可能,尤其是考虑到Joel的实习生在一个夏天就做到了。

如果你只想做一种语言,那很简单。如果想做多种语言,就稍微复杂一点,但也不是太难。最难的部分是,虽然任何图灵完备的语言都能做其他图灵完备语言能做的事情,但内置的数据类型会让语言的表现大相径庭。

举个例子:

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

要复制这些功能,得写很多C++代码(好吧,其实用一些循环结构可以写得比较简短,但还是很多)。

这有点偏题了。

你有没有根据语言的语法写过一个分词器/解析器?如果没有,你可能需要学习一下,因为这是这个项目的主要部分。我建议你先想出一个基本的图灵完备的语法——可以参考Python的字节码。然后你需要创建一个词法分析器/解析器,它能根据语言的语法(也许使用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行做类似的事情,我就能告诉你这个语言和Python一样强大。

14

我的回答将专注于如何解析Python代码,以便将其翻译成其他语言,而不是像Ira在他的回答中提到的那些更高层次的内容。

简单来说:不要使用解析器模块,有更简单的方法。

从Python 2.6开始就有的ast模块更适合你的需求,因为它提供了一个现成的抽象语法树(AST)供你使用。我去年写过一篇关于这个的文章,简单来说,使用astparse方法可以将Python源代码解析成AST。而parser模块会给你一个解析树,而不是AST。要注意这两者的区别

现在,由于Python的AST非常详细,给定一个AST,前端的工作并不是特别难。我想你可以很快为某些功能的部分准备一个简单的原型。然而,想要得到一个完整的解决方案会花更多时间,主要是因为不同语言的语义(意思)不同。语言的一个简单子集(比如函数、基本类型等)可以很容易地翻译,但一旦进入更复杂的部分,你就需要复杂的工具来在一种语言中模拟另一种语言的核心功能。例如,Python的生成器和列表推导在PHP中是不存在的(据我所知,关于PHP的知识确实有限)。

最后给你一个小建议,考虑一下Python开发者创建的2to3工具,它可以将Python 2代码转换为Python 3代码。在前端方面,它包含了你需要的大部分元素来将Python翻译成其他语言。不过,由于Python 2和3的核心是相似的,所以在这里不需要复杂的模拟工具。

130

自1995年以来,我一直在开发一些工具(DMS软件重构工具包),用于一般程序的处理(语言翻译只是其中一种特殊情况),这背后有一支强大的计算机科学家团队支持。DMS提供了通用的解析、抽象语法树(AST)构建、符号表、控制和数据流分析、翻译规则的应用、带注释的源代码再生等功能,所有这些都是通过明确的计算机语言定义来参数化的。

要做好这些工作,所需的技术手段非常庞大(尤其是如果你想以通用的方式处理多种语言),而且你还需要可靠的解析器来处理那些定义不可靠的语言(PHP就是一个完美的例子)。

你考虑构建一个语言到语言的翻译器或者尝试一下并没有错,但我想你会发现,处理真实语言的工作比你想象的要复杂得多。我们在DMS上投入了大约100个人年的时间,每种“可靠”的语言定义(包括我们为PHP艰难构建的那个)又需要6到12个月的时间,对于像C++这样棘手的语言,所需时间更长。这将是一次“非常艰难的学习经历”;对我们来说确实如此。(你可能会发现上面网站的技术论文部分对你启动学习很有帮助。)

人们常常试图通过从他们熟悉的某种技术入手,来构建某种通用的工具,这种技术能完成部分工作。(Python的AST就是一个很好的例子。)好消息是,这部分工作已经完成。坏消息是,这种工具内置了无数假设,而大多数假设你在尝试让它做其他事情时才会发现。到那时你会发现,这个工具是为原本的功能而设计的,真的会非常抵制你让它做其他事情的尝试。(我怀疑让Python的AST来模拟PHP会非常有趣。)

我最初开始构建DMS的原因是为了建立一些假设极少的基础。它确实有一些让我们头疼的假设。到目前为止,没有出现“黑洞”。(在过去15年里,我工作的最难部分就是尽量防止这些假设的出现。)

很多人也犯了一个错误,认为只要能解析(也许还能得到AST),就离完成复杂的工作不远了。一个艰难的教训是,你需要符号表和流分析才能进行良好的程序分析或转换。AST是必要的,但还不够。这就是为什么Aho和Ullman的编译器书籍不会在第二章就结束。(提问者在计划构建超出AST的额外工具这一点上是对的。)想了解更多这个话题,可以查看解析后的生活

关于“我不需要完美的翻译”的说法是个问题。弱翻译器的做法是转换代码中“简单”的80%,把困难的20%留给手动处理。如果你打算转换的应用程序比较小,并且只打算一次性做好,那么那20%是可以接受的。如果你想转换多个应用程序(甚至是同一个应用程序随着时间的推移进行小改动),那就不太好。如果你尝试转换10万行的源代码,那么20%就是2万行原始代码,这些代码在你已经不理解的另外8万行翻译程序的上下文中是很难翻译、理解和修改的。这需要付出巨大的努力。在百万行级别,这在实际操作中几乎是不可能的。(令人惊讶的是,有些人不信任自动化工具,坚决坚持手动翻译百万行的系统;这甚至更“困难”,而且他们通常会痛苦地发现,耗时长、成本高,往往还会失败。)

要想翻译大规模系统,你必须追求高达90%以上的转换率,否则很可能无法完成翻译的手动部分。

另一个关键考虑是要翻译的代码的大小。即使有好的工具,构建一个有效、稳健的翻译器也需要大量的精力。虽然构建一个翻译器看起来很酷,但对于小型代码库(例如,根据我们的经验,最多约10万行源代码),经济上并不划算。没有人喜欢这个答案,但如果你真的只需要翻译1万行的代码,可能还是直接咬牙切齿去做比较好。是的,这确实很痛苦。

我认为我们的工具非常好(但我可能有点偏见)。即便如此,构建一个好的翻译器仍然非常困难;我们大约需要1.5到2个人年的时间,而我们知道如何使用我们的工具。不同之处在于,使用这么多技术手段,我们成功的几率远高于失败的几率。

撰写回答