使用C#实现编译器的最有趣和最有前途的方法是什么?

4
我正在进行为期6个月的毕业项目的开端。该项目的目标是实现一种脚本语言的.Net编译器。我在课程中学习了编译器构造,并且知道通常如何实现编译器的基本步骤,但我们使用Bison和GCC作为后端的简单编译器,因此我对在.Net平台上实现编译器不太了解。
在这个主题上进行了一些研究后,我找到了以下代码生成的替代方案(我不是在谈论编译器的其他重要部分,比如解析器——这超出了范围):
  1. 使用Reflection.Emit进行直接代码生成。
  2. 使用Common Compiler Interface对Reflection.Emit进行抽象,以实现部分代码生成的自动化。
  3. 使用CodeDOM在运行时编译C#和VB。
  4. 出现了一种新兴的C#“编译器作为服务”的形式,名为Roslyn,现在可以作为CTP使用。
  5. DLR支持动态代码生成,并具有通过表达式树等方式进行运行时代码生成的一些接口。
  6. Mono附带了Mono.Cecil库,似乎也具有一些代码生成功能。
我的项目的主要目标是深入了解.Net的内部结构,学习编译器构造并获得良好的成绩。次要目标是设计一个编译器实现,可以在后来以宽松的开源许可证向社区开放。
那么,在这里最有趣、教育性强、娱乐性高和前景光明的方法是什么?如果我有更多时间,我肯定会尝试所有方法,但我需要在6个月内提交我的工作,以获得积极的成绩...
提前感谢您, 亚历山大。

请注意,Roslyn只是围绕着你的123的一个厚包装器。 - SLaks
@SLaks,我认为Roslyn实际上并没有使用CodeDOM(#3)。 - svick
我不太确定那个。我怀疑你是对的。 - SLaks
你喜欢哪种类型的编程语言?动态的还是静态的? - Dykam
@HansPassant:我不是在问解析器,而是关于更好的执行代码生成的方法。当然编写解析器也非常具有挑战性,但这超出了本问题的范围。 - Alexander Galkin
显示剩余2条评论
3个回答

5
如果您想选择更简单的方式,并且您的语言可以合理地转换为C#,我建议您生成C#代码(或类似代码),并进行编译。Roslyn可能是最好的选择。显然,CCI也可以使用CCI Code进行编译,但我从未使用过。我不建议使用CodeDOM,因为它不支持静态类或扩展方法等功能
如果您想要更多的控制权或者想要降低级别,您可以直接使用Reflection.Emit来生成CIL。但这将需要(更)多的工作量,特别是如果您不熟悉CIL。我认为Cecil可以以同样的方式使用,但它是用于其他目的的,并且我不认为它比Reflection.Emit提供任何优势。
DLR是针对动态语言而设计的,正如其完整名称所示。它使用的Expression可用于代码生成,但我认为它们最适合在运行时生成相对简单的方法。当然,如果您的语言是动态的,DLR本身非常有用。

2

Boo 是一种针对CLI的语言/编译器。它似乎是开源的,因此您可以研究他们如何实现它。


非常有趣的建议!我读过《用Boo编写DSL》这本书,甚至在我的一个工作项目中使用了Boo(作为脚本引擎)-- 但是我从来没有从编译器构建的角度来看待它。谢谢你! - Alexander Galkin

2

在我写编译器时,我会写汇编语言(即汇编语言源代码),然后通过系统的汇编器运行。这样我可以轻松地查看我正在生成的内容。相对于解码十六进制操作码而言,读取 mov ax, bx (x86 汇编)要容易得多。

如果在最终产品中不允许使用汇编器,那么我将使用汇编输出来开发编译器,一旦我把所有东西都弄好了,我就会产生一个二进制输出路径。美妙的是,我只需更改实际字节输出(操作码和二进制值而不是文本)。

我建议你在项目中采用类似的方法。最初开发输出 MSIL 的工具,然后使用 ILASM 进行汇编。这样,您可以通过阅读生成的代码轻松验证代码生成器的输出。一旦您确信您的代码生成器有效工作,再添加一个输出选项,该选项将使用Reflection.Emit 或公共编译器基础结构。


有趣的建议,谢谢!MSIL输出对于调试和编译器优化非常好。无论如何,我首先考虑编写一个转换器到C#,然后实现自己的编译器,因为编译器优化并不容易和透明。 - Alexander Galkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接