通常编译器会从它们支持的语言转换为汇编语言。或者至多是类似汇编的语言(字节码),如GCC的GIMPLE / GENERIC或Python / Java / .NET字节码。
编译器转换为更简单的语言会不会更简单,这种语言已经实现了语法的一个重要子集?
例如,与C 100%兼容的Objective-C编译器只能为它扩展到C的语法添加语义,将其转换为C.我可以看到这样做的许多优点;可以使用这个Objective-C编译器将其代码转换为C,以便使用不支持C ++的不同编译器编译生成的C代码(但是可以更好地编译,或者编译更快,或者能够编译更多架构)。或者可以在只允许使用C的项目中使用生成的C代码。
我想/希望如果事情像这样工作,那么为当前语言编写扩展会更容易(例如:添加C ++关键字以简化常见模式的实现,或者,仍然在C ++中,通过将内联成员函数移动到头文件的末尾来删除在使用前声明规则)
会有什么样的处罚?生成的代码很难被人类理解?编译器无法像现在这样进行优化?还有什么?
答案 0 :(得分:6)
通过使用Intermediate languages,这实际上被很多语言使用。最典型的例子是Pascal,它有Pascal-P系统:Pascal被编译成一种假设的汇编语言。移植pascal只意味着为这种汇编语言编写一个编译器:一个比移植整个pascal编译器简单得多的任务。编写完这个编译器之后,你只需要编译用这个编写的(机器无关的)pascal编译器。
Bootstrapping在编程语言设计中也经常使用。许多语言的编译器都用同一种语言编写(Haskell在这里可以想到)。通过这样做,为该语言编写新功能只是意味着将该想法转换为当前语言,将其放入编译器,然后重新编译。
我不认为这个方法的问题实际上是生成代码的可读性(我不会通过编译器个人生成的汇编字节代码进行筛选),而是优化之一。高级编程语言中的许多想法(弱写入)都很难自动转换为C等低级系统语言.GCC倾向于在代码生成之前进行优化。
但是大多数情况下,编译器会转换为更简单的语言,除了最基本的系统语言。
答案 1 :(得分:2)
顺便提一下,作为一个反例,Tcl是一种语言,已知非常非常难(如果不是完全不可能)转换为C.在过去的20年中,有几个项目试过这个,甚至商业产品的一个承诺,但没有实现。
部分原因是因为Tcl是一种非常动态的语言(因为任何具有eval函数的语言都是如此)。在某种程度上,这是因为知道某些东西是代码还是数据的唯一方法就是运行程序。
答案 2 :(得分:1)
由于Objective-C是C的严格超集并且C ++包含非常大量的C,很像C,要解析你实际上已经需要能够解析C.在这种情况下,输出到机器代码和输出到更多的C代码在处理成本上没有实质性的差别,用户的主要成本是编译现在需要的时间与最初的时间一样长,再加上第二个编译器所花费的时间。
任何尝试复制和粘贴看起来像C的东西并将其余部分翻译出来都会出现问题。首先,C ++不是C的严格超集,因此看起来像C的东西不一定完全相同(特别是与C99相比)。即使他们这样做,假设用户在他们的C语言中出错,编译器也不倾向于以机器可读的格式提供错误信息,因此Objective-C到C层很难给出收到例如后,用户有意义的错误“第99行的错误”。
也就是说,许多编译器套件,比如GCC,甚至更像即将推出的Clang + LLVM,使用中间形式将知道某个体系结构细节的位与知道特定语言细节的位分离。 。但是,它往往更像是一种数据结构,而不是故意容易表达为书面语言的东西。
所以:出于纯粹的实际原因,编译器不能像这样工作。
答案 3 :(得分:1)
Haskell实际上是通过这种方式编译的:GHC编译器首先将源代码转换为中间函数语言(比Haskell self不那么丰富),执行优化然后将整个事务降低为C代码,然后由GCC编译。这个解决方案存在问题,并且项目开始取代这个后端。
http://blog.llvm.org/2010/05/glasgow-haskell-compiler-and-llvm.html
答案 4 :(得分:0)
有一个完全基于这个想法的编译器构造堆栈。任何新语言都是作为较低级别语言或已在此堆栈中定义的语言组合的简单翻译实现的。
http://www.meta-alternative.net/mbase.html
但是,为了能够这样做,您需要在添加到层次结构的每种小语言中至少使用一些元编程功能。这个要求在语言语义上增加了一些严重的限制。