编译原理:绪论 —— 词法分析
词法分析 (Scanning)
词法分析是编译的第一个阶段。词法分析器的主要任务是从左向右逐行扫描 (Scanning) 源程序的字符,识别出各个单词,确定单词的类型。将识别出的单词转换成统一的机内表示——词法单元 (token) 形式。
token 是一个二元组,其中第一个分量种别码用来表示单词的种别,就比如人说的自然语言中都有词性,程序设计语言也有这些东西,他们大体可分为五类:
单词类型 | 种别 | 种别码 | |
---|---|---|---|
1 | 关键字 | program、if、else、then、… | 一词一码 |
2 | 标识符 | 变量名、数组名、记录名、过程名、… | 多词一码 |
3 | 常量 | 整型、浮点型、字符型、布尔型、… | 一型一码 |
4 | 运算符 | 算术 (+ - * / ++ —) 关系 ( > < == != >= <= ) 逻辑 (& | ~ ) |
5 | 界限符 | ; ( ) = { } … | 一词一码 |
在 1 中,因为我们每个关键字都是确定的,所以我们为每一个关键字分配一个种别码,也就是一词一码。
2 是标识符,他是程序员在编程中为对象等起的名字,由于标识符是一个开放的集合,我们在事先并不能确认到底有那些标识符,因此我们将所有的标识符都作为一个单词并分配同一个种别码,也就是多词一码,为了区分每个标识符,我们使用 token 的第二个分量属性值来储存不同标识符具体的字面值
3 是常量,常量与标识符类似,也是一个开放型集合,但是不同类型的常量他们的构成类型是不同的,因此我们可以给每个不同类型的常量分配一个种别码,也就是也就是一型一码,为了区分不同的常量,我们也是使用 token 的第二个分量来存放每个常量具体的值
4 和 5 与 1 类似,他们都是可以事先可以确定的,所以我们可以为每一个运算符和界限符分配一个种别码,也就是一词一码,当然我们也可以为每一个运算符分配一个种别码,为了区分他们具体的区别,同样我们也要使用 token 的第二个分量
Example
根据以上的分配原则,我们可以看一个例子
对以上代码进行分析,我们可以得到这样的一个 token 序列
Code | Token | |
---|---|---|
1 | while | WHILE,- |
2 | ( | SLP,- |
3 | value | IDN,value |
4 | != | NE,- |
5 | 100 | CONST,100 |
6 | ) | SPR,- |
7 | { | LP,- |
8 | num | IDN,num |
9 | ++ | INC,- |
10 | ; | SEMI,- |
11 | } | RP,- |
种别码本身应该是一个整数,在这里为了直观起见,我们采取了宏定义的形式。
我们先来看 1 ,while
是一个关键字,因此我们采取一词一码,我们可以直接将他区分开,因此他的第二个分量是空的
与 1 同样的道理 (
、!=
、)
、{
、++
、}
、;
我们都可以直接将他们区分,因此他们的属性值都是空的
在 3 和 8 中,value
和 num
都是标识符,因此他们的种别码都是 IDN (IDentifier)
,他们的第二个分量用来存放他们的字面值。
5 100
是一个常量,那么属性值就是 100 本身。
THE END
graph TD Start-- 字符流 -->词法分析器 词法分析器-- 词法字节流 -->语法分析器 语法分析器-- 语法树 -->语义分析器 语义分析器-- 语法树 -->中间代码生成器 中间代码生成器-- 中间表示形式 -->机器无关代码优化器 机器无关代码优化器-- 中间表示形式 -->目标代码生成器 目标代码生成器-- 目标机器语言 -->机器相关代码优化器 机器相关代码优化器-- 目标机器语言 -->Fin