第三章 语法分析器
判断单词流表示的输入程序在设计语言中是否为一个有效的句子
概述
- 概念路线图
主要任务,确定输入程序在源语言中是否是一个语法上有效的语句。通过将源语言的形式限制到一个称为上下文无关语言(context-free language)的语言集,可以确保语法分析器能够高效地回答成员资格问题。
-
自顶向下语法分析(top-down parsing ) 递归下降语法分析器(recursive-descent parser)和LL(1)语法分析器;
-
自底向上语法分析(bottom-up parsing ) LR(1)语法分析器
-
语法分析
给出单词流s和语法G,找到G中生成s的一个推导
语法的表示
RE无法匹配括号左右平衡的表达式
-
上下文无关语法 (CFG)
对于语言L,其CFG定义了表示L中有效语句的符号串的集合。
设G为上下文无关语法,描述了语句的形成;则L(G)为可以从G导出的语句集,G定义的语言 -
语句
可以从语法规则推导出的一个符号串 -
产生式
CFG中的每个规则都称为一个产生式 -
非终结符
语法产生式中使用的语法变量 -
终结符
出现在语句中的单词,包含一个词素及其语法范畴;在语法中,单词通过其语法范畴表示 -
推导
推导是一系列的重写步骤,从语法的起始符号开始,,结束于语言中的一个语句 -
句型
有效推到中的某个步骤出现的符号串 -
上下文无关语法的构成
上下文无关语法G是一个四元组( T , NT , S , P):
T 终结符或语言L(G)中单词的集合
NT G产生的非终结符的集合
S 一个非终结符,L(G)中语句的集合
P G中产生式或重写规则的集合
T和NT可以在P中推导出来
语法分析树
-
表示推导的图 语法分析树
-
最右推导 每次都重写最右侧的非终结符(仅看非终结符的最右侧)
-
最左推导 每次都重写最左侧的非终结符
-
二义性 如果L(G)中的某个语言有一个以上最右(最左)推导,那么语法G就是二义性的 // 不良性质,无法确定分析树,转化成确定的代码
-
为强制保证优先级正确 在 a+b* c 之类的语句,会按照 a+(b*c)来进行推导, 其他具有优先级先后的均如此
上下文无关语法及对应语法分析器的类
从特定输入语句构造推导的过程称为语法分析
语法分析器看到的“程序”来自于词法分析器的输出:一个单词并注明了其语法范畴
ex. a+b*c ==> <name,a> + <name,b> * <name,c>
将语法分析器的功能形象化定义为 “为输入程序构建语法树” 也是有用的。
树的根已知,即语法的起始符号;叶子节点已知,必须按照从左至右的顺序逐一匹配词法分析器返回的单词流
自顶向下语法分析
- 从根开始构建语法树,并使树向叶子的方向增长,直至:
- 语法分析树的下边缘只包含终结符 且输入流已经耗尽
- 部分完成的语法分析树的下边缘各节点,与输入流存在着明确的不匹配
上下文无关语法的很大一个子集不进行回溯即可完成语法分析
为进行自顶向下语法分析而转换语法
-
左递归 会导致无限循环
对于CFG中的一个规则,如果其右侧第一个符号与左侧符号相同或者能够推导出左侧符号,那么称该规则是左递归的,前者为直接左递归,后者为间接左递归引入e使得左递归变成右递归:即规则中的递归只涉及最右侧的符号
-
无回溯语法
一种CFG,最左自顶向下语法分析器可以在至多前瞻一个单词的情况下,总是能够预测正确的产生式规则(前瞻符号 look ahead symbol) -
提取左因子以消除回溯
在一组产生式中,提取并隔离共同前缀的过程
自顶向下的递归下降语法分析器
递归下降的语法分析器,在结构上呈现为一组相互递归的过程,语法中的每个非终结符号都对应与一个过程,因而,语法自身充当了实现语法分析器的指南
LL(1)语法分析器: 由左(Left)到右扫描其输入,构建一个最左推导(Leftmost),其中仅使用一个前瞻符号(1),其是无回溯的
语法分析器生成器:可以根据规格来构建语法分析器,编译器的编译器。
自底向上语法分析 ×
从叶子节点开始构建语法树,并使树向根的方向增长,直到出现以下两种情况:
1. 将分析书的上边缘缩减到只有一个节点,即语法的目标符号 (分析成功)
2. 无法找到句柄 (失败)
- 句柄 <A -> β , k > ,其中β出现在语法分析树的上边缘,而其右侧末端位于位置k,且将β替换为A是语法分析中的下一步
- 归约 在自底向上语法分析器中,利用A -> β将树上边缘中的β替换为A,从而缩减语法树上边缘的做法
LR(1)从左(Left)到右扫描,反向(Reverse)最右推导,一个前瞻符号(1)
实际问题
出错恢复
通过找到下一个同步单词 synchronizing word 例如 ; ,再调用分析器
一元运算符
增加一个反引用的形式
处理上下文相关的二义性
- 重写语法 暂时搁置二义性
- 根据声明类型来归类标识符
左递归和右递归的选择
- 栈深度
右递归语法栈深度更大,受限于列表长度;左递归栈深度取决于语法本身,而非输入流 - 结合性