本文中内容整理西安交通大学软件学院吴晓军老师的ppt中,仅供学习使用,请勿转载或他用
参考教材:《程序设计语言 编译原理》(第3版) 陈火旺等 国防工业出版社
文章目录
程序语言的语法描述与分析
目的
- 对语言的语法结构进行形式描述
- 从形式描述中,研究语法分析器的构造。(分析法递归子程序和算符优先分析法)
上下文无关文法:context-free grammar
引言
文法(grammar)
问题:如何描述语言
定义:文法是描述语言的语法结构的形式规则(即语法规则)
目的:解决语言的有穷说明问题,包含对语法的描述,但却不表达任何语义
文法的描述应该达到以下要求
- 形式上严格、准确
- 易于理解
- 具有较强的描述能力
- 有利于句子的分析和翻译,构造语法分析器
文法分类
课本上有具体介绍这四类文法,看看了解一下
分为4类:0、1、2、3型文法
与程序语言语法有关的是上下文无关文法
文法和语言
一个上下文无关文法G是一个四元式 ( V T , V N , S , P ) (V_T,V_N,S,P) (VT,VN,S,P),其中:
这里的闭包指的是文法符号
-
V T V_T VT:是非空有限集,它的每个元素是终结符号;
-
V N V_N VN:是非空有限集,它的每个元素是非终结符号;
V T ∩ V N = Φ V T ∪ V N = V V_T\cap V_N=\Phi \qquad V_T\cup V_N = V VT∩VN=ΦVT∪VN=V -
S: S ∈ V N S\in V_N S∈VN,称为开始符号
-
P P P:产生式集合(有限),每个产生式的形式是 { P → α ∣ P ∈ V N , α ∈ ( V T ∪ V N ) ∗ , S 至少一次为 P } \{P\rightarrow\alpha|P\in V_N,\alpha\in(V_T\cup V_N)^*,S至少一次为P\} {P→α∣P∈VN,α∈(VT∪VN)∗,S至少一次为P}
例子
G1(E)中的E表示开始符号,在这说明一下
| 表示或
-> is defined as 被定义为
由此可见,文法G1(E)所定义的语言是算术表达式。
如: i d + i d , i d ∗ ( i d + i d ) id+id,id*(id+id) id+id,id∗(id+id)等,他表达了简单算数表达式由id用A连接起来
该文法的:
- V N V_N VN是出现在 P P P的左部的所有符号集合
- V V V是 P P P的所有符号,所以$V_T = V \setminus V_N $
- S S S是该文法所定义的句子名字
- 所以:写出了 P P P就能找出其他三元素
定义
终结符
是用以组成语言中的串的基本符号,与程序语言中的“单词”是同义语;
如:表达式 i d + ( i d ) ∗ ( − i d ) id+(id)*(-id) id+(id)∗(−id)中,+、-、*、/、id均为终结符
非终结符
是标记某种串的集合的特定符号,与“语法变量”、”语法范畴“是同义词‘
如:表达式、运算符都表示一个串的集合
开始符号
一个 V N V_N VN,标记最终感兴趣的语法范畴。其他非终结符用以定义其它的串集,这有助于定义该语言,也有助于为它处理的语言提供一个分层的结构
产生式
规定由终结符和别的语法范畴组成一个新的语法范畴的办法
结构:非终结符->一串非终结符和终结符
例子:
如果右部只有一个,则直接叫做右部,有多个叫做右部候选式
例如如下表达式:
该语法范畴叫做句子,在程序语言中叫做程序
语言的句子是由一串 V N V_N VN定义,到最后才是一串 V T V_T VT
习惯记号
记号 | 含义 |
---|---|
V N V_N VN | 大写字母A,B,C等 |
V T V_T VT | 小写字母,0-9,+,- 等运算符,标点,分界符,id(自己定义的标识符的代表),if |
X 、 Y 、 Z X、Y、Z X、Y、Z | 文法符号,可以表示 V N V_N VN或 V T V_T VT的一个符号 |
u 、 v 、 w ⋅ ⋅ ⋅ z u、v、w\cdot\cdot\cdot z u、v、w⋅⋅⋅z | V T ∗ V_T^* VT∗中的串 |
α , β , γ \alpha,\beta,\gamma α,β,γ | 文法符号 ∈ ( V T ∪ V N ) \in(V_T\cup V_N) ∈(VT∪VN) |
S S S | 开始符号,第一个产生式中出现 |
→ \rightarrow → | 定义为(元语言符号) |
| | 或(元语言符号) |
问题:表达式语言无穷,如何定义?
- 有穷条产生式,产生无穷集,要求产生式必须递归
- 定义算数表达式用了两条浓缩的产生式。一般地,定义一个语言的产生式是很复杂的
- 对递归的算术表达式的产生式,进行反复的推导产生表达式语言
推导和语言
问题:用文法如何定义一个语言?
思路:从S出发,反复使用 P P P,对非终结符替换展开,最后得到全由终结符串组成的一个串
涉及到:替换、推导、句型、句子、语言
直接推出
是两个字符串之间的一种关系 R R R。
如: ( α A β ) R ( α γ β ) (\alpha\ A\ \beta)\ R \ (\alpha \ \gamma\ \beta) (α A β) R (α γ β),表示:若 A → γ ∈ P , α 、 β ∈ V ∗ A\rightarrow \gamma\in P,\alpha、\beta\in V^* A→γ∈P,α、β∈V∗,则 R R R就是直接推出, R R R记为 ⇒ \Rightarrow ⇒。即: α A β ⇒ α γ β \alpha\ A \ \beta \Rightarrow \alpha \ \gamma\ \beta α A β⇒α γ β
其中 α , β \alpha,\beta α,β都是文法符号串
推导
如两个串 u o , u n u_o,u_n uo,un,存在一个串序列 u o ⇒ u 1 ⇒ ⋅ ⋅ ⋅ ⇒ u n u_o\Rightarrow u_1 \Rightarrow \cdot\cdot\cdot \Rightarrow u_n uo⇒u1⇒⋅⋅⋅⇒un,则 u o R 1 u n , R 1 u_o R_1 u_n,R_1 uoR1un,R1记为 ⇒ + 或 ⇒ ∗ \stackrel{+}{\Rightarrow}或\stackrel{*}{\Rightarrow} ⇒+或⇒∗
- u o ⇒ + u n u_o\stackrel{+}{\Rightarrow}u_n uo⇒+un:表示从 u o u_o uo出发,经一步或若干步,可以推导出 u n u_n un
- u o ⇒ ∗ u n u_o\stackrel{*}{\Rightarrow}u_n uo⇒∗un:表示从 u o u_o uo出发,经零步或若干步,可以推导出 u n u_n un
R1叫做推导关系,有两种表示形式
两种的区别类似于闭包的加号和乘号,0步的话表示开始和结束都是一样的(即 u o u_o uo和 u 1 u_1 u1一样)
从文法的开始符号出发,则一定用的是加号去表达,开始是非终结符,最后结束是终结符,因为至少要经过一步推导
推导的最后是由终结符组成的终结符串
怎样由推导引出语言
只需要在推导中加入一些限制,即对 u o ⇒ + u n u_o\stackrel{+}{\Rightarrow}u_n uo⇒+un和 u o ⇒ ∗ u n u_o\stackrel{*}{\Rightarrow}u_n uo⇒∗un加一点限制
- 令 u o u_o uo为S,即推导要从开始符号开始,那么: S ⇒ ∗ α , α ∈ V ∗ S\stackrel{*}{\Rightarrow}\alpha,\alpha\in V^* S⇒∗α,α∈V∗,则称 α \alpha α为G的句型
- 如果在要求 α ∈ V T ∗ \alpha\in V_T^* α∈VT∗,则 α \alpha α为G的句子
- 文法G所产生的句子的全体是一个语言,记为L(G)。 L ( G ) = { α ∣ S ⇒ + α & α ∈ V T ∗ } L(G)=\{\alpha |S\stackrel{+}{\Rightarrow} \alpha \ \&\ \alpha \in V_T^* \} L(G)={α∣S⇒+α & α∈VT∗}
说明:
- 由文法G定义语言L需要依赖一种运算,即关系 ⇒ + \stackrel{+}{\Rightarrow} ⇒+。 V T ∗ V_T^* VT∗中有许多串,只有那些 ( S , u ) , ( S , v ) (S,u),(S,v) (S,u),(S,v)存在 ⇒ + \stackrel{+}{\Rightarrow} ⇒+关系的才是语言中的句子
- α , β \alpha ,\beta α,β是句型,表示 ( S , α ) ( S , β ) (S,\alpha)(S,\beta) (S,α)(S,β)有 ⇒ ∗ \stackrel{*}{\Rightarrow} ⇒∗的关系,但他们的构成是不全属于 V T V_T VT的字符
- G的句型集,是指存在 S ⇒ ∗ α S\stackrel{*}{\Rightarrow}\alpha S⇒∗α关系的所有 α \alpha α,该集的子集是L(G)
- V ∗ ⊃ 句型集 ⊃ L ( G ) V^*\supset 句型集\supset L(G) V∗⊃句型集⊃L(G)
句子一定是终结符串,终结符串不全是句子(参考说明1,必须与开始字符存在 ⇒ + \stackrel{+}{\Rightarrow} ⇒+关系才可以)
句型是终结符和非终结符的混合串,但是他们的混合串不一定全是句型(参考说明2,必须与开始字符存在 ⇒ ∗ \stackrel{*}{\Rightarrow} ⇒∗关系才可以)
语言是由句子构成的
V T ∗ V_T^* VT∗不代表语言(表示的意思是所有终结字符串), V ∗ V^* V∗不代表句型集(代表所有字符和非终结字符的串)
例子
根据文法G: E → E + E ∣ E ∗ E ∣ ( E ) ∣ i E\to E+E|E*E|(E)|i E→E+E∣E∗E∣(E)∣i,句子 i 1 ∗ ( i 2 + i 3 ) i_1*(i_2+i_3) i1∗(i2+i3)推导过程如下:
- 最左推导: E ⇒ E ∗ E ⇒ i 1 ∗ E ⇒ i 1 ∗ ( E ) ⇒ i 1 ∗ ( E + E ) ⇒ i 1 ∗ ( i 2 + E ) ⇒ i 1 ∗ ( i 2 ∗ i 3 ) E\Rightarrow E*E\Rightarrow i_1*E \Rightarrow i_1*(E)\Rightarrow i_1*(E+E)\Rightarrow i_1*(i_2+E) \Rightarrow i_1*(i_2*i_3) E⇒E∗E⇒i1∗E⇒i1∗(E)⇒i1∗(E+E)⇒i1∗(i2+E)⇒i1∗(i2∗i3)
- 最右推导: E ⇒ E ∗ E ⇒ E ∗ ( E ) ⇒ E ∗ ( E + E ) ⇒ E ∗ ( E + i 3 ) ⇒ E ∗ ( i 2 ∗ i 3 ) ⇒ i 1 ∗ ( i 2 ∗ i 3 ) E\Rightarrow E*E\Rightarrow E*(E)\Rightarrow E*(E+E)\Rightarrow E*(E+i_3) \Rightarrow E*(i_2*i_3)\Rightarrow i_1*(i_2*i_3) E⇒E∗E⇒E∗(E)⇒E∗(E+E)⇒E∗(E+i3)⇒E∗(i2∗i3)⇒i1∗(i2∗i3)
注意:从一个句型到另一个句型的推导过程并不唯一,但是通常只考虑最左推导和最右推导
语法树与二义性
语法树
目的:为了理解句子的语法,即理解句子如何从开始符号推导得到,因此引入“图”
定义:句型推导的图形表示,与替换顺序的选取无关
作用:明显地形成文法所暗含的句子的分层语法结构,为语法分析提供了一些新的途径
基本介绍
树的内节点:非终结符A标记,若 A → X Y Z A\to XYZ A→XYZ,则该产生式的一个子树为
树的叶:非终结符|终结符,对应一个句型
在语法树中找出文法的概念
语法树 | 文法 |
---|---|
内节点A | V N V_N VN |
叶 | 文法符号 |
子树 | 直接推导 |
根节点 | S |
任一次全剪 | 句型 |
叶子 ∈ V T \in V_T ∈VT时,将叶子顺序排列 | 句子 |
例子
例一
由此可见
- 每一中间过程,句型很容易获得
- 树忽略了符号的替换顺序的不同,不同推导过程得到相同的语法树
- 有的文法,对于同一句子,应用不同规则进行推导得到不同的语法树
例二
根据文法G对句子 i d + i d ∗ i d id + id * id id+id∗id进行推导
二义性问题
定义:文法G的某一句子有两个不同的树,则G为二义的
处理二义性对语法分析不便,因此希望:
- 判定二义否
- 控制充分条件,消除二义性
解决办法
尽量去掉二义性
- 如对上例,可以通过阐明运算符的优先性和结合性来解除文法的二义性
- 通过重写一个文法,把结合性和优先规则结合进文法本身中去
应注意, L ( G ) = L ( G ′ ) , G ≠ G ′ L(G)=L(G'),G\neq G' L(G)=L(G′),G=G′
语言的二义性问题与文法的二义性问题:
- 如语言找到一个文法是无二义的,则语言是无二义的
- 如未找到一个文法是无二义的,则也不能断定它二义,但先天二义也存在
- 文法的二义性是不可判定的(因为文法的二义性由句子的语法树判定,不可能对无穷句子来判别)
二义性示例
I saw you in a boat
- 我在船上看你
- 我看见你在船上
最后,作为描述程序语言的上下文无关法,我们限制:
所有非终结符都必须有用处
- 每一个非终结符都必须在句型中出现
- 对P不存在不终结的回路
四个都是正确的
B:因为句子集是一个无穷集,无法对所有句子做判断