在Haskell实现LLVM Micro C编译器

2021-06-05 00:56:47

在本系列中,我们将探讨如何在Haskell中为LLVM的小型C子集编写编译器。我们的语言Micro C,基本上是真实C的小子集。我们有基本的数字类型,真正的BOOL类型,指针和结构。在系列末尾,我们' LL有一个漂亮的可执行文件,MCC(Micro C编译器),它需要一个.mc源文件并生成可执行文件。

Kaleidescope教程的斯蒂芬Diehl&#39的翻译提供了使用Haskell和LLVM构建简单语言的出色介绍。但是,它使用的是LLVM的旧版本而不是目前可用的。特别是,在将Irbuilder模块添加到Haskell绑定和所需用户时写入很多管道本身,它写得在图书馆处理了很多管道。此外,虽然Kaleidescope是一个用于编译器建设的精细教学语言,但我们的版本,虽然它是仍然是肉类,但允许我们深入了解LLVM功能。此外,基本上每个人都知道C 1,并且能够将我们的编译器和#39; S输出进行比较到Clang' s是一个很好的调试资源。

本教程假设熟悉Haskell。要学习语言,请参阅此Superb StackOverflow答案中提到的资源。供参考,在这个项目中使用的Haskell在答案中占据了早期中级类别的答案,因为有很多Monad变形金刚,但没有花哨的加剧,衣服,递归方案或任何其他GHC的延伸必须提供。虽然所有这些高级语言特征实际上都可以在编写编译器中非常有用,但我将他们留出了MCC,以便尝试更初学者友好。

Compiler的完整Haskell源在https://github.com/jmorag/mcc.git上生存。获取LLVM Toolchain设置是相当涉及的,所以代替为您提供构建指令,我的推荐就是使用NIX。在repo的根目录中,有一个shell.nix文件,您可以用来删除包含必要的Haskell库,Cabal和Clang的shell。如果运行nix-shell --pure --run' Cabal New-Clean; Cabal New-Test'顺利运行​​,然后应该正确设置所有内容。如果没有,请打开一个问题。

Haskell Tooling经常在助焊剂中。当我开始编写Micro C时,我使用Vim和Ale,但是通过堆栈切换到Emacs和Into Onlo。截至2020年4月,我与丁迪更换了互联网,并转回普通的Cabal,因为它与NIX更好地播放。我一直是看待GHCIDE,但Dante对我来说足够好,而且我没有找到打开的时间或动机&#39。在这些工具Don' T工作或花费太多的情况下,GHCID是一个伟大的回力。

遵循这篇优秀的博客文章,由Alexis King,我们在包中指定了我们的项目信息.YAML 2.前几行仅指定项目名称和作者

我们还将增加GHC' S警告水平以捕获更多的潜在问题。其中一些可能是令人讨厌的,但他们解决了比他们的更多头痛。

依赖性: - 基础> = 4.7&& < 5 - MTL - 阵列 - 容器 - 文本 - 字符串转换 - 目录 - 进程 - UNIX - FilePath - Bytestring - PrettyPrinter - 漂亮简单 - LLVM-HS-Pure≫ = 9&&&& < 10 - llvm-hs-pretty> = 0.9&& < 1 - Megaparsec - Parser-Combinators库:source-dirs:src可执行文件:main:main.hs source-dirs:应用程序依赖项: - OptParse应用 - MCC测试:TestAll:Main:TestAll.HS源码:测试依赖性: - 美味 - 鲜美 - 金色 - 鲜美猎 - MCC

过载机是处理Haskell' S臭张弦问题和Lambdacase的必要罪恶是一种微小的句法延伸,让我们逃脱,弥补了更少的变量名称,从而解决了计算机科学的艰难问题。

编译器' s作业是拍摄一个或多个源文件,将它们解析为抽象语法树(AST),检查它们是否进行语义错误,如果它们没有,则将其降低到中间表示(IR),优化所述IR,并为目标CPU生成可执行文件。

不同的语言以不同的方式对待这些步骤。 Lisp' s语法如此紧密地仔细地,解析几乎是一个no-op,而c有infix运算符和块语句,使从一系列字节序列变换到AST非活动。许多动态语言在运行时执行几乎没有语义分析,而在频谱的另一边,依赖性类型的语言执行如此复杂的分析,以便他们可以证明他们的程序将终止。我们的C方言落在中间的某个地方;我们将在编译时间拒绝程序,该程序将浮点浮到int类型变量,但我们将不努力执行任何类型的推断或终止检查。我们也不关心目标特定代码生成,将此留给LLVM。基本架构将是如下:

现在我们'我们奠定了预先的,我们实际上可以在第1部分开始编码!

1,如果你不愿意使用LLVM,你应该真的真的学习它,因为LLVM首先设计为C和C ++的中间代表

2最近的本机Cabal格式得到了普通斯坦斯的支持,消除了大部分需要使用HP​​ACK的需求。此外,FPComplete现在建议提交生成的Cabal文件,因此在未来,它可能是一个好主意用手编写MCC.Cabal。