可变目标C编译器学习笔记(一)

本文是可变目标C编译器的学习笔记,重点介绍了预处理阶段,如宏定义(明示常量、带参数宏、字符串化、黏合运算符、变参宏)、条件编译和预定义宏。讨论了lcc编译器的设计特点,强调其小而快,适用于教学和实践。
摘要由CSDN通过智能技术生成

可变目标C编译器学习笔记(一)

第一章 引论

要编写一个编译器,首先要理解一个编译器是什么,有什么作用。
编译器就是将高级语言翻译成低级语言的程序。

以下引用自百度百科:
一个现代编译器的主要工作流程:源代码 (source code) → 预处理器 (preprocessor) → 编译器 (compiler) → 目标代码 (object code) → 链接器 (Linker) → 可执行程序 (executables)。

编译器可以将源代码翻译成目标机器上的汇编代码或者目标代码。而可变目标编译器能够针对不同的机器(MIPS,X86,SPARC)生成代码。

本书主要介绍了lcc编译器,与gcc不同,lcc的代码量很少,易于学习,而且速度很快。

1.1 文本程序

代码片段:包括源代码和对其他代码片段的引用。
例:
<a fragment label 1>≡
sum = 0;
for(i = 0, i < 10, i++)<increment sum 1>

<increment sum 1> ≡
sum += x[i]
以上为两个代码段,而第一个代码段中引用了第二个代码段。这两段代码的功能是计算数组x中所有元素之和。

1.3 概述(因为理解不全面,部分可能有误)

一段代码的编译分为几个阶段。
第一个阶段是由C的预处理程序进行宏扩展、引入头文件、选择条件编译代码等工作。
第二个阶段,编译器开始工作,首先由词法分析器(lexical analyzer)扫描器(scanner)将输入的源程序分解成单词(token)
词法分析器输出单词和单词定义点位置,并处理#指令。
第三个阶段,根据C语言的语法规则对单词串进行分析(parse),同时分析 程序语义(semantic)正确性。经过分析后,源程序会生成抽象语法树(abstract syntax tree),树中每一个节点代表一个基本运算。
然后代码生成器将树转为有向无环图(dag)。
第四个阶段,lcc的与目标机器无关的前端将程序的表示结构传递给后端,由后端把这些结构翻译成汇编代码。

1.4 设计

对于lcc来说,并没有一个独立的设计阶段。lcc刚开始只是针对C语言的一个子集的编译器,所以其最初的设计目标非常有限,仅定位于针对一般的编译器实现、特别是代码生成的教学的需要。即使后来lcc演化成了适于实用的C编译器,这一设计目标仍然没有大的改变。
  lcc比大多数其他ANSI C编译器更小、更快。尽管有时在编译器设计时会忽视编译的速度,但快速仍是广为欣赏的特点,用户经常把速度作为他们使用lcc的原因之一。快速编译本身并不是设计的目标,它是追求简单、特别是注意编译器中严重影响速度的组成部分的实现的自然结果。lcc的词法分析和指令选择都特别快,对整个系统的速度贡献最大。
  lcc能够生成相当高效的目标代码,它以产生好的本地代码为设计目标,而其他优化编译器所具有的全局优化,不在lcc的设计目标之中。大多数现代编译器,特别是CPU供应商开发的编译器,必须采取尽可能的优化措施,以期在性能测试中突出他们的机器。这些编译器很复杂,一般需要数十人组成的小组进行开发。尽管这些高度优化的C编译器在启用优化选项时,产生的代码比lcc产生的代码更高效,但数百名使用lcc作为日常主要C编译器的开发者发现,对大多数应用来说,lcc产生的代码已经足够快了,同时,由于lcc的本身速速非常快,也帮助他们节约了许多时间。另外,系统开发者如果需要对lcc进行修改,则会发现lcc很容易理解。
  lcc的前端大约有9000行代码,每种与目标相关的代码生成器有700行代码,还有约1000行与目标无关的后端代码被所有的代码生成器共享。
  除个别例外,lcc的前端一般使用成熟的编译技术。lcc的词法分析器和递归下降分析器都是通过手工编写的(注:词法分析器另一个方法是通过LEX工具自动生成)。后端是lcc最令人感兴趣的模块,原因之一就是体现了它旨在提高可变目标能力的设计选择。第一,后端使用了代码生成器lburg,该产生器可以根据紧缩规范产生代码生成程序。第二,只要可能,一些明显依赖于目标机器的函数尽可能被移到前端实现。

1.5 公共声明

在此节开始之前,读者需要掌握C语言宏定义相关的知识。这个Blog写的很详细。

在《C Primer Plus》中也有关于宏定义的知识(大一用的谭浩强的书,而且没翻完,对于我来说宏定义了解甚少),下面用一定篇幅学习宏定义。

明示常量 #define

用法:

#include <stdio.h>
#define TWO 2/*分为三个部分 define为第一部分叫做预处理指令 第二部分是TWO叫做
宏,第三部分是 2 叫做替换体*/
#define OW "Zhangyi is so \
handsome."/*反斜杠把该定义延续到下一行*/

#define FOUR  TWO*TWO
#define PX printf("X is %d.\n", x)
#define FMT "X is %d.\n"

int main(void)
{
   
	int x = TWO;
	PX;
	
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值