编译原理 - 语法分析(1): 自上而下的语法分析

本文深入探讨编译原理中语法分析的技巧,对比正则文法与上下文无关文法,阐述自上而下语法分析的基本概念及面临的挑战,如回溯与左递归问题,并提供了解决方案。

为什么我们不用词法分析那一套方式(正则文法、有限状态机等)来解决语法分析?

正则文法通常什么样?

对于文法G=(V, T, S, P),如果产生式的形式如下:

A -> xB
A -> x

其中A, B属于V,x属于T*,则称为右线性文法;相似的,如果产生式的形式如下:

A -> Bx
A -> x

则称为左线性文法。右线性文法和左线性文法统称为正则文法

例子:

 

G(S):

  S->aS|bS

  S->aA
  A->aB|bB
  B->a|b

 

上下文无关文法通常什么样?

 对于文法G=(V, T, S, P),如果产生式的形式如下:

 

对于任何

0型文法:
    α -> β :α∈(VN∪VT)* , β∈(VN∪VT)* (可以是符号也可以是字)

1. 在0型文法的基础上,约束满足|β|>=|α|,即1型文法(上下文有关文法)。

2. 在上下文有关文法的基础上,约束满足所有的产生式左边只有一个非终结符。

例子:

    G(S):
        S -> aSa|bSbA
        A -> bA

很显然的上下文无关文法包括了正则文法,是一个更大的范围。

所以由于正则文法的表达能力,它的表述能力有限,而高级语言的语法结构合适用上下文无关文法描述。所以我们需要一套全新的算法来进行语法分析。

 

自上而下的语法分析

什么是自上而下的语法分析?

对于任何一个上下文无关文法,我们可以构建一个类似于下图的语法树。

该语法树(将无线递归下去)可以用来表示文法:

G(s):

S→aAS | a
A→SbA |SS |ba
 
对于这棵树的树根(S),他一定是开始符号。对于它的树叶(a,b),它一定是终止符号。
而自上而下的语法分析,从树根开始寻找出这样一个 推导出的句子恰为输入符号串的导出序列的过程。
 
自上而下分析所面临的问题
回溯

假设有文法:

S -> xAy

A -> **|*

对于输入串 x**y 匹配过程如下:

1.读第1个字符x,展开S树,发现S有唯一产生式S->xAy。且对于产生式的右边确实有第一个节点是叶结点(终结符),且为x。所以x得到匹配。

2.读第2个字符*,因为S的第一个节点已经处理完毕,于是尝试第二个节点A。发现第二个节点A并不是叶结点。

3.因为A不是叶节点,于是展开A,发现产生式右边有两个项:*和**,他们都满足第一个字符是*,故可能存在两个选择。当第一个选择是错误的时候,就需要回溯。

回溯会带来很多麻烦事:

1.因为语义和语法处理一般同时工作,所以当回头的时候,语义部分的工作都白费了。

2.如果存在了虚假匹配(如题用A->*处理了**的第一个*,后面出错)使得需要复杂的回溯处理。

3.如果分析不成功,我们难于知道输入串出错的确切位置。

左递归

如果存在左递归的产生式(如A->Abc),那么因为是处理过程的本质是树的深度遍历,会导致会无穷无尽的递归下去。

 

左递归的消除
直接左递归

P->Pα|β

这意味着 β(α)*

改写成:

P->βP'

P'->αP'|ε

更通用的:

P→Pα1 / Pα2 /…/ Pαn / β1 / β2 /…/βm

其中,αi(I=1,2,…,n)都不为ε,而每个βj(j=1,2,…,m)都不以P开头,将上述规则改写为如下形式即可消除P的直接左递归:

P→β1 P’ / β2 P’ /…/βm P’

P’ →α1P’ / α2 P’ /…/ αn P’ /ε

间接左递归

对于类似于:

S->Qc|c

Q->Rb|b

R->Sa|a

把S->Qc|c中的Q替换成S的表达式,就变成了直接左递归,再按照上述方法处理。

posted on 2017-05-08 12:08  TsAihS 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/TsAihS/p/6811309.html

java编程 含有界面 以及完整代码 〈程序〉→ main()〈语句块〉 〈语句块〉→{〈语句串〉} 〈语句串〉→〈语句〉;〈语句串〉|〈语句〉; 〈语句〉→〈赋值语句〉|〈条件语句〉|〈循环语句〉 〈赋值语句〉→ ID =〈表达式〉; 〈条件语句〉→ if〈条件〉〈语句块〉 〈循环语句〉→ while〈条件〉〈语句块〉 〈条件〉→(〈表达式〉〈关系符〉〈表达式〉) 〈表达式〉→〈表达式〉〈运算符〉〈表达式〉|(〈表达式〉)|ID|NUM 〈运算符〉→+|-|*|/ 〈关系符〉→<|<=||>=||!> word.wordList包(存储了关键字): word:此类是定义了存储关键字的结构:包括String型的关键字,和int型的识别符。 wordList:此类存储了29个关键字,在构造函数中初始化。 2、word包(进行词法分析)中: basicFunction:此类定义了做词法分析的基本函数: GetChar()将下一输入字符读到ch中,搜索知识器前移一个字符位置 GetBC();检查ch中的字符是否为空白。若是,则调用GetChar直至不 是字符为止 Concat();将ch中的字符连接到strToken之后 IsLetter();判断ch中的字符是否为字母 IsDigit();判断ch中的字符是否为数字 Reserve();对strToken中的字符创查找保留字表,若是则返回它的编码,否则返回0 Retract();将搜索指示器回调一个字符位置 RetractStr();将strToken置空 lexAnalysis:此类是用来进行词法分析,将分析后的单词存入word数组中,(注:在词法分析中,若是一串字母,则认为是ID,若是数字,则认为是NUM。存储的时候识别符分别存ID与NUM的识别符,但是内容仍然是自己的内容) 其中的wordAnalysis函数就是词法分析函数(具体实现请看后面的重要函数分析) 3、stack包(定义栈)中: 栈是通过链表来定义的,因此 StringListElement:次类定义了链表的每一个节点 StringStrack:此类定义了栈,其中有长度属性,有函数: Top();用来取得栈顶 Push();压栈 Pop();出栈 4、sentence包(语法分析)中: juzi :定义了文法的句子的结构:key(左边部分) content[](右边推出的部分) lo(长度) grammar :存储了文法的27个关系式 AnalysisFB :定义了分析表的存储结构 AnalysisF :存储分析表 SentenceAnalysis :语法分析 JuProduction(word w):此函数是用来判断在当前栈与输入串的情况下,用哪一个产生式,返回产生式在数组中的下标 若输入串的第一个字符与栈顶字符相同则表示可以规约,则返回-1; 若不能过用产生式,则返回-2; AnalysisBasic(word w):此函数是分布进行语法分析,对栈操作 * 根据所需要的产生式对符号栈进行操作 * 返回0表示规约;返回1表示移进;否则表示输入串不是文法的句子 5.Main包(主界面)中 Main:此类定义了图形界面
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值