我想知道为什么C ++是编写编译器的好选择。当然,C对此也有好处,因为许多编译器都是用C或C ++编写的,但是这次我对C ++更加感兴趣。有什么好的理由吗?我一直在互联网上寻找该信息,但找不到任何好的理由。
我想知道为什么C ++是编写编译器的好选择。当然,C对此也有好处,因为许多编译器都是用C或C ++编写的,但是这次我对C ++更加感兴趣。有什么好的理由吗?我一直在互联网上寻找该信息,但找不到任何好的理由。
Answers:
C ++有两个方面。它具有低级开发方面,这使其看起来像是用于执行低级操作(如代码生成)的自然语言。它还具有高级方面(C则没有),可以让您以逻辑,面向对象的方式构造复杂的应用程序(如编译器),同时仍保持性能。由于它同时具有低级和高级功能,因此对于需要低级功能或性能的大型应用程序是一个不错的选择。
我的经验与您在这里的前提不同。实际上,对于高级通用语言,使用与源语言(正在编译的语言)相同的语言编写编译器是一种非常普遍的做法。例如:
一个例外是为现有编译器框架(例如GCC,LLVM或Polyglot)编写的编译器前端,然后以该框架的语言编写,或者依赖于现有解析器生成器(例如Yacc)的编译器。由于GCC,LLVM和Yacc是通用的,用C和C ++编写的成熟工具,因此激励了编译器编写者使用它们,这可能导致C和C ++在编译器实现语言分发中占有很大份额。
javac
命令行),它将Java编译为Java字节码。它是用Java编写的-我本人已经对其进行了多次修改,您可以在线浏览其Java源代码。另一个是嵌入在Hotspot JVM中的即时编译器,它将Java 字节码编译为本地机器代码。像大多数JVM一样,它是用C ++编写的,但它不是Java编译器 -实际上,它对Java语言一无所知。
要编译什么到什么?编译器将源代码从一种语言(源语言)转换为另一种语言(目标语言),但这并没有说明目标语言的低级性。
您选择用来编写编译器的语言取决于上下文。例如,在一个将来自PHP的语言编译成本地PHP代码的项目中,我混合使用了PHP和C#来编写编译器,因为鉴于我的技能,这对我来说最有意义。另一个人会选择Python,Java和PHP或C ++以及一些JavaScript,或者其他任何选择。
C或C ++是受欢迎的选择,因为它支持编译器相关工具(请参阅Telastyn的答案),并且由于这两种语言都使您真正地本机化。但是选择另一种语言没有错。
请注意,为了变得更加怪异,您可以选择源语言来编写编译器本身。这就是CoffeeScript编译器和许多其他编译器的情况。它在IDE中也很流行:第一个Visual Studio之一是使用相同的Visual Studio构建的。
我倾向于在这里质疑基本前提。尽管C和C ++可以很好地编写编译器,但其他许多语言似乎也可以很好地完成任务。
不过,这取决于您正在编译的语言。对于小型,简单的语言,C和Pascal可以很好地工作。如果您要编译大而复杂的东西,那么编译器也会变得又大又复杂-在这种情况下,C ++用于组织和使用较大程序的额外功能显然很方便。不过,这并不是真正针对编译的,只是一般而言对大型程序有用的功能。
我认为也值得一提。初学者(似乎)认为编译器主要是在进行文本操作,因此他们认为Perl之类的东西将对编写编译器产生巨大的帮助。实际上,直到构建AST之后,大多数有趣的编译部分才真正开始。虽然我确定Perl可以很好地完成这项工作,但是它的文本处理功能也并没有真正赋予它巨大的优势(文本处理主要在lexer中,而C语言之类的lexer生成器无论如何都支持RE)。
编译器可以用任何现代语言来实现。但是,编译器最重要的要求之一就是要快。
C ++在这里有明显的优势。C ++中的优化并不便宜。但是,由于该语言的低级性质,与其他任何语言相比,手动优化C ++代码都是可能的(非汇编语言的Assembly除外)。
我怀疑使用它们的主要动机是Lex / Yacc / Bison输出(主要是C)。由于长期以来一直是标准,因此它很有动力。
并不是那些特别好的理由...
我对此事有经验。我已经用C和C ++编写了编译器。C和C ++之间的主要区别是C没有自动进行动态内存管理。C语言中的所有内存管理都必须明确完成。编写编译器需要处理字符串处理和数组管理。在C语言中,您被迫考虑声明的每个字符串和每个数组的大小,并在访问这些对象时检查索引(如果您希望代码安全稳定)。当然,在C中可以进行动态内存管理,但是没有什么是自动的。您必须使用malloc()和free()显式分配和释放内存,将动态对象的大小保留在单独的变量中,以确保您不会超出范围访问它们。
在C ++中,您可以具有相同的机制,但是它确实是开发时高效的,因为所有内存管理都可以封装在构造函数和析构函数中,而不必显式调用。因此,编译器正在为您分配和释放资源。如果创建自己的类,则动态对象的大小也可以封装,并且可以通过重载运算符[]检查索引的边界访问。这些抽象有助于使您的代码更整洁,更易于理解和调试,并且绝对可以加快开发速度。
如果使用C创建编译器,肯定会花费更多时间。C ++将使您在更少的时间内完成项目。C和C ++具有相同的性能,但是C ++具有C没有的许多优点。
该CompCert项目是未在C或C ++编写的研究C编译器,但更多的OCaml中和勒柯克。
观察一下C ++曾经被翻译成C(在Cfront中)。现在,您可以将GCC前端用于Gimple,然后将Gimple转储到某个数据库,然后将Gimple编写到汇编翻译器中。但是出于法律原因(GCC运行时库例外),要求此类编译器为开源。向您的律师询问详细信息,我不是律师。GCC的旧变体已经用C(+多种领域特定语言)编写,并且前端带有一些C ++变体。OpenWatcom可能是用C编写的C ++编译器(我留给您检查)。
Compcert的源可免费用于学术和研究目的。如果要在工业上(合法地)使用它,则需要获得Absint的许可。
如果我在2020年受命从头开始编写C(或C ++)编译器(在Linux上运行,也许是一些交叉编译器),那么我可能不会用C ++编写它。我会考虑使用Ocaml,Go或Rust编写它。如果允许的话,我可以基于Frama-C。如果需要用C或C ++编写代码,我首先会为其编写一个垃圾收集器库,可能是一些持久层- 对于整个程序优化非常有用-然后我将考虑使用元编程方法(生成大多数C或C ++代码)。我的临时工具(可能是Bismon或RefPerSys)编译器 如果允许的话)。
您可以找到一些用Common Lisp或Python(例如ShivyC或nqcc)编码的(或多或少开源)C编译器。还可以查看ZetaC。
请注意,GCC的最新版本在技术上不是用纯C ++编码的,它们是GCC涉及的十几种特定于领域的语言(其中一些是图灵完备的)。另请参阅我的旧版GCC MELT项目。
如果在将来的GCC版本中将某些Python或Guile解释器嵌入其中(例如,作为GCC通道管理器的替代品),我不会感到惊讶。
另请参阅MILEPOST GCC项目。