从零写一个编译器(三):语法分析之几个基础数据结构
项目的完整代码在 C2j-Compiler
写在前面
这个系列算作为我自己在学习写一个编译器的过程的一些记录,算法之类的都没有记录原理性的东西,想知道原理的在龙书里都写得非常清楚,但是我自己一开始是不怎么看得下来,到现在都还没有完整的看完,它像是一本给已经有基础的人写的书。
在parse包里一共有8个文件,就是语法分析阶段写的所有东西啦
- Symbols.java
- Production.java
- SyntaxProductionInit.java
- FirstSetBuilder.java
- ProductionManager.java
- ProductionsStateNode.java
- StateNodeManager.java
- LRStateTableParser.java
项目的完整代码在 C2j-Compiler
SyntaxProductionInit 语法初始化
在上一篇说了,竟然要验证句子正确与否,自然就需要语法,也就是给出相应的语法推导式
所有语法的初始化工作都在SyntaxProductionInit里完成
///EXT_DECL_LIST ->EXT_DECL_LIST COMMA EXT_DECL
right = getProductionRight(new int[]{Token.EXT_DECL_LIST.ordinal(), Token.COMMA.ordinal(), Token.EXT_DECL.ordinal()});
production = new Production(productionNum, Token.EXT_DECL_LIST.ordinal(), 0, right);
productionNum++;
addProduction(production, false);
比如下面这个就对应C语言的变量声明语句的推导式,PROGRAM是整个推导式的开始符号,EXT_DEF_LIST就是声明列表,这里的EXT_DEF_LIST -> EXT_DEF_LIST EXT_DEF需要注意一下是左递归情况,LR语法是可以处理的,关于这个可以看之前的博文。
比如EXT_DECL_LIST -> EXT_DECL -> VAR_DECL 多个变量名称声明可以推导是一个变量名称声明或者多个变量名称声明 + 逗号 + 变量名称声明
VAR_DECL 则可以是一个标识符或者一个多重指针
即一个从叶子节点不断的推导,读入终结符,最后推导到开始符号,且输入流也已经读完
/*
* PROGRAM -> EXT_DEF_LIST
*
* EXT_DEF_LIST -> EXT_DEF_LIST EXT_DEF
*
* EXT_DEF -> OPT_SPECIFIERS EXT_DECL_LIST SEMI
* | OPT_SPECIFIERS SEMI
*
*
* EXT_DECL_LIST -> EXT_DECL
* | EXT_DECL_LIST COMMA EXT_DECL
*
* EXT_DECL -> VAR_DECL
*
* OPT_SPECIFIERS -> CLASS TTYPE
* | TTYPE
* | SPECIFIERS
* | EMPTY?
*
* SPECIFIERS -> TYPE_OR_CLASS
* | SPECIFIERS TYPE_OR_CLASS
*
*
* TYPE_OR_CLASS -> TYPE_SPECIFIER
* | CLASS
*
* TYPE_SPECIFIER -> TYPE
*
* NEW_NAME -> NAME
*
* NAME_NT -> NAME
*
* VAR_DECL -> | NEW_NAME
*
* | START VAR_DECL
*
*/
在语法推导式初始化的过程一共要构建三个数据结构
private HashMap<Integer, ArrayList<Production>> productionMap = new HashMap<>();
private HashMap<Integer, Symbols> symbolMap = new HashMap<>();
private ArrayList<Symbols> symbolArray = new ArrayList<>();
- ProductionMap的key就是推导式的左边,value即对应的一个或多个产生式
- SymbolMap类似ProductionMap,key是推导式的左边,value是一个或者多个产生式的右边
Symbol类似Production,也是用来表示产生式的,但是稍有点不同,也还包括终结符,在后面也会有不同的作用,
//Symbols
public int value;
public ArrayList<int[]> productions;
public ArrayList<Integer> firstSet = new ArrayList<>();
public boolean isNullable;
如果一个非终结符,它可以推导出空集,那么这样的非终结符我们称之为nullable的非终结符
- symbolArray存储着每一个Symbols对象,在后面也会有不一样的作用
Production 产生式类
在上一篇里说到验证语法的过程就是在一堆对应语法产生式中推导出答案,Production类就是来表示一个产生式
private int dotPos = 0;private int left;private ArrayList<Integer> right;private ArrayList<Integer> lookAhead = new ArrayList<>();private int productionNum = -1;public Production(int productionNum, int left, int dot, ArrayList<Integer> right) {this.left = left;this.right = right;this.productionNum = productionNum;lookAhead.add(Token.SEMI.ordinal());if (dot >= right.size()) {dot = right.size();}this.dotPos = dot;
}
- left和right就是产生式的左边和右边,都是用之前Token的值来表示
- lookahead向前看集合,后面用到再提
- dos就像构造这个自动机的辅助工具,之后用到详细说
- productionNum是这个产生式对应编号,这个编号是在初始化语法的时候给定的
小结
这一篇主要介绍了几个数据结构,这几个数据结构都是之后构建有限状态自动机的基础。本来想把状态机的构建也写在这一篇,但是如果加上去之后,篇幅太长,加一部分会感觉不成模块,有点分散,所以自动机的构建就写在下一篇。
另外我的github博客:https://dejavudwh.cn/
转载于:https://www.cnblogs.com/secoding/p/11367530.html
从零写一个编译器(三):语法分析之几个基础数据结构相关推荐
- 从零写一个编译器(完结):总结和系列索引
前言 这个系列算作我自己的学习笔记,到现在已经有十三篇了,加上这篇一共十四篇.一步一步的从词法分析到语法分析.语义分析,再到代码生成,准备在这一篇做一个总结收尾和一个这个系列以前文章的索引. (另外, ...
- 从零写一个编译器(一):输入系统和词法分析
项目的完整代码在 C2j-Compiler 前言 从半抄半改的完成一个把C语言编译到Java字节码到现在也有些时间,一直想写一个系列来回顾整理一下写一个编译器的过程,也算是学习笔记吧.就从今天开始动笔 ...
- 从零写一个编译器(二):语法分析之前置知识
项目的完整代码在 C2j-Compiler 前言 在之前完成了词法分析之后,得到了Token流,那么接下来就是实现语法分析器来输入Token流得到抽象语法树 (Abstract Syntax Tree ...
- 从零写一个编译器(四):语法分析之构造有限状态自动机
项目的完整代码在 C2j-Compiler 通过上一篇对几个构造自动机的基础数据结构的描述,现在就可以正式来构造有限状态自动机 我们先用一个小一点的语法推导式来描述这个过程 s -> e e - ...
- 从零写一个编译器(六):语法分析之表驱动语法分析
项目的完整代码在 C2j-Compiler 前言 上一篇已经正式的完成了有限状态自动机的构建和足够判断reduce的信息,接下来的任务就是根据这个有限状态自动机来完成语法分析表和根据这个表来实现语法分 ...
- 从零写一个编译器(五):语法分析之自动机的缺陷和改进
项目的完整代码在 C2j-Compiler 前言 在上一篇,已经成功的构建了有限状态自动机,但是这个自动机还存在两个问题: 无法处理shift/reduce矛盾 状态节点太多,导致自动机过大,效率较低 ...
- 从零写一个编译器(十):编译前传之直接解释执行
项目的完整代码在 C2j-Compiler 前言 这一篇不看也不会影响后面代码生成部分 现在经过词法分析语法分析语义分析,终于可以进入最核心的部分了.前面那部分可以称作编译器的前端,代码生成代码优化都 ...
- 从零写一个编译器(九):语义分析之构造抽象语法树(AST)
项目的完整代码在 C2j-Compiler 前言 在上一篇完成了符号表的构建,下一步就是输出抽象语法树(Abstract Syntax Tree,AST) 抽象语法树(abstract syntax ...
- 从零写一个编译器(八):语义分析之构造符号表
项目的完整代码在 C2j-Compiler 前言 在之前完成了描述符号表的数据结构,现在就可以正式构造符号表了.符号表的创建自然是要根据语法分析过程中走的,所以符号表的创建就在LRStateTable ...
最新文章
- 机器学习也能套模版:在线选择模型和参数,一键生成demo
- Python 人脸识别 OpenCV (haarcascades)
- 如何修改Linux命令提示符
- leetcode1162. 地图分析(bfs)
- 方法覆盖异常篇 java 1615387415
- 将下图的nfa确定化为dfa_实战技术利用AutoCAD确定PCB板型
- Java语言编写一个简单彩票机的程序
- 神舟七号飞船应用计算机进行飞行状态属于,“神舟七号”飞船应用计算机进行飞行状态调整属于()。...
- 鸿蒙系统代还,荣耀智慧屏可以看电视了!华为还是妥协了
- MES管理系统基础知识
- html5自动调用js函数,从html文件中的外部js文件调用Javascript函数
- oracle 排除节假日,ORACLE 计算节假日
- 复习SSM day01 SSM Maven工程的搭建及配置文件
- 强化学习实践三 :编写通用的格子世界环境类
- maxent阈值使用
- 秀一段《易语言》的源代码
- 织梦响应式精密机械模具类网站织梦模板(自适应手机端)
- c语言b=x%1000 100什么意思,C语言程序-设计 100个小程序代码.doc
- ios内购二次验证安全性问题_苹果IOS内购二次验证返回state为21002的坑
- 系统分析师难考吗?通过率大概是多少?
热门文章
- BZOJ3627 [JLOI2014]路径规划
- 谈谈CTO、技术总监、首席架构师的区别
- 数据库分库分表(sharding)系列(五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案...
- jquery 插件闭包
- isc-dhcp监听网口的实现步骤
- JS和C#分别防注入代码
- IAR需要注意的地方
- Exception in thread “main“ java.lang.IllegalArgumentException: http://www.dmg.org/PMML-4_4(没搞定)
- linux下面把png文件转化为背景透明
- 【机器学习】 二次损失函数的不足及交叉熵损失softmax详解