【20200422】编译原理课程课业打卡十七之求解文法FirstVT&LastVT&构造文法算符优先关系表


叮嘟!这里是小啊呜的学习课程资料整理。好记性不如烂笔头,今天也是努力进步的一天。一起加油进阶吧!
在这里插入图片描述

一、课业打卡十七之求解文法FirstVT&LastVT&构造文法算符优先关系表

问题描述

已知文法G[S]为:
S->a|^|(T)
T->T,S|S

(1)计算G[S]的FirstVT和LastVT。
(2)构造G[S]的算符优先关系表并说明G[S]是否为算符优先文法。
(3)给出输入串(a,a)# 和 (a,(a,a))# 的算符优先分析过程。

题目解析

(1)计算G[S]的FirstVT和LastVT。

在这里插入图片描述
(2)构造G[S]的算符优先关系表并说明G[S]是否为算符优先文法。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

(3)给出输入串(a,a)# 和 (a,(a,a))# 的算符优先分析过程。
在这里插入图片描述
在这里插入图片描述

二、知识巩固

1、自下而上的语法分析

(1)优先分析法   【本章重点】

    简单优先分析(简洁、效率低)
    算符优先分析(表达式类型)

(2)LR分析    【第六章学习】

在这里插入图片描述
自下而上语法分析试图将一个字符串反向归约至开始符号。
自下而上语法分析比自上而下语法分析更有效率,对语法的限制更少。

2、分析符号串是否为文法的句子实例

文法G[S](1) S → aAcBe
(2) A → b
(3) A → Ab
(4) B → d
分析符号串abbcde是否G[S]的句子

在这里插入图片描述

3、自下而上语法分析的策略

自下而上语法分析的策略:移进-规约分析
移进就是将一个终结符推进栈;
归约就是将0个或多个符号从栈中弹出,根据产生式将一个非终结符压入栈;
移进-归约过程是自顶向下最右推导的逆过程(规范归约)。

文法G[E]:
E -> T + E | T
T -> int * T | int | (E)

在这里插入图片描述
在这里插入图片描述

4、我们如何决定什么时候移进,什么时候规约?

例如已知文法G[E]:
E -> T + E | T
T -> int * T | int | (E)

考虑 int | * int + int
我们可以用 T -> int进行归约,而得到 T | * int + int

致命错误: 无法规约到开始符号 E

直觉: Want to reduce only if the result can still be reduced to the start symbol

一般的移进-归约策略:

若句柄在栈顶出现,则归约;
否则移进;

句柄(Handles):句型的最左直接短语。

5、关于短语、直接短语、句柄的定义

在这里插入图片描述

6、关于移进-归约冲突的产生&解决方法

实际应用中可能出现的’冲突’:
移进与归约都合法,产生移进-归约冲突;
归约时可以适用两个不同的产生式,产生归约-归约冲突;

二义文法会导致‘冲突’
但应注意,许多的非二义文法同样会导致‘冲突’

Conflict Solutions:

      改写文法
      根据产生式出现的顺序来选择
      根据算符的优先级    【***】

7、简单优先分析法

按照文法符号(包括终结符和非终结符)的优先关系确定句柄。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

简单优先文法的定义:

满足以下条件的文法是简单优先文法
(1)在文法符号集V中,任意两个符号之间最多只有一种优先关系成立。
(2)在文法中任意两个产生式没有相同的右部。
(3)不含空产生式。

8、算符优先分析法

  • 某些文法具有“算符”特性。
    1、表达式运算符(优先级、结合性)
    2、人为地规定其算符的优先顺序,即给出优先级别和同一级别的结合性
  • 只考虑算符之间的优先关系来确定句柄。
    在这里插入图片描述

如何确定算符优先关系?

文法G[E]:E→E+E|E-E|E*E|E/E|E^E|(E)|i

(1) 优先级次于i,右结合
(2)*和/优先级次之,左结合
(3)+和-优先级最低,左结合
(4)括号‘(’,‘)’的优先级大于括号外的运算符,小于括号内的运算符,内括号的优先性大于外括号
(5)#的优先性低于与其相邻的算符

算符优先关系的定义
在这里插入图片描述

9、算符文法(OG)& 算符优先文法(OPG)的定义

算符文法(OG)的定义

定义 :  
如果不含空产生式的上下文无关文法 G 中没有形如 U->…VW…的产生式,其中V,W∈VN则称G 为算符文法(OG)。

性质1:
在算符文法中任何句型都不包含两个相邻的非终结符。(数学归纳法)
性质2:
如 Vx 或 xV 出现在算符文法的 句型 a 中,其中V∈VN,x∈VT, 则 a 中任何 含 x 的短语必含有V。(反证法)

算符优先文法(OPG)的定义

在 OG 文法 G 中:
若任意两个终结符间至多有一种算符优先关系存在,则称G 为算符优先文法(OPG)。

注意:允许b>c,c>b;不允许b>c,b<c,b=c
结论: 算符优先文法是无二义的。

Ending!
更多课程知识学习记录随后再来吧!

就酱,嘎啦!

在这里插入图片描述

注:
人生在勤,不索何获。

  • 43
    点赞
  • 140
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
好的,这是一个比较复杂的问题,需要分几步来完成。我尽量详细地回答你。 1. 读取文件并判断算符文法 首先,我们需要读取输入的文法并判断其是否为算符文法。算符文法的特点是,每个产生式的右部只有一个终结符或一个非终结符和一个终结符之间有一个算符。下面是一个算符文法的例子: ``` E -> E + T | T T -> T * F | F F -> ( E ) | id ``` 读取文件可以使用 Python 内置的 `open()` 函数,代码如下: ```python with open('grammar.txt', 'r') as f: grammar = f.readlines() ``` 这里假输入的文法文件名为 `grammar.txt`,并将其读入到 `grammar` 变量中。接下来,我们需要判断文法是否为算符文法。可以使用正则达式来匹配每个产生式,代码如下: ```python import re for line in grammar: if not re.match(r'^[a-zA-Z]+\s*->\s*([a-zA-Z]+\s*[+\-*/]\s*)*[a-zA-Z]+$', line.strip()): print('This is not an operator grammar!') exit() ``` 如果输入的文法不是算符文法,就输出错误信息并结束程序。 2. 计算 FIRSTVT 集和 LASTVT 集 接下来,我们需要计算每个非终结符的 FIRSTVT 集和 LASTVT 集。首先,我们需要将文法用 Python 的数据结构示出来,比如使用字典来示每个产生式的左部和右部: ```python productions = {} for line in grammar: left, right = map(str.strip, line.split('->')) right = right.split('|') productions[left] = [r.split() for r in right] ``` 然后,我们可以按照算符文法的规则计算每个非终结符的 FIRSTVT 集和 LASTVT 集。具体计算方法可以参考经典编译原理教材,这里简单介绍一下。 对于每个产生式 `A -> αBβ`,如果存在 `B -> ε` 或者 `α` 中的某个符号可以推导出空串,那么将 `FIRSTVT(B)` 中的元素加入到 `FIRSTVT(A)` 中。 对于每个产生式 `A -> αBβ`,如果存在 `B -> ε` 或者 `β` 中的某个符号可以推导出空串,那么将 `LASTVT(B)` 中的元素加入到 `LASTVT(A)` 中。 对于每个产生式 `A -> αB` 或者 `A -> Bβ`,将 `FIRSTVT(B)` 中的元素加入到 `FOLLOWVT(A)` 中。 根据上述规则,我们可以编写 Python 代码来计算每个非终结符的 FIRSTVT 集和 LASTVT 集,代码如下: ```python # 计算 FIRSTVT 集 firstvt = {} for symbol in productions.keys(): firstvt[symbol] = set() while True: updated = False for left, right in productions.items(): for r in right: if len(r) > 0 and r[0] not in productions: if r[0] not in firstvt[left]: firstvt[left].add(r[0]) updated = True elif len(r) > 0 and r[0] in productions: for s in firstvt[r[0]]: if s not in firstvt[left]: firstvt[left].add(s) updated = True if len(r) > 1 and r[-1] not in productions: if r[-1] not in firstvt[left]: firstvt[left].add(r[-1]) updated = True elif len(r) > 1 and r[-1] in productions: for s in firstvt[r[-1]]: if s not in firstvt[left]: firstvt[left].add(s) updated = True if not updated: break # 计算 LASTVT 集 lastvt = {} for symbol in productions.keys(): lastvt[symbol] = set() while True: updated = False for left, right in productions.items(): for r in right: if len(r) > 0 and r[0] not in productions: if r[0] not in lastvt[left]: lastvt[left].add(r[0]) updated = True elif len(r) > 0 and r[0] in productions: for s in lastvt[r[0]]: if s not in lastvt[left]: lastvt[left].add(s) updated = True if len(r) > 1 and r[-1] not in productions: if r[-1] not in lastvt[left]: lastvt[left].add(r[-1]) updated = True elif len(r) > 1 and r[-1] in productions: for s in lastvt[r[-1]]: if s not in lastvt[left]: lastvt[left].add(s) updated = True if not updated: break ``` 3. 构造算符优先分析 接下来,我们可以使用计算出的 FIRSTVT 集和 LASTVT 集来构造算符优先分析算符优先分析是一个二维格,行和列都是文法中的终结符和非终结符,每个单元格里的内容示两个符号之间的优先关系。具体构造方法可以参考经典编译原理教材,这里也简单介绍一下。 对于每个产生式 `A -> αBβ`,将 `FIRSTVT(B)` 中的每个元素和 `FOLLOWVT(A)` 中的每个元素加入到 `M[A, a]` 中,其中 `a` 是 `FIRSTVT(β)` 中的每个元素。 对于每个产生式 `A -> β`,将 `FIRSTVT(β)` 中的每个元素和 `FOLLOWVT(A)` 中的每个元素加入到 `M[A, a]` 中,其中 `a` 是 `FIRSTVT(β)` 中的每个元素。 对于每个产生式 `A -> αB`,将 `LASTVT(B)` 中的每个元素和 `FOLLOWVT(A)` 中的每个元素加入到 `M[B, a]` 中,其中 `a` 是 `FIRSTVT(β)` 中的每个元素。 具体实现可以参考下面的 Python 代码: ```python # 构造优先关系 precedence_matrix = {} for symbol in productions.keys(): precedence_matrix[symbol] = {} for s in productions.keys(): precedence_matrix[symbol][s] = '' for left, right in productions.items(): for r in right: if len(r) > 0 and r[0] not in productions: for a in firstvt[r[0]]: precedence_matrix[left][a] = '<' if len(r) > 1 and r[-1] not in productions: for a in lastvt[r[-1]]: precedence_matrix[r[-1]][a] = '>' for i in range(len(r) - 1): if r[i] not in productions and r[i+1] not in productions: precedence_matrix[r[i]][r[i+1]] = '=' elif r[i] not in productions and r[i+1] in productions: for a in firstvt[r[i+1]]: precedence_matrix[r[i]][a] = '<' elif r[i] in productions and r[i+1] not in productions: for a in lastvt[r[i]]: precedence_matrix[a][r[i+1]] = '>' else: for a in lastvt[r[i]]: for b in firstvt[r[i+1]]: precedence_matrix[a][b] = '=' ``` 4. 对给定达式进行分析 最后,我们可以使用构造出的算符优先分析来对给定的达式进行分析。具体方法是,使用一个栈来保存符号,从左到右扫描达式,如果遇到终结符就直接压入栈中,如果遇到非终结符,则根据算符优先分析中对应单元格的内容来确定优先关系。如果栈顶符号优先级低于当前符号,就将当前符号压入栈中;否则,就弹出栈顶符号,直到栈顶符号优先级低于当前符号或者栈为空。如果最后栈中只剩下一个符号,且它是文法的起始符号,那么达式就是合法的。 具体实现可以参考下面的 Python 代码: ```python expression = 'a+b*c' stack = [] i = 0 while i < len(expression): if expression[i] in productions.keys(): if len(stack) == 0 or precedence_matrix[stack[-1]][expression[i]] == '<': stack.append(expression[i]) i += 1 elif precedence_matrix[stack[-1]][expression[i]] == '>': right = stack.pop() left = stack.pop() for left_, right_ in productions.items(): if [left, expression[i]] in right_: stack.append(left_) break elif precedence_matrix[stack[-1]][expression[i]] == '=': i += 1 else: stack.append(expression[i]) i += 1 if len(stack) == 1 and stack[0] == 'E': print('The expression is valid!') else: print('The expression is invalid!') ``` 完整的代码如下所示:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发芽ing的小啊呜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值