一、语法分析器做什么

语法分析是根据某种给定的形式文法对由单词序列(如英语单词序列)构成的输入文本进行分析并确定其语法结构的一种过程。

一个语法分析器从词法分析器获得一个词素序列,并验证这个序列是否可以由源语言的文法生成。语法分析器会构造一棵语法分析树,并把它传递给编译器的其他部分进一步处理,在构建语法分析树的过程中,就验证了这个词素序列是否符合源语言的文法。

二、自底向上的语法分析器的实现

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实现相关推荐

  1. vscode如何添加本地python解释器、解析器 Interpreter?(Python: Select Interpreter)

    先安装python扩展 然后点ctrl+shift+p搜索python:select,选择解析器(或者也可以直接点左下方的) 然后360报毒了,允许通过,然后选择你想要的解释器 然后就好了

  2. 使用ANTLR做一个简单的Python SQL语法解析器 - 推酷

    使用ANTLR做一个简单的Python SQL语法解析器 - 推酷 使用ANTLR做一个简单的Python SQL语法解析器 - 推酷 posted on 2016-11-14 13:11 lexus ...

  3. 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 ...

  4. 用 C 语言开发一门编程语言 — 语法解析器

    目录 文章目录 目录 前文列表 编程语言的本质 词法分析 语法分析 使用 MPC 解析器组合库 安装 快速入门 实现波兰表达式的语法解析 波兰表达式 正则表达式 代码实现 前文列表 <用 C 语 ...

  5. CSS大会 | 打破常“规”:挖掘语法解析器规则漏洞

    2019年7月30-31日,第五届互联网安全领袖峰会(CSS 2019)在北京开幕.作为前沿技术安全研究团队代表,Tencent Blade Team两位高级安全研究员受邀登台,探讨如何挖掘语法解析器 ...

  6. Boost学习之语法解析器--Spirit

    Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...

  7. sqlparser mysql_SQL语法解析器JSQLParser | IT瘾

    相关 [sql 语法 解析器] 推荐: SQL 语法解释器jsqlparser. 是用java 开发的解析器, 可以生成java类层次结构.. 可以完美解析 表的 增删查改等操作.. 展开它的源码你会 ...

  8. mysql ddl 语法解析工具_sharding-sphere之语法解析器

    语法解析器,根据不同类型的语句有不同的语法解析器去解析成成SQLStatement,SQL解析器的类图我用脑图画出来如下: SQLParser.png 可以看到,不同的sql有不同的处理解析器去解析, ...

  9. NET Core中使用Irony实现自己的查询语言语法解析器

    在之前<在ASP.NET Core中使用Apworks快速开发数据服务>一文的评论部分,.NET大神张善友为我提了个建议,可以使用Compile As a Service的Roslyn为语 ...

最新文章

  1. pandas数据结构:Series/DataFrame;python函数:range/arange
  2. 算法之组合数学及其算法篇(三) ----- 容斥原理应用以及几个典型的递归关系
  3. 一致性hash算法使用
  4. PHP中$_SERVER的详细参数
  5. 记一次ArrayList产生的线上OOM问题
  6. 2017 Google 开发者大会直播入口
  7. [转]mysql优化——show processlist命令详解
  8. 使用Git将本地项目上传到Github操作详解
  9. 电子科技大学《图论及其应用》复习总结--第五章 匹配与因子分解
  10. tp1900芯片对比7621a_TP无线路由器WDR7660千兆版,厉害了单芯片TP1900
  11. IP Fragment攻击原理
  12. 我想推出这么一种应用(现代诗歌)
  13. 亚洲销售女神徐鹤宁经典语录——太过精辟!
  14. 小米面试题:手机分身,电话号码隐藏。
  15. c语言小游戏----改版斗兽棋
  16. 哇!用Python读取CVS文件竟然有5招,据说90%的人只会2招
  17. SpringBoot微信小程序商城(前台+后台)源码分享
  18. 后台怎么接收处理从url 客户端传来的json数据格式
  19. 经典乱码“烫烫烫”和“屯屯屯”
  20. 05-旭日X3派测评——Open Cv Pangolin等库安装ORB_SLAM2 安装运行

热门文章

  1. 属性编辑器 - 字体设置
  2. 腾讯AI Lab 崔乐阳博士忆西湖大学读博期间和张岳导师之间的故事
  3. mac os 升级 12.0.1 monterey 根目录只读
  4. jar命令查看查找搜索 jar, war 文件内容
  5. 【​观察】Bespin Global:探索MSP服务智能进化之路
  6. stm32毕设分享 GSM手机短信收发系统(源码+论文)
  7. android ART学习
  8. IT领域标准化浅谈(一):中国标准化相关组织
  9. python Turtle Graphics海龟绘图工具
  10. [web安全原理分析]-XEE漏洞入门