python编写语法解析器_SLR语法分析器 python实现
一、语法分析器做什么
语法分析是根据某种给定的形式文法对由单词序列(如英语单词序列)构成的输入文本进行分析并确定其语法结构的一种过程。
一个语法分析器从词法分析器获得一个词素序列,并验证这个序列是否可以由源语言的文法生成。语法分析器会构造一棵语法分析树,并把它传递给编译器的其他部分进一步处理,在构建语法分析树的过程中,就验证了这个词素序列是否符合源语言的文法。
二、自底向上的语法分析器的实现
I. 推导方式
输入:文法 $ G=(V,T,P,S) $ 的拓广文法 $ G’ $
输出: $ G’ $ 的 $ LR(0) $ 分析表。即 $ action $ 和 $ goto $ 表
步骤:
① 构造 $ I_0 $ 。 $ I_0 = CLOSURE( lbrace S’ rightarrow .S rbrace ) $
② 通过 $ GO(I_i, X) $ 函数求出 $ LR(0) $ 的项目集规范族 $ C= lbrace I_0,I_1,…,I_n rbrace $
③ 遍历项目及规范族 $ C $ , $ I_0 $ 对应初始状态 $ 0 $, $ I_i $ 对应状态 $ i $
(1) 若项目 $ A→α·aβ $ 属于 $ I_k $ 且转换函数 $ GO(I_k,a)= I_j $ ,当 $ a $ 为终结符时,则置 $ ACTION[k,a] $ 为 $ S_j $ 。
(2) 若项目 $ A→α· $ 属于 $ I_k $ ,则对任何终结符 $ a $ 和’#'置 $ ACTION[k,a] $ 和 $ ACTION $ [k,#]为 $ r_j $ , $ j $ 为在文法 $ G′ $ 中某产生式 $ A→α $ 的序号。
(3) 若 $ GO(I_k,A)=I_j $ ,则置 $ GOTO[k,A] $ 为 $ G_j $ ,其中 $ A $ 为非终结符。
(4) 若项目 $ S′→S· $ 属于 $ I_k $ ,则置 $ ACTION $ [k,#]为 $ acc $ ,表示接受。
II. 关键函数
1. CLOSURE(J) 函数
即求J中每一项的闭包。
也可以用递归。
1
2
3
4
5
6
7
8function CLOSURE(J):
I = J
重复执行:
for I 中每个项目,形如A->α.Bβ,执行:
for 增广文法中每一个以B开始的产生式,B->γ,执行:
if 以B开始的加点最左侧的产生式,B->.γ 不在 I 中,将其加入 I 中
直到 I 不再增大
返回 I
2. GO(I,X) 函数
参数:
$ I $ 为项目集闭包。
$ lbrace X rbrace $ 为 $ I $ 中点后字符的集合,因此 $ X $ 就是其中一项。
比如:$ I_0= lbrace Srightarrow .E, Erightarrow .E+T, Erightarrow .T, Trightarrow .T*F, Trightarrow .F, Frightarrow .(E), Frightarrow.g rbrace $ ,则 $ lbrace X rbrace = lbrace E, T, F, (, g rbrace $,需要把 $ X $ 中每一项都传入 $ GO $ 函数进行计算。
1
2
3
4
5function GO(I,X):
J = Φ
for I 中每一个项目,形如A->α.Xβ(点后面的字符为 X ),执行:
J = J ∪ {A->αX.β},即将点右移一位。
返回 CLOSURE(J),即返回 J 的闭包
3. ★ 如何使用 $ CLOSURE(J) $ $ GO(I,X) $
以下,大写字母为非终结符,小写字母或符号为终结符
文法: $ G = lbrace Srightarrow E, Erightarrow E+T, Erightarrow T, Trightarrow T*F, Trightarrow F, Frightarrow (E), Frightarrow g rbrace $
① 构造 $ I_0 $ 。即求增广文法的第一个产生式的闭包 $ CLOSURE( lbrace S rightarrow .E rbrace ) $ 。
即 $ CLOSURE(J), J = {S rightarrow .E} $ E是非终结符,所以找以E为开始的点在产生式右部的开始的产生式。$ E rightarrow .T % $ , $ T $ 仍为非终结符,所以再像 $ E $ 一样找 $ T $,把它们都加入 $ J $。
② 利用 $ GO(I_0, X) $ 构造 $ I_i $
第①步求出了
$ I_0= lbrace Srightarrow .E, Erightarrow .E+T, Erightarrow .T, Trightarrow .T*F, Trightarrow .F, Frightarrow .(E), Frightarrow.g rbrace $
(1) 首先找出 $ I_0 $ 中所有点后的字符, $ lbrace X rbrace = lbrace E,T,F,(,g rbrace $
(2) 每一个 $ lbrace X rbrace $ 中的字符都会作为 $ GO(I_0,X)中的参数X $
a. 求 $ GO(I_0, E) $ ,得到 $ I_1 $
此时 $ X $ 为 $ E $ , 即形如 $ A rightarrow α.Xβ $ 的产生式为 $ lbrace Srightarrow .E,Erightarrow .E+T rbrace $
因此 $ J = Φ ∪ lbrace Srightarrow E.,Erightarrow E.+T rbrace $
然后求 $ CLOSURE(J) $ ,返回 $ I_1 $
b. 求 $ GO(I_0, T) $ ,得到 $ I_2 $ , 同上
…
e. 求 $ GO(I_0, g) $ ,得到 $ I_5 $ , 同上
(3) 再找出 $ I_1 $ 中所有点后的字符, $ lbrace X rbrace = lbrace + rbrace $
f. 求 $ GO(I_1, +) $ ,得到 $ I_6 $ , 同上
…
③ 所有 $ I_x $ 的集合就是项目及规范族 $ C $ , $ C= lbrace I_0, I_1, …, I_n rbrace $
III. 实现
0. 数据结构
python 列表、集合等
1. 项目生成
步骤:
① 读取文法文件,存入列表
② 遍历列表的所有元素,为其加点,从产生式的右边的第一个符号的左侧开始加点,点每次右移一位,直到移到最右侧,这些标有点的产生式就是文法的LR(0)项目,即
产生式:S->AB; 项目:(1) S->.AB (2) S->A.B (3) S->AB.
读取文法后,将终结符、非终结符分别存入终结符列表、非终结符列表,便于之后的判断。
2. 读取规范句型
将标识符、符号、关键字等读出,转换为文法可以识别的终结符与非终结符组成的串,等待识别。
3. $ CLOSURE $, $ GO $函数生成
$ CLOSURE(J) $
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# 为了与列表CLOSURE区分,我使用了CLOSURE FUNCTION 的简写 CLOSUREF
def CLOSUREF(J):
tempClosure = []
for i in J:
nodePosition = i.index('@')
if (nodePosition == (len(i) - 1)) or ((i[nodePosition + 1]) in TERMINATOR): # 点在最后一位 或 点后是终结符
tempClosure.append(i)
elif((i[nodePosition + 1]) in NONTERMINATOR): # 点后为非终结符
tempClosure.append(i)
searchClosure(i[nodePosition+1], tempClosure) # 传入S->@B 中的 B,即找以 B 为开始的产生式
if tempClosure in CLOSURE: # 如果当前生成的CLOSURE已经生成过了,则直接返回之前生成的相同的CLOSURE
return CLOSURE[CLOSURE.index(tempClosure)]
CLOSURE.append(tempClosure)
return tempClosure
def searchClosure(c, tempClosure):
for i in grammarWithNode: # 遍历所有项目
if i[0] != c:
continue
if i[1] == '@': # 点在产生式右部的开始
tempClosure.append(i)
if c != i[2] and i[2] in NONTERMINATOR : # 点后的仍然是非终结符,如 E
searchClosure(i[2], tempClosure) # 递归找以 E 为产生式开始的,且点在产生式右部的开始
$ GO(I,X) $
1
2
3
4
5
6
7
8
9
10
11
12
13def GO(I,X):
J = []
for i in I:
nodeIndex = i.index('@')
if nodeIndex == len(i) - 1:
continue
if i[nodeIndex + 1] != X:
continue
moveRightStr = nodeRightMove(i) # 将点右移一位
J.append(moveRightStr)
return CLOSUREF(J)
4. 求FIRST、FOLLOW集
FIRST:
寻找最左终结符
递归
如:求 $ S rightarrow Eb $ 求S的FIRST集,E为终结符。 $ S rightarrow E, E rightarrow a $ 相当于 $ S rightarrow a $ , 因此E的最左终结符一定是S的
$ E rightarrow a , E rightarrow T $ 同理,$ T $的终结符集一定是 $ E $的子集,依次向下递归即可。
FOLLOW:
寻找每个非终结符右侧的终结符,(不考虑空串的情况时)
有三种情况:
① $ A rightarrow aBb $ , $ B $ 为非终结符, $ b $ 为终结符, $ FOLLOW(B) = FOLLOW(B) ∪ lbrace b rbrace $
② $ A rightarrow aB $ , $ B $ 为非终结符, $ E rightarrow Af $ 即 $ E rightarrow aBf $ , 因此 $ A $ 的 $ FOLLOW $ 集就是B的 $ FOLLOW $ 集的一个子集,因此 $ FOLLOW(B) = FOLLOW(B) ∪ FOLLOW(A) $
③ $ A rightarrow aBE $ , $ B $ 为非终结符, $ E $ 为非终结符, $ E rightarrow a $ 即 $ A rightarrow aBa $ ,因此 $ E $ 的 $ FIRST $ 集就是 $ B $ 的 $ FOLLOW $ 集的一个子集,因此 $ FOLLOW(B) = FOLLOW(B) ∪ FIRST(E) $
重复这个操作,直到所有 $ FOLLOW $ 集不再增大为止
5. 生成SLR分析表
① 首先构造 $ I_0 $ , $ I_0 = CLOSURE( lbrace S rightarrow E rbrace ) $,然后根据 "3."的描述,求出 $ C = lbrace I_0, I_1, …, I_n rbrace $
② $ I_0 $ 为初始状态。构造 $ action $ 表与 $ goto $ 表,$ action $ 表列标所有终结符和’#’, $ goto $表列标为所有终结符,行标均为所有项目及规范族的下标。
③ 令初始状态 $ k = 0 $, k递增进行如下循环:
(1) 如果 $ A rightarrow α.aβ $ 在 $ I_k $ 中,并且 $ a $为终结符,那么求一下 $ GO(I_k, a) $ 的值是 $ C $中的哪一项,如果求出是 $ I_k $ , 则 $ action[k,a] = Sj $ ,即在行标为 $ k $, 列标为 $ a $ 的位置上写入 $ Sj $。
(2) 如果 $ A rightarrow α.Bβ $ 在 $ I_k $ 中,并且 $ B $为非终结符,那么那么求一下 $ GO(I_k, B) $ 的值是 $ C $中的哪一项,如果求出是 $ I_k $ , 则 $ goto[k,B] = Sj $,即在行标为 $ k $, 列标为 $ B $ 的位置上写入 $ j $。
(3) 如果 $ A rightarrow α. $ , 并且 $ A rightarrow α $ 在(不加点)文法 $ G $ 中是第 $ j $ 个产生式,那么对于每个终结符(包括#)$ t $ ,如果 $ t ∈ FOLLOW(A) $ ,(A为产生式左部), 则 $ action[k,t] = rj $ ,即在行标为 $ k $ , 列标为满足要求的 $ t $ 的位置上写入 $ rj $ 。
(4) 如果当前项目为增广文法新加入的项目的中介状态 $ S rightarrow E. ∈ I_k $ , 则 $ action $ [k,#] $ = acc $ 。
遍历完 $ C $ 中所有 $ I $ 以及 $ I $ 中所有项目后,$ SLR $ 分析表就生成了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22def generateSLR():
global action, goto
action = [[' ' for col in range(len(TERMINATOR))] for row in range(len(CLOSURE))]
goto = [[' ' for col in range(len(NONTERMINATOR))] for row in range(len(CLOSURE))]
for k in range(0, len(CLOSURE)):
for a in CLOSURE[k]: # Closure内各表达式
nodeIndex = a.index('@')
if nodeIndex == len(a) - 1:
grammarIndex = grammarOriginalLists.index(a[0:len(a)-1])
for ter in TERMINATOR:
if a[0] == grammarOriginalLists[0][0]:
action[k][TERMINATOR.index('#')] = "a0"
elif ter in FOLLOW[NONTERMINATOR.index(a[0])]:
action[k][TERMINATOR.index(ter)] = "r" + str(grammarIndex)
elif a[nodeIndex+1] in TERMINATOR:
resultClosure = GO(CLOSURE[k], a[nodeIndex+1])
aIndex = CLOSURE.index(resultClosure)
action[k][TERMINATOR.index(a[nodeIndex+1])] = "S" + str(aIndex)
elif a[nodeIndex+1] in NONTERMINATOR:
resultClosure = GO(CLOSURE[k], a[nodeIndex+1])
aIndex = CLOSURE.index(resultClosure)
goto[k][NONTERMINATOR.index(a[nodeIndex+1])] = "G" + str(aIndex)
6. 进行语法分析
利用Python的数据结构列表模拟栈的操作,状态栈、符号栈分别存放当前状态、当前的符号,输入流不断进行输入,状态与当前输入利用SLR表进行转换,得到新的状态与符号。
三、 源码
python编写语法解析器_SLR语法分析器 python实现相关推荐
- vscode如何添加本地python解释器、解析器 Interpreter?(Python: Select Interpreter)
先安装python扩展 然后点ctrl+shift+p搜索python:select,选择解析器(或者也可以直接点左下方的) 然后360报毒了,允许通过,然后选择你想要的解释器 然后就好了
- 使用ANTLR做一个简单的Python SQL语法解析器 - 推酷
使用ANTLR做一个简单的Python SQL语法解析器 - 推酷 使用ANTLR做一个简单的Python SQL语法解析器 - 推酷 posted on 2016-11-14 13:11 lexus ...
- Python语法解析器PLY——lex and yacc in Python - 娄振林专栏 - 博客频道 - CSDN.NET
Python语法解析器PLY--lex and yacc in Python - 娄振林专栏 - 博客频道 - CSDN.NET Python语法解析器PLY--lex and yacc in Pyt ...
- 用 C 语言开发一门编程语言 — 语法解析器
目录 文章目录 目录 前文列表 编程语言的本质 词法分析 语法分析 使用 MPC 解析器组合库 安装 快速入门 实现波兰表达式的语法解析 波兰表达式 正则表达式 代码实现 前文列表 <用 C 语 ...
- CSS大会 | 打破常“规”:挖掘语法解析器规则漏洞
2019年7月30-31日,第五届互联网安全领袖峰会(CSS 2019)在北京开幕.作为前沿技术安全研究团队代表,Tencent Blade Team两位高级安全研究员受邀登台,探讨如何挖掘语法解析器 ...
- Boost学习之语法解析器--Spirit
Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...
- sqlparser mysql_SQL语法解析器JSQLParser | IT瘾
相关 [sql 语法 解析器] 推荐: SQL 语法解释器jsqlparser. 是用java 开发的解析器, 可以生成java类层次结构.. 可以完美解析 表的 增删查改等操作.. 展开它的源码你会 ...
- mysql ddl 语法解析工具_sharding-sphere之语法解析器
语法解析器,根据不同类型的语句有不同的语法解析器去解析成成SQLStatement,SQL解析器的类图我用脑图画出来如下: SQLParser.png 可以看到,不同的sql有不同的处理解析器去解析, ...
- NET Core中使用Irony实现自己的查询语言语法解析器
在之前<在ASP.NET Core中使用Apworks快速开发数据服务>一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语 ...
最新文章
- pandas数据结构:Series/DataFrame;python函数:range/arange
- 算法之组合数学及其算法篇(三) ----- 容斥原理应用以及几个典型的递归关系
- 一致性hash算法使用
- PHP中$_SERVER的详细参数
- 记一次ArrayList产生的线上OOM问题
- 2017 Google 开发者大会直播入口
- [转]mysql优化——show processlist命令详解
- 使用Git将本地项目上传到Github操作详解
- 电子科技大学《图论及其应用》复习总结--第五章 匹配与因子分解
- tp1900芯片对比7621a_TP无线路由器WDR7660千兆版,厉害了单芯片TP1900
- IP Fragment攻击原理
- 我想推出这么一种应用(现代诗歌)
- 亚洲销售女神徐鹤宁经典语录——太过精辟!
- 小米面试题:手机分身,电话号码隐藏。
- c语言小游戏----改版斗兽棋
- 哇!用Python读取CVS文件竟然有5招,据说90%的人只会2招
- SpringBoot微信小程序商城(前台+后台)源码分享
- 后台怎么接收处理从url 客户端传来的json数据格式
- 经典乱码“烫烫烫”和“屯屯屯”
- 05-旭日X3派测评——Open Cv Pangolin等库安装ORB_SLAM2 安装运行
热门文章
- 属性编辑器 - 字体设置
- 腾讯AI Lab 崔乐阳博士忆西湖大学读博期间和张岳导师之间的故事
- mac os 升级 12.0.1 monterey 根目录只读
- jar命令查看查找搜索 jar, war 文件内容
- 【​观察】Bespin Global:探索MSP服务智能进化之路
- stm32毕设分享 GSM手机短信收发系统(源码+论文)
- android ART学习
- IT领域标准化浅谈(一):中国标准化相关组织
- python Turtle Graphics海龟绘图工具
- [web安全原理分析]-XEE漏洞入门