我正在学习编译器课程,程序的编译分为以下步骤:
- 词法分析
- 语法分析
- 语义分析
- 中间代码生成
- 代码优化
- 目标代码生成
如何查看每个步骤的输出?例如,我想在语法分析后查看解析树。
我正在Linux机器上使用GCC编译器编译程序。
我们可以通过在 GCC 中使用 -Wa 编译器选项来查看程序的汇编代码,类似地,是否有选项可以查看令牌、解析树和中间代码。
我正在学习编译器课程,程序的编译分为以下步骤:
如何查看每个步骤的输出?例如,我想在语法分析后查看解析树。
我正在Linux机器上使用GCC编译器编译程序。
我们可以通过在 GCC 中使用 -Wa 编译器选项来查看程序的汇编代码,类似地,是否有选项可以查看令牌、解析树和中间代码。
虽然您可以使用gcc中的-fdump-tree-all
和-fdump-rtl-all
选项,但我认为它们的输出对于编译器学生来说并不是非常有用。值得一提的是,我作为博士研究生的一部分开始从事gcc工作,已经完成了两门本科课程,并且我发现gcc
及其调试文件是不透明且难以跟踪的。
此外,gcc实际上并没有遵循编译器的教科书设计。实际上,没有人这样做,因为那样做并不奏效。我相当确定gcc并不产生解析树或抽象语法树。它建立了一个IR(称为gimple),在此基础上进行高级优化。
我建议尝试使用LLVM代替,因为它被认为是设计良好且易于跟踪的。另一个选择是从教科书下载代码,特别是Appel书籍,假设有可用的话。
如果我可以推荐自己的建议,那么另一个建议是使用phc。使用phc,您可以将解析树作为图像进行查看,并在编译器的每个单独传递之后查看AST和源代码。 这里是AST和解析树部分的比较。它们是使用phc轻松生成的。您可以查看编译器IR,CFG,SSA形式以及类型推断和别名分析的调试输出。您还可以打开和关闭优化和传递以查看它们产生的效果。
我认为这对您可能会有用。
你可以使用-E
查看预处理器输出。 -fdump-tree-*
会转储树形内部表示,例如-fdump-tree-all
。有各种-d
选项可用于转储RTL中间表示,例如-fdump-rtl-all
(请参阅手册以获取所获得的传递的单独转储);此外,-dD
会转储所有宏定义。
.optimized
命名的文件中。这一点并不明显,我花了约20分钟查看文档,并搜索gcc未生成此转储文件的情况,当偶然注意到新建的文件时(这并不容易,因为我在/tmp/
目录下进行测试,它相当杂乱)。 - Hi-Angel从clang
编译器的角度来看,您无法看到编译器生成的每个输出。这是因为与其他编译器相比,clang的工作方式不同。
词法分析
令牌可以通过以下方式发出:
clang test.c -Xclang -dump-tokens
clang test.c -Xclang -dump-raw-tokens
中间代码生成
可以通过以下方式发出字节码: clang test.c -S -emit-llvm
语义分析
在生成AST的同时进行语义分析。可以通过以下方式发出AST:
clang test.c -Xclang -ast-dump
clang test.c -Xclang -ast-view (this generates a graph for the textual AST)
代码优化
您可以通过打印应用于C代码的优化流水线来查询代码优化:
clang test.c -S -mllvm -print-after-all
目标代码生成
生成的代码(即汇编输出)可以通过以下方式查看:
clang test.c -S
奖励
您还可以查看clang为程序调用的完整流程。例如,发出对象文件的流程可以通过以下方式进行查看:
clang -ccc-print-phases test.c -c
0: input, "test.c", c
1: preprocessor, {0}, cpp-output
2: compiler, {1}, ir
3: backend, {2}, assembler
4: assembler, {3}, object
phc
似乎是一种独立的编译器,即它不是一个简化 GCC 字节码理解的应用程序。 - Hi-AngelW<X<Y>>Z;
是变量声明还是表达式。 - Qwertie