从零写一个编译器(二):语法分析之前置知识
项目的完整代码在 C2j-Compiler
前言
在之前完成了词法分析之后,得到了Token流,那么接下来就是实现语法分析器来输入Token流得到抽象语法树 (Abstract Syntax Tree,AST)。但是在完成这个语法分析器不像词法分析器,直接手撸就好了,还是需要一些前置的知识。
这些前置知识在之前的博文都有提起过
之前的博文目录
项目的完整代码在 C2j-Compiler
什么是语法分析?
如果我们把词法分析看成是组合单词,输出单词流,那么语法分析就可以看作是检查这些单词是不是符合语法的过程。在词法分析的时候用正则或者手工比对来验证单词,语法分析则是用上下文无关文法 (context-free grammar,CFG)。
若一个形式文法 G = (N, Σ, P, S) 的产生式规则都取如下的形式:V -> w,则谓之。其中 V∈N ,w∈(N∪Σ) 。上下文无关文法取名为“上下文无关”的原因就是因为字符 V 总可以被字符串 w 自由替换,而无需考虑字符 V 出现的上下文。一个形式语言是上下文无关的,如果它是由上下文无关文法生成的*
BNF范式
巴科斯范式(英语:Backus Normal Form,BNF)是一种用于表示上下文无关文法的语言。
看一个例子:
S –> AB
A –> aA | ε
B –> b | bB
其中S A B叫作非终结符,代表可以通过推导产生新的符号,之前在Token类里定义的也有这些非终结符;a b ε叫作终结符,表示其无法再通过推导产生新的符号了,ε则表示空;
上面的每一行就是一个产生式规则,也叫推导式,代表了一种非终结符的转移方式;
S就是开始符号。
只有终结符的符号串称为句子 (sentence)。
比如通过这三个产生式,就可以断定bbb符合语法规则。
语法分析的几种方法
和之前讲的一样,主要分为自顶向上和自底向下两种
之前在学习的时候稍微记录了一下这几种方法,在这里就不说了
递归下降和LL(1)语法分析
自底向上语法分析
在这里稍微的再说一下这次语法分析使用的方法,LALR(1),它也属于自底向上的分析算法。
自底向上的语法分析
一个自底向上的语法分析过程对应为一个输入串构造语法分析书的过程,它从叶子节点开始,通过shift和reduce操作逐渐向上到达根节点
自底向上的语法分析需要一个堆栈来存放解析的符号,例如对于如下语法:
0. statement -> expr
1. expr -> expr + factor
2. | factor
3. factor -> ( expr )
4. | NUM
来解析1+2
stack | input | |
---|---|---|
null | 1 + 2 | |
NUM | + 2 | 开始读入一个字符,并把对应的token放入解析堆栈,称为shift操作 |
factor | + 2 | 根据语法推导式,factor -> NUM,将NUM出栈,factor入栈,这个操作称为reduce |
expr | + 2 | 这里继续做reduce操作,但是由于语法推导式有两个产生式,所以需要向前看一个符合才能判断是进行shift还是reduce,也就是语法解析的LA |
expr + | 2 | shift操作 |
expr + NUM | null | shift操作 |
expr + factor | null | 根据fator的产生式进行reduce |
expr | null | reduce操作 |
statement | null | reduce操作 |
此时规约到开始符号,并且输入串也为空,代表语法解析成功
所以实现自底向上的语法解析关键就是识别堆栈上是应该进行shift还是reduce操作。
- 进行暴力匹配,搜索堆栈上的符号和所有的语法推导式进行匹配 x
- 构造一个状态机来根据堆栈压入或弹出后的状态来决定是否进行reduce操作
所以接下来的任务自然就是构建一个有限状态自动机来能够指导语法分析器来进行操作。
小结
所谓的前置知识其实也就是了解语法分析在干什么,和大概要怎么干。
语法分析就是检查输入的Token流是不是符合语法的过程,而完成这一步骤的语法分析算法,拿自底向上来说,也就是从叶子节点向上推导成树顶端的过程。
另外我的github博客:https://dejavudwh.cn/
转载于:https://www.cnblogs.com/secoding/p/11367521.html
从零写一个编译器(二):语法分析之前置知识相关推荐
- 从零写一个编译器(完结):总结和系列索引
前言 这个系列算作我自己的学习笔记,到现在已经有十三篇了,加上这篇一共十四篇.一步一步的从词法分析到语法分析.语义分析,再到代码生成,准备在这一篇做一个总结收尾和一个这个系列以前文章的索引. (另外, ...
- 从零写一个编译器(三):语法分析之几个基础数据结构
项目的完整代码在 C2j-Compiler 写在前面 这个系列算作为我自己在学习写一个编译器的过程的一些记录,算法之类的都没有记录原理性的东西,想知道原理的在龙书里都写得非常清楚,但是我自己一开始是不 ...
- 从零写一个编译器(一):输入系统和词法分析
项目的完整代码在 C2j-Compiler 前言 从半抄半改的完成一个把C语言编译到Java字节码到现在也有些时间,一直想写一个系列来回顾整理一下写一个编译器的过程,也算是学习笔记吧.就从今天开始动笔 ...
- 从零写一个编译器(六):语法分析之表驱动语法分析
项目的完整代码在 C2j-Compiler 前言 上一篇已经正式的完成了有限状态自动机的构建和足够判断reduce的信息,接下来的任务就是根据这个有限状态自动机来完成语法分析表和根据这个表来实现语法分 ...
- 从零写一个编译器(五):语法分析之自动机的缺陷和改进
项目的完整代码在 C2j-Compiler 前言 在上一篇,已经成功的构建了有限状态自动机,但是这个自动机还存在两个问题: 无法处理shift/reduce矛盾 状态节点太多,导致自动机过大,效率较低 ...
- 从零写一个编译器(四):语法分析之构造有限状态自动机
项目的完整代码在 C2j-Compiler 通过上一篇对几个构造自动机的基础数据结构的描述,现在就可以正式来构造有限状态自动机 我们先用一个小一点的语法推导式来描述这个过程 s -> e e - ...
- 从零写一个编译器(十二):代码生成之生成逻辑
项目的完整代码在 C2j-Compiler 前言 在上一篇解释完了一些基础的Java字节码指令后,就可以正式进入真正的代码生成部分了.但是这部分先说的是代码生成依靠的几个类,也就是用来生成指令的操作. ...
- 从零写一个编译器(十):编译前传之直接解释执行
项目的完整代码在 C2j-Compiler 前言 这一篇不看也不会影响后面代码生成部分 现在经过词法分析语法分析语义分析,终于可以进入最核心的部分了.前面那部分可以称作编译器的前端,代码生成代码优化都 ...
- 从零写一个编译器(九):语义分析之构造抽象语法树(AST)
项目的完整代码在 C2j-Compiler 前言 在上一篇完成了符号表的构建,下一步就是输出抽象语法树(Abstract Syntax Tree,AST) 抽象语法树(abstract syntax ...
最新文章
- 同样是程序员,优秀的程序员能够月入5万甚至50万!,一般的程序员却只能月入5千甚至更低?那么他们差别在哪里呢?
- Win32使用Windows公共控件库创建工具条
- css继承和边框圆角 及 写三角形
- Shell特殊变量:Shell $0, $#, $*, $@, $?, $$和命令行参数
- SAP Marketing Cloud里的contact main facet是什么意思
- Docverter – 文本文件轻松转换为 PDF,Docx 和 ePub 文件
- 交叉编译openssl不修改Makefile的方法
- ubuntu 软件包降级
- SQL点滴9—使用with语句来写一个稍微复杂sql语句
- matlab 28m35,F28M35M22C
- access insert语句怎么写_码住!MySQL中超实用的几种SQL语句
- 你的计算机无法启动怎么回事,电脑无法正常启动如何做系统-“你的电脑未能正确启动”的解决方法...
- 阿拉伯数字小写金额转换成中文大写金额C程序说明
- 计算机组成原理笔记(王道考研) 第七章:输入输出系统
- TabLayout 的使用 更改下划线的长度,和一个奇葩的问题
- 日历控件CalendarView
- 如何让ie6 ie7 并存
- java实现计算器_Java 实现简单计算器
- 电气比例阀外接压力传感器和PID控制器实现微正压0.1%的超高精度控制
- Passage Re-ranking with BERT