330 likes | 482 Views
ç¬¬å››ç« è¯æ³•åˆ†æž - 自顶å‘下分æžæ–¹æ³•. 主è¦å†…容: è¯æ³•åˆ†æžç®€ä»‹ 三个é‡è¦çš„é›†åˆ è‡ªé¡¶å‘下分æžçš„æ¡ä»¶ 递归下é™è¯æ³•åˆ†æž LL(1) è¯æ³•åˆ†æž. è¯æ³•åˆ†æžç®€ä»‹. è¯æ³•åˆ†æžçš„功能 è¯æ³•é”™è¯¯ç±»åˆ« è¯æ³•é”™è¯¯çš„å¤„ç† è‡ªé¡¶å‘下分æžçš„基本æ€æƒ³. Parser. Token/TokenList. è¯æ³•æ ‘/è¯æ³•é”™è¯¯ä¿¡æ¯. è¯æ³•åˆ†æžå™¨çš„功能 è¯æ³•é”™è¯¯ç±»åˆ« 1) 程åºçš„开始符,è¯å¥ï¼ˆè¡¨è¾¾å¼ï¼‰çš„开始 符 ( åŽç»§ç¬¦ ) é”™ 2) æ ‡è¯†ç¬¦ï¼ˆå¸¸é‡ï¼‰é”™ï¼šè¯¥å‡ºçŽ°æ—¶æœªå‡ºçŽ° 3) 括å·ç±»é”™è¯¯ï¼šä¸åŒ¹é…   4) 分隔符错: assignment.
E N D
第四章 语法分析-自顶向下分析方法 主要内容: • 语法分析简介 • 三个重要的集合 • 自顶向下分析的条件 • 递归下降语法分析 • LL(1)语法分析
语法分析简介 • 语法分析的功能 • 语法错误类别 • 语法错误的处理 • 自顶向下分析的基本思想
Parser Token/TokenList 语法树/语法错误信息 • 语法分析器的功能 • 语法错误类别 1) 程序的开始符,语句(表达式)的开始 符(后继符)错 2) 标识符(常量)错:该出现时未出现 3) 括号类错误:不匹配 4) 分隔符错:assignment
语法错误处理 要求:报告错误出现的位置 修复错误并继续检查后续部分 执行开销不应太大 处理策略: 1)紧急方式恢复; 2)短语级恢复; 3)出错产生式; 4)全局纠正;
Z a B d b B c • 自顶向下分析基本思想 • 从文法开始符出发试图推导出所给的终极符串。 • 例 G[z] : [1] Z aBd [2] B d [3] B c [4] B bB 对给定的终极符串abcd,推导过程: Z [1] aBd [4] abBd [3] abcd 自顶向下的语法分析过程【Sf,Rest,Action(D/M/S/E)】 Z # abcd # Derivation aBd # abcd # Match Bd # bcd # Derivation bBd # bcd # Match Bd # cd # Derivation cd # cd # Match d # d # Match # # Success
三个重要的集合 • First集的定义 设G=(VT,VN,S,P)是上下文无关文法, (VT VN )*,则: First()={ aVT | * a...} (if * then {} else ) 作用:可以根据当前的输入符号是属于哪个产生式右部的首符集而决定选择相应产生式进行推导。
S a A b A S d 文法G3[S]: S aA | d A bAS | 输入串W=abd。自顶向下的推导过程为: S aA abAS abS abd 相应的语法树为:
Follow集的定义 设G=(VT,VN,S,P)是上下文无关文法,AVN,S是开始符号,则: Follow(A)={ a VT | S+ ...Aa... } (if S*...A then {#} else ) 作用:当文法中存在产生式形如:A时,如果当前的字符属于Follow(A),则用空取代A的出现。
Predict集的定义 Predict(A→) = First() , 当First() = First()-{}Follow(A) , 当First()
计算First(X)集 对每一文法符号X计算First(X) • 若XVT,First(X)={X} • 若XVN则 First(X)={a| Xa…PSet,aVT} • 若XVN,且有产生式X,则 First(X) • 若XVN,有产生式XY1Y2…Yn,且Y1,Y2,…,Yi VN,则 当Y1,Y2,…,Yi-1* , 则First(Y1)-{},First(Y2)-{},… First(Yi-1)-{}, First(Yi)都包含在First(X)中。 当Yi * (i=1,2,…n), 将{}并入First(X)中。
计算First()集 若符号串=X1X2…Xn, • 当X1,X2,…Xi-1*,Xi不能*,则 First()=1i-1(First(Xj)-{}) First(Xi) • 若所有Xi都能*,则 First()= 1nFirst(Xj)
计算Follow集 1:对所有BVN,令Follow(B):={ };对开始符S, 令Follow(S):={# }; 2:若有产生式A→xBy, 如果First(y) 则: Follow(B):= First(y) 否则 Follow(B):=(First(y)-{}) Follow(A) 3:重复2,直至对所有BVN,Follow(B)收 敛为止。
计算Predict集 Predict(A→) = First() , 当First()不含 = First()-{ } Follow(A) , 当First()含
例子 E T E’ E’ + T E’ | T F T’ T’ *F T’ | F id | ( E )
Predict( ETE’ ) = first(TE’) = { id , ( } • Predict( E’ +TE’ ) = first(+TE’) = { + } • Predict( E’ ) = follow(E’) = { ) , # } • Predict( T FT’ ) = first(FT’) = { id , ( } • Predict( T’ *FT’ ) = first(*FT’) = { * } • Predict( T’ ) = follow(T’) = { + , ) , # } • Predict( F id ) = first(id) = { id } • Predict( F (E) ) = first((E)) = { ( }
自顶向下分析的条件 • 产生式A→被选择的条件是: 当前的输入符属于predict(A→)。 • 至多一个产生式被选择的条件是: predict(A→k) predict(A→j )=,当k j • 自顶向下分析方法的条件: predict(A→k) predict(A→j )=,当k j
递归下降法 递归下降法(Recursive-Descent Parsing) 对每个非终极符按其产生式结构产生相应语法分析子程序. 终极符产生匹配命令 非终极符则产生调用命令 文法递归相应子程序也递归,所以称这种方法为递归子程序方法或递归下降法
例:Stm→ whileExpdoStm 则对应产生式右部的语法分析程序部分如下: begin Match($while); Exp; Match($do); Stm end
whilex>ydoif x>z then x:= x+y else x:= y Begin Match($while); Exp; Match($do); Stm End
当产生式中形如: A 1| 2| …| n 则按下面的方法编写子程序A: procedure A( ) begin if tokenPredict(A1) then (1) else if tokenPredict(A2) then (2) else …… if tokenPredict(An) then (n) else err( ) end 其中对i=X1X2…Xn,(i) = ’(X1);’(X2);…;’(Xn); 如果XVN,’(X)= X 如果XVT,’(X)= Match(X) 如果X= , () = skip(空语句)
假设有文法 Z →a B a B →b B |c 则相应的递归子程序可如下: procedure Z( ) begin if token=a thenMatch(a); B; Match(a) else err( ) end; ReadToken ReadToken procedure B ( ) begin if token = b thenMatch(b); B; else if token = c thenMatch(c); elseerr( ) end; 主程序:Begin ReadToken;Zend
LL分析方法 • LL(1)是LL(k)的特例,其中的k则表示向前看k个符号。 • LL(1)方法和递归下降法属于同一级别的自顶向下分析法,但有一些区别. • 递归下降法对每个非终极符产生子程序,而LL(1)方法则产生LL分析表; • 递归下降法能判断每个产生式的结束,而LL(1)方法则不能; • 递归下降法分析法不用符号栈,而LL(1)方法则用符号栈。
LL(1)分析方法的条件 对于任一非终极符A,其任意两个产生式A→和A→,都要满足下面条件: Predict(A→) Predict(A→)= 满足这一条件的文法称为LL(1)文法。
LL(1)分析例 • 文法G[A]: A a B c[1] • B d [2]| b B[3] • 输入串:abbdc • 分析过程: • (A,abbdc)1(aBc,abbdc) (Bc,bbdc) 3(bBc,bbdc) (Bc,bdc) 3 (bBc,bdc) (Bc,dc) 2 (dc,dc) (c,c) ( , )
LL(1)分析的动作 • 替换:当X1VN时选相应候选式去替换X1。 • 匹配:当X1VT时它与Y1进行匹配,其结果可能成功,也可能失败,如果成功则去掉X1和Y1,否则报错。 • 接受:当格局为(空,空)时报分析成功。 • 报错:出错后,停止分析。
LL(1)分析器的组成 • LL(1)语法分析表(LL(1)矩阵) • LL(1)语法分析驱动程序
LL(1)分析表的构造 • T:VN VT → P { Error } T(A,t)=A→若tPredict( A→ ) T(A,t)=Error 否则 其中P表示所有产生式的集合
a X Input 栈为空情形的处理 X VT情形的处理 X VN情形的处理 Stack LL[1]分析表 LL(1)分析的驱动器
LL_Driver [1] 初始化: Stack :=empty;Push(S); [2] 读下一个输入符: Read(a); [3] 若当前格局是( empty, # ),则成功结束; 否则转下; [4] 设当前格局为( X....., a.....),则 若 XVT & X=a 则{Pop(1);Read(a);goto [3] } 若 XVT & Xa 则 Error; 若 XVN,则: if T(X,a)=X→Y1Y2 … Yn then {Pop(1);Push(Y1,.....,Yn);goto[3]} else Error
LL分析实例 E T E’[1] E’ + T E’[2] | [3] T F T’[4] T’ * F T’[5] | [6] F id[7] | ( E )[8] • 文法G: 符号串 i + i * i # 的LL(1)分析过程:
Predict( [1] ) = first(TE’) = { id , ( } Predict( [2] ) = first(+TE’) = { + } Predict( [3] ) = follow(E’) = { ) , # } Predict( [4] ) = first(FT’) = { id , ( } Predict( [5] ) = first(*FT’) = { * } Predict( [6] ) = follow(T’) = { + , ) , # } Predict( [7] ) = first(id) = { id } Predict( [8] ) = first((E)) = { ( }
分析栈S 输入流T 矩阵元素 E # i + i * i # LL[ E ,i ] = [1] T E’# i + i * i # LL [ T ,i ] = [4] F T’ E’# i + i * i # LL [ F ,i ] = [7] i T’ E’ # i + i * i # Match T’ E’# + i * i # LL [ T’,+] = [6] E’# +i * i # LL [ E’,+ ] = [2] +T E’# +i * i # Match T E’# i * i # LL [ T,i ] =[4] F T’ E’# i* i # LL [ F,i ] = [7] i T’ E’# i * i # Match T’ E’# * i # LL [ T’,* ] = [5] *FT’ E’# * i # Match FT’ E’# i # LL[F,i] = [7] iT’ E’# i # Match T’ E’# # LL[T’,#] = [6] E’# # LL[E’, #] = [3] # # ok
if-then-else语句 • BL语言{ [i ]j | i j 0 }不是LL文法 • 条件语句的产生式是无法变换成LL(1)型 产生式的。