文章

Nim是转译器吗?

这个问题在 IRC 频道、与人交谈时,以及几乎每次Nim在Hackernews或更大的编程子论坛上发表文章时,都会在评论区反复出现。这个问题也被回答过很多次,既有简短有效的 “不”,也有更长的回答。本文将详细介绍为什么答案是 “否”,希望下次再有人问这个问题时能作为参考。

什么是编译器?

问“Nim 是转译器吗?”这个问题的人通常是指“相对于编译器而言”,因此要理解为什么答案是 “否”,我们需要了解编译器和转译器之间的区别。虽然这两个词有时可以互换使用,但它们的含义之间存在着微妙而重要的区别。但在讨论这个问题之前,究竟什么是编译器?编译器的存在时间几乎和计算机的使用时间一样长。上世纪50年代初,随着计算机的功能越来越强大,第一批编译器开始出现。编译器的工作是将用抽象语言编写的程序转换成更具体的东西。许多编译器会将你选择的语言直接编译成二进制代码(如 GCC),或编译成特定的虚拟机字节码格式(如 Java 编译器)。还有一些编译器会使用抽象程度较高的语言,然后将其编译成另一种语言中更具体的实现。TypeScript就是这样一个例子,它将代码编译成JavaScript,在输出有效的JavaScript代码之前运行所有静态类型检查等。

但我以为转译器只是在语言之间进行转换?

这似乎是导致人们提出本文标题问题的误解。虽然转译器确实是将一种语言转换为另一种语言,但两者的区别在于抽象层次。通过将C语言编译为汇编语言,你基本上是在使用C语言中的信息来决定生成什么样的汇编代码,并在此过程中丢弃这些信息。另一方面,转译器是一种在两种语言之间进行转换的工具,同时保持相同的抽象层次。因此,理论上完美的转译是一个双向过程,你可以在两种语言之间来回切换。然而,由于在两种不同语言之间进行转译需要结构上的变化和假设,情况通常并非如此。转译器的例子包括:JSweet将Java转换为TypeScript的带代码,f2c将Fortran 77转译为C代码,或者J2ObjC将 Java转换为Objective-C,甚至包括随Nim提供并将C转译为Nim的工具c2nim。反编译器通常用于将一种语言的代码用于抽象程度相同或更高的语言。即使是这个列表中的术语也有点宽泛,例如,f2c是将Fortran编译为机器代码的链条的一部分,因此是将Fortran的功能翻译为C语言。

那么,是什么让Nim不是一个转译器呢?

Nim编译器使用Nim代码,并输出C、C++、Objective-C或JavaScript代码。这听起来有点像转译器。尤其是当它编译为类型化语言时。但关键还是在于抽象层次。Nim不仅拥有比C等语言严格得多的类型系统,而且还支持同类最佳的元编程。这意味着 Nim编译器不仅能将Nim代码转换为C代码,还能让程序本身用Nim代码生成Nim代码。这可以通过模板和宏来实现,这也是 Nim如此灵活的重要原因。事实上,你可以在Nim中编写一个转译器,读取不同语言的代码文件,并在编译时将其转换为Nim代码。因此,Nim并不仅仅是一个转译器,它输出的代码并不能转换回创建它的Nim,而且抽象程度也下降了不少。事实上,Nim输出的C代码甚至都不是为了让人类阅读或理解,而是为了尽可能快地生成,而且Nim会使用一些巧妙的技巧,让C编译器输出更高效的机器代码。这些功能让Nim在编译器领域中如鱼得水。

那么,就没有什么是真正的转译器了吗?

上述定义相当严格,很多人看完后都会问自己这个问题。而这一切都取决于你希望自己的定义有多严格。不同的语法是一种抽象吗?Java和Objective-C是否足够相似,以至于不会跨越抽象的界限?现实情况是,所有语言都有一些差异,毕竟有什么理由去创造一种语言的完全拷贝呢?但一般来说,这个术语最常用于独立的工具,这些工具将一种语言中已经完成的项目转换成另一种语言。有时,这些工具可能无法100%准确地完成转换,甚至在无法准确翻译的部分直接失败。这些工具通常用于将一种语言一次性转换成另一种语言,或者仅仅是为了能用另一种语言使用某个库。不过,该术语也有更宽泛的用法,例如用于将下一代JavaScript转换为浏览器兼容JavaScript的Babel(Babel 本身也称自己为编译器),甚至用于将语法转换为 JavaScript的CoffeeScript(也称自己为“编译为JavaScript”)。正如用户“mst”在IRC上讨论这个问题时所说的:

转译器,也是某种意义上的编译器

总之,“转译者”这个词最近被用滥了。虽然比我在这里使用的定义更宽松的定义当然也可以适用,但要把Nim归类为转译器,你就需要把定义放宽到几乎荒谬的地步。Nim使用C语言的方式与Rust使用 LLVM 的方式大致相同,都是为了优化编译目标,并在许多不同的目标上运行。毕竟,站在巨人的肩膀上是一种无需攀爬就能到达远方的好方法。

本文由作者按照 CC BY 4.0 进行授权