编译原理 (二)词法分析、语法分析、语义分析以及中间代码生成器的基本概念

简介: 编译原理 (二)词法分析、语法分析、语义分析以及中间代码生成器的基本概念

1.词法分析

词法分析的过程中,源代码程序被输入到了一个叫做扫描器的东西中,扫描器的任务就是进行词法分析。他应用了一种叫做有限状态机的算法把源代码分割成一个一个的记号,举例比如array[index] = (index + 4) * (2 + 3)这行代码,经过扫描就会变成如下的一个个记号:

记号 类型
array 标识符
[ 左方括号
index 标识符
] 右方括号
= 赋值
( 左圆括号
index 标识符
+ 加号
4 数字
) 左圆括号
* 乘号
( 左圆括号
2 数字
+ 加号
3 数字
) 右圆括号


以上的这些记号一般有以下几类:关键字、标识符、字面量(数字、字符串等)和特殊符号。

单词类型 种别 种别码
关键字 if、else、for…… 一词一码
标识符 变量名、数组名…… 多词一码
常量 整型、浮点型、字符…… 一型一码
运算符 算术(+ - * / %)、关系(> < =)、逻辑(& | ~) 一词一码
界限符 ; ( ) [ ] { } 一词一码


在识别这些标志的同时,扫描器也同时把标识符存放到了符号表,将数字、字符串常量存放到文字表,以备后续步骤使用。对于C语言的预处理,他的宏替换和文件包含等工作不交给编译器范围而是交给独立的预处理器处理。


2.语法分析

语法分析则由分析器去扫描扫描器产生的那些记号去进行语法分析,产生语法树,整个过程采用了上下文无关语法的分析手段,由语法分析树生成的树是以表达式为节点的树,如下所示:

这个数的左分支是array[index]右分支是(index + 4) * (2 + 3)左分支和右分支又可以再拆开,形成语法树

通过语法树我们可以看到很多运算符号的优先级和含义也被确定了下来。对于有多重含义的符号,比如*可以做乘法,也可以作为指针,语法分析阶段,要去确定他们的含义来进行区分,出现了不合法的表示方式,则会抛出语法错误。


3.语义分析

语义分析由语义分析器来完成,语法分析器仅完成了语法的对错,他并不去关心代码实现的含义,在C语言中两个指针相乘是没有意义的,但是在语法层面确是合法的。编译器能分析的语义是静态语义,即编译期可以确定的语义,相反,动态语义则是在运行的时候才确定的语义。


静态语义包括声明类型和类型的匹配、转换。比如当一个浮点数赋值给整型的时候,隐藏了一个过程,就是浮点型到整型转换的过程。但是将浮点数赋值给指针的时候,在语法层面可以,但是语义阶段,会发现,类型不匹配则会报错。

经过语义分析后,整个语法数表达式都被标志了类型,如下:

该表达式中基本所有的类型都是整型,并不需要做类型转换,有些需要做转换的会在语法树上插入转换节点


4.z中间语言生成

目前的编译器都会有很多优化,在源代码中就会有一些优化过程,比如以上的(2+6)就会在编译的时候进行优化,优化后就直接变成了一个数字5

其实直接在语法树上边做优化比较困难,所以源代码优化器往往把整个语法树转换成中间代码,跟目标机器和运行环境无关,他不包含数据的尺寸、变量地址和寄存器的名字。常见的中间代码有三地址码,P-代码等。比如x = y op z,该三地址码表示将变量y和z进行op操作后赋值给x,比如x = y + z;一下是常用的三地址表示方式

指令类型 指令形式
赋值操作 x = y op z 、 x = op y
复制指令 x = y
条件跳转 if x op y goto z
非条件跳转 goto z
参数传递 param z
过程调用 call p, n
过程返回 return x
数组引用 x = y[ i ]
数组赋值 y[ i ] = x
地址以及指针操作 x = &y 、x = *y 、*x = y

我们把上述的例子的语法树翻译成三地址码如下

t1 = 2 + 3
t2 = index + 4
t3 = t1 * t2
array[index] = t3

在三地址码基础上进行优化,会把2+3的结果计算出来,得到t1 = 5然后把t1换成5。这样三地址码就变成了如下

t2 = index + 4
t2 = t2 * 8
array[index] = t2

中间代码把编译器分成了前端和后端(此前后端非彼前后端),前端负责生成与机器无挂的中间代码,后端则是将中间代码变成目标代码。这样对于一些跨平台的编译器而言,可以针对不同平台使用同一个前端,然后对应不同机器开发不同后端。


参考资料《编译原理》、《程序员的自我修养(链接、装载与库)》

相关文章
|
自然语言处理 编译器
编译原理复习五:属性文法与三地址码的生成(附题目与答案 超详细)
编译原理复习五:属性文法与三地址码的生成(附题目与答案 超详细)
1061 0
|
自然语言处理 编译器 C语言
软考:区分词法分析、语法分析、语义分析
本文解释了编译过程中的词法分析、语法分析和语义分析三个阶段的区别,并提供了相关练习题,帮助读者理解各阶段在编译过程中的作用和重要性。
727 4
|
11月前
|
Linux 开发工具 git
【Git】Git 完全指南:从入门到精通
Git 是一种强大的版本控制工具,掌握了其基本命令和高级特性后,可以大大提高开发效率并方便团队协作。通过本篇文章,你已经学会了 Git 的核心命令及其使用方法,希望你能够灵活运用 Git 在实际项目中进行版本管理。
3298 4
|
中间件 Linux vr&ar
Centos7升级Glibc
Centos7升级Glibc
1715 6
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简
1934 1
DFA与NFA的区别,由正规表达式构造DFA,以及DFA的相关化简
|
存储 C语言 索引
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
本文全面介绍了Python的基础知识,包括Python的诞生背景、为什么学习Python、Python的应用场景、Python环境的安装、Python的基础语法、数据类型、控制流、函数以及数据容器的使用方法,旨在为Python零基础读者提供一篇全面掌握Python语法的博客。
3717 1
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
|
存储 关系型数据库 MySQL
深入解析MySQL数据存储机制:从表结构到物理存储
深入解析MySQL数据存储机制:从表结构到物理存储
1472 1
|
缓存 网络协议 网络架构
网络抓包分析【IP,ICMP,ARP】以及 IP数据报,MAC帧,ICMP报和ARP报的数据报格式
本文详细介绍了如何使用网络抓包工具Wireshark进行网络抓包分析,包括以太网v2 MAC帧、IP数据报、ICMP报文和ARP报文的格式,以及不同网络通信的过程。文章通过抓包分析展示了IP数据报、ICMP数据报和ARP数据报的具体信息,包括MAC地址、IP地址、ICMP类型和代码、以及ARP的硬件类型、协议类型、操作类型等。通过这些分析,可以更好地理解网络协议的工作机制和数据传输过程。
网络抓包分析【IP,ICMP,ARP】以及 IP数据报,MAC帧,ICMP报和ARP报的数据报格式
|
存储 弹性计算 前端开发
阿里云服务领域Agent智能体:从概念到落地的思考、设计与实践
本文讲述了作者团队在阿里云的服务领域Agent是如何设计与实践的,以及到目前为止的一些阶段性成果,作者做出了总结和整理。
|
数据可视化 uml
UML图讲解(关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系)
UML图讲解,关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系。
6165 0
UML图讲解(关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系)