1.52k likes | 2.26k Views
语法分析器是根据源语言的文法构造出来的。 用于程序语言的编译程序构造中的一些典型的语法分析方法及分析器的生成器 Yacc。 语法分析方法:自顶向下分析:递归预测分析和 LL(1) 分析;自底向上分析:算符优先分析和 LR 分析 。. 4 . 1 语法分析器的作用 4 . 2预测分析器 4.2.1预测分析 4.2.2递归预测分析器的构造 4 .2.3非递归预测分析器的构造— LL(1) 4 . 3 书写文法 4 . 3 . 1消除左递归 4 . 3 . 1提取左因子 4.4自顶向下的带回溯的分析方法简介. 4.1语法分析器的作用.
E N D
语法分析器是根据源语言的文法构造出来的。 • 用于程序语言的编译程序构造中的一些典型的语法分析方法及分析器的生成器Yacc。 • 语法分析方法:自顶向下分析:递归预测分析和LL(1)分析;自底向上分析:算符优先分析和LR分析。
4.1 语法分析器的作用 4.2预测分析器 4.2.1预测分析 4.2.2递归预测分析器的构造 4 .2.3非递归预测分析器的构造—LL(1) 4.3 书写文法 4.3 .1消除左递归 4.3 .1提取左因子 4.4自顶向下的带回溯的分析方法简介
4.1语法分析器的作用 单词符号 词 法 分析器 语 法 分析器 源程序 分析树 取下一个 单词符号 语 法 分析器 语 法 分析器 * r m * l m w w S w S w 自顶向下分析 自底向上分析
构造推导的关键问题 在构造最左推导的过程中,面对当前读入的单词符号和当前被替换的非终结符两者,应该选择这个非终结符的那条候选式去替换它(推导);主要找出选择一个非终结符号的候选式的方法; 在构造最右推导的过程中,面对当前读入的单词符号,已分析过的符号串中是否已构成一个产生式的右部(可归约),即句柄。如果已构成句柄,即用相应的产生式左部(非终结符号)去替换它(归约),寻找句柄的方法。
二. 构造最左推导(aabbaa) (1.自顶向下) SaASa A SbA SS ba S S aAS a S A aSbAS aabAS a S b A aabbaS a aabbaa a b
二. 构造最右推导 (2.自底向上) SaAS a A SbA SS ba S S aAS (aAS) a S A aAa ( a) a aSbAa (SbA) S b A aSbbaa (ba) a a aabbaa (a) b
4.2预测分析器 4 .2 .1 预测分析 预测分析的原理 4 .2 .2 递归预测分析器的构造 用一组递归过程实现预测分析,产生式的状态转换图可作为编写递归过程的兰图。 4 .2 .3 非递归预测分析器的构造—LL(1) 对于每一步分析,分析表项M[A,a]=‘A’ 表示:面对非终结符号A和向前看符号a应选 择产生式A进行分析。
4 .2 .1 预测分析 自顶向下分析是从文法的开始符号出发,试构造出一个最左推导,从左至右匹配输入的单词符号串。如果在每步推导中,面对被替换的非终结符号(不妨称为A)和当前从左至右读入输入串读到的单词符号(又称向前看符号,不妨称为a),如果A的定义(无ε-产生式)A→α1 |α2 |… |αn 中,只有αi(1≤i≤n)推导出的第一个终结符号是a,那么,我们就可以用产生式A→αi 构造最左推导,即用αi替换A。
例4.1 下面文法生成pascal类型的一个子集 type Simple id (4.1) array[ simple ]of type Simple integer char num dotdot num array [ num dotdot num ] of integer
array [ num dotdot num ] of integer typearray[simple] of type {注:A=type,a=array, type→array[simple ] of type} array[num dotdot num] of type {注:A=simple, a=num simple→num dotdot num } array[num dotdot num] of simple {注:A=type,a=integer , type→simple } array[num dotdot num] of integer {注:A=simple,a=integer ,simple→integer }
例4.1,在推导过程中,完全可以根据当前的向前看符号决定选择哪个产生式往下推导,因此,分析过程是完全确定的。这种分析称为自顶向下的预测分析。 例4.1,在推导过程中,完全可以根据当前的向前看符号决定选择哪个产生式往下推导,因此,分析过程是完全确定的。这种分析称为自顶向下的预测分析。 原因在于,文法中,AVN, A12... n i,j(1i,jni<>j),从 i推导出来的第一个终结符号集合(称为FIRST( i) )和从 j推导出来的第一个终结符号集合(称为FIRST( j) )不相交,即, FIRST( i) FIRST( j)=
定义4.1 令G[S]=(VT,VN,S,P),则 FIRST()=a a…a VT 例4.2 文法G[S],其产生式如下: S→aA|d A→bAS|ε (4.2) 若 w=abd,则构造最左推导的过程如下: S aA {注:A=S,a=a,S→aA} abAS {注:A=A,a=b,A→ bAS} abS {注:A=A,a=d, A→ε} abd {注:A=S,a=d, S→d} *
考虑第三步推导:abAS abS (A) d是句型abAS中紧跟随非终结符A的终结符号,把紧跟随非终结符A的终结符号集记作Follow(A),其定义如下: 定义4.2 令G[S]=(VT,VN,S,P), 则 FOLLOW(A)=aS … Aa…, a VT, A VN 若S ...A, 则规定$∈Follow(A),‘$’作为输入串的结束符号( Follow(A)的作用) 。 + + * +
4.2.2递归预测分析器的构造 文法(4.1)的预测分析器,由图4.3中所示的一组递归过程组成,这组递归过程的执行,将实现根据文法(4.1)对任一句子w进行预测分析。因此,这个分析器称为递归预测分析器。其中,过程type和过程simple是相应于文法(4.1)的非终结符号type和simple的, 而过程match是为了简化过程type和过程simple的代码所附设的。如果过程match的参数t与向前看符号a是匹配的,则进展到下一个输入符号。
PROCEDURE match(t:token); BEGIN IF lookahead=t THEN lookahead :=nexttoken ELSE error END;
PROCEDURE type; BEGIN IF lookahead in{integer,char,num} THEN simple ELSE IF lookahead =‘’ THEN BEGIN match(‘’); match(id) END ELSE IF lookahead =array THEN BEGIN match(array); match(‘[‘) ; simple; match(‘]’); match(of); type END ELSE error END;
PROCEDURE simple; BEGIN IF lookahead=integer THEN match(integer) ELSE IF lookahead=char THEN match(char) ELSE IF lookahead =num THEN BEGIN match(num); match(dotdot); match(num) END ELSE error END;
构造方法: A VN,构造一个递归程,不妨命名为A。过程A根据当前向前看符号a处于A的哪个候选式的FIRST集合中,就选择那个候选式进行分析。根据选择的候选式,从左至右,若是终结符号,则和向前看符号匹配;若是非终结符号,则调用相应过程;若aFOLLOW(A),则选择A。 使用状态转换图构造递归预测分析器 每个产生式右部是VT∪VN ∪{}上的正规表达式,由此画出相应的识别器,称作状态转换图,以此作为编写递归预测分析器的蓝图。
给定文法G,状态转换图的画法如下: AVN 1. 创建一个初始状态和一个终结状态; 2.对于每一个产生式A X1X2,…,Xn, 创建一条从初始状态到终结状态的路径, 箭弧分别标记以X1,X2,…,Xn。 例4.3 (4.3) G[E]=(VT={+,*,(,), id}, VN={E,E',T,T',F}, E,P) P: E→TE' E'→+TE'ε T→FT' T'→*FT' ε F→(E) id
T E’ E : 0 1 2 + T E’ 3 4 5 6 E’ : F T’ 7 8 T : 9 * 10 T’ : F T’ 11 12 13 ( ) E 14 F : 15 16 17 id 图4.4 文法 4.3的转换图
预测分析器的工作: 从开始符号的状态图开始,若处于状态s, 从s有弧到达状态t。若当前向前看符号是a,a 和某标记匹配,则分析进入t状态且读入下 一 个输入符号;若aFIRST(A),则转到A状态图, 分析到达A状态图的接受状态后,分析进入t 状态;若aFOLLOW(A),则选弧。 状态图的确定性问题: 根据上述选择方法,若能选择唯一,则是确定的;否则,是非确定的。
T E’ E : 0 1 2 T E’ + E’ : 3 4 5 6 T + T 3 4 E’ : 5 + 3 4 6 6 T + T T + 4 0 3 0 3 E : 6 6 图4.5 简化转换图
图4.5 算术表达式的简化转换图 + T 0 3 E: 6 * F 13 T: 7 8 ) ( E F: 14 15 16 17 id
PROCEDURE E: BEGIN T; WHILE lookahead=‘+’ DO BEGIN match(‘+’); T END END; PROCEDRUE T: BEGIN F; WHILE lookahead=‘*’ DO BEGIN match(‘*’); F END END;
PROCEDURE F: BEGIN IF lookahead=‘(’ THEN BEGIN match(‘(’); E; match(‘)’) END ELSE IF lookahead=id THEN match(id) ELSE error END;
作业: 4.1 4.2 4.3 (a) (c ) 4.4 自己看
4.2.3 非递归预测分析器的构造 一. 基本思想 二.非递归预测分析器的模型和分析演示 三.非递归预测分析器的控制程序 四. 计算 FIRST和 FOLLOW集合 五.非递归预测分析表的构造 六. LL(1)文法 七. 在预测分析法中的错误处理示例
一. 基本思想 预测分析是在每步推导中,对被替换的非终结符号A和当前向前看符号a能选择A的某条产生式进行推导。非递归预测分析的基本思想是,根据文法G,构造一张分析表M,表中元素M[A,a]存放的,要么是被选择的产生式(正确分析情况);要么是出错处理程序入口(分析出现错误)。整个分析是在分析表M的驱动下完成的。本节主要围绕LL(1)分析表展开讨论。
二.非递归预测分析器的模型 id + id * id $ 输入 ETE’ id+TE’ FT’E’ id+FT’E’ 预测分析 控制程序 + F F id id idT’E’ id+idT’E’ T T’ T’ T idE’ E’ E E’ $ 栈
三.非递归预测分析器的控制程序 置 ip指向 w$的第一个符号;令x为栈顶符号,a是 ip所指向的符号. push(st,$);push(st,s); REPEAT IF xVT{$} THEN IF x=a THEN { pop(st); ip:=ip+1} ELSE error( ) ELSE IF M[x,a]=xy1y2…yk THEN {p0p(st);push(st,yk);…push(st,y1); write(xy1y2…yk) } ELSE error( ) UNTIL x=$
四. 计算FIRST和FOLLOW集合 目的:构造文法G的分析表M,实际上,构造预测分析。 G[Z]: Z d XYZ Y c X Y a (4.4) (VTVN)*, =XYZ, X , Y ,FIRST()必包含FIRST(Z)。同样, =AXYt 则tFOLLOW(A)。必须注意能产生空串的符号,这样的符号称为nullable,若A ,则nullable(A)=true。 + * * + + *
算法4.2 计算nullable,FIRST和FOLLOW 初始化: 除FOLLOW(S)={$}外, FIRST和 FOLLOW全为空集. nullable全为false. FOR aVT DO FIRST(a)={a} ; REPEAT FOR A Y1Y2…YnP DO { IF i(1i n) nullable(Yi)=true THEN nullable(A)=ture; FOR i:=1 TO n DO { IF (i=1) or (1 j i-1)nullable(Yj)=true THEN FIRST(A):=FIRST(A)FIRST(Yi); 计算FOLLOW集 }} UNTIL FIRST,FOLLOW,nullable不再增大
IF YiVN THEN { IF (i=n)orj(i+1j n)nullable(Yj)=true THEN FOLLOW(Yi):=FOLLOW(Yi) FOLLOW(A); IF Yi+1 VT THEN Yi+1 FOLLOW(Yi) ELSE FOR k:=i+1 TO n DO IF (k=i+1)or j(i+1j k-1)nullable(Yj)=true THEN FOLLOW(Yi):=FOLLOW(Yi) FIRST(Yk); }
例 4.5 把算法4.2应用于文法G[E](4.3), 得到下面的计算结果。 VN
五. 非递归预测分析表的构造 在对文法G的每个非终结符号A及其任意候选α都构造出FIRST(α)和FOLLow(A)之后,用它们来构造G的分析表M[A,a]。 算法4.3 非递归预测分析表的构造 1.对文法G的每个产生式A执行第2步 和第3步; 2. 对每个终结符号a∈FIRST(),把 A 加至M[A,a]中; 3. 若α ε,则对任何b∈FOLLOW(A), 把A 加至M[A,b]中; 4. 把所有无定义的M[A,a]标上错误标记。 *
六. LL(1)文法 对于某些文法,M[A,a]可能含有多重定义。 例4.7 文法(4.5),它的分析表如表4.4所示。其中M[S’,e]包含两个产生式S’eS 和S’。这是来自文法(4.5 )的二义 性, FOLLOW(S’)={e, $} 反应了这一点。 G[S]: S iEtSS’a S’ eS Eb (4.5)
一个文法G, 若它的分析表M不含多重定义 入口,则被称为LL(1)文法。LL(1)中的第一 个“L”意味着自左而右地扫描输入,第二个“L” 意味着生成一个最左推导,并且“1”意味着为做 出分析动作的决定,在每一步利用一个向前看 符号,一个文法G是LL(1)的,当且仅当对于 G的每一个非终结符号A的任何两个不同产生 式Aαβ ,下面的条件成立: 1. FIRST(α)∩FIRST(β)=Φ;它们不 应该都能推出空字ε; 2.假若β*ε,那么, FIRST(α)∩ FOLLOW(A)=Φ.
七. 在预测分析法中的错误处理示例 下面两种情况下发现源程序的语法错误: 1.栈顶上的终结符号与下一个输入符 号不 匹配; 2. 分析表入口M[A,a] 为空。 处理方法:跳过剩余输入符号串中的若干符号,使栈和剩余输入符号串能重新协调地同步工作。在表中加入M[A,FOLLOW(A)]:=“synch”。 在分析中查到入口M[A,a],若是空白,则跳过输入符号a;若是synch,则从栈中将非终 结符号A弹出。如果栈顶的终结符号与输入符 号不匹配,则将此终结符号从栈中弹出。
4.3 书写文法 通常使用的,不是LL(1)的,也不能用于递归预测分析器的构造。通过改写,使之适合于自顶向下分析。 4.3 .1 消除左递归 1 .左递归的定义 2 .左递归文法不适于构造自顶向下分析 3 . 消除直接左递归 4 . 消除间接左递归 4.3 .2 提取左公因子
4.3 .1 消除左递归 1 .左递归的定义 一个文法G,若存在推导A A ,其中, A∈VN,∈(VT∪VN)*,则称G是左递归的。 存在上述推导的原因是文法G中存在左递归规则。例如,描述表达式常用的语法G[E],其产生式如下: E→E+TT T→T*F F (4.6) F→(E) id + +
二.左递归文法不适于用来构造自顶向下分析 这种规则更简单的代表是S→Sa|b (1)FIRST(Sa)∩FIRST(b)≠Φ。 (2)由S产生的句子是{ban|n≥0}。例如,对 于输入baaa$,从左到右扫描输入串,开 始,向前看符号是b,此时,选用S的 哪 条候选式?若选用S→b,则肯定构造不 出S baaa;若选用S→Sa,则面对向前看 符号b,下次仍选用S→Sa,不知何时选 用S→b。构造分析树的过程如图4.9所示。 +
S a S S a 图4.9 含直接左递归文法的分析树结构 用这样的规则构造递归预测分析的过程,那么,一进入这种过程不匹配任何输入符号,直接执行递归调用,形成自己调用自己的死循环。
三.消除直接左递归 AA ,(VTVN)* A A’ A’ A’ A * 文法(4.6) 文法(4.3) EE+TT E TE’ T T*F F E’ +TE’ F (E) id T FT’ T’ *FT’ F (E) id +
直接左递归的一般形式 A A1 A2... An 1 2... m A 1 A’ 2A’ ... mA’ A’ 1A’ 2A’ ... n A’ 四.消除间接左递归 间接左递归的例子 S Aa b A Ac Sd (4.7) S Aa Sda 算法4.4要求无环路A A和无-产生式。 +
, 算法4.4 消除左递归 1.AVN, 按任一顺序排列成A1, A2, …,An. 2. for i:=1 t0 n do for j:=1 to i-l do { if Ajδ1|δ2|…|δk , Ai Ajγ P then 把Ai Ajγ改写成 Ai δ1γ|δ2γ|…|δkγ 消除关于Ai- 产生式的直接左递归性 } 3.化简由(2)所得到的文法。
例 4.9 G[s]: S Acc A Bb b B Sa a 非终结符号排序为B,A,S A (Sa a)b b 把B的产生式代入A中 A Sa bab b S (Sa bab b)c c 把A的产生式代入S中 S Sa bcabc bc c S abcS’ bc S’cS’ 消除直结左递归 S’ abcS’ A Sa bab b A 和 B的产生式是多余的 B Sa a
S Ac c A Bb b B Sa a 非终结符号排序为S,A, B B (Acc) a a 把S的产生式代入B中 B Acac a a B (Bbb)cacaa 把A的产生式代入B中 B Bbcabcacaa B bcaB’caB’aB’ 消除直结左递归 B’ bcaB’ S Ac c 最后G[s]的产生式 A Bb b B bcaB’caB’aB’ B’ bcaB’
4.3.2 提取左因子 文法G的产生式 A, 若 1, 1, 1和1从左端开始有相同的子串,这个子串称为和的公共左因子。显然,含有公共左因子的规则A不能用来构造预测分析。为此,用提取左因子来改写这样的规则。例如,stmtif expr then stmt else stmt 改写 if expr then stmt stmtif expr then stmt (else stmt) 成:stmtif expr then stmt S’ S’ else stmt * *
若A 1 2 改写成: AA‘ A‘12 例4.11 G[S]: S aSdAc A aS b (4.9) 把A的产生式代入S中: S aSdaScbc 提取左因子: S aSS’bc S’ dc A的产生式是多余的。 G[S]: SApBq A aAp d B aBq c (4.10)