語法分析

語法分析器

語法分析器作用

  1. 從詞法分析器獲得單元的序列,確認該是否可以由語言文法生成
  2. 對於語法錯誤的程序,報告錯誤信息
  3. 對於語法正確的程序,生成分析樹 (簡稱語法樹 )

語法分析的任務

  1. 從詞法分析中獲得的每個屬性字(token)在語句或程序中是什麼作用
  2. 檢查語句或程序是否符合程序語言的語法

語法分析器分類

  1. 自頂向下語法分析器(處理LL文法):從語法分析樹的根部開始構語法分析樹,推導式
  2. 自底向上語法分析器(處理LR文法):從語法分析樹的葉子開始構語法分析樹,規約式

上下文無關文法與正則文法

一個上下文無關文法(CFG)包括四部分:

  1. 終結符號(terminal)的集合T
  2. 非終結符號(nonterminal)的集合N
  3. 唯一的開始符號S(S ∈ N)
  4. 若干以下形式的產生式(production):XY1Y2...Yn\rightarrow Y_1Y_2...Y_n
    其中X∈N 且Y ∈TN{ε}T\cup N \cup \{ \varepsilon \}

區別: 正則表達式無法定義 L={anbnn1}L=\{ a^nb^n| n\geq1 \},上下文無關語言可以:S \rightarrow 0 EXPR 1
EXPR \rightarrow 0 EXPR 1 | ε

NFA轉爲上下文無關文法

  1. 右線性文法:A\rightarrowaB , A\rightarrowa ,Aε\rightarrow \varepsilon
  2. 左線性文法:A\rightarrowBa , A\rightarrowa ,Aε\rightarrow \varepsilon

推導與規約

  1. 推導(derivation):從開始符號開始,每一步推導就是用一個產生式的右方取代左端的非終端符號
  • 最左推導:每步推導都替換最左邊的非終結符號
  • 最右推導:每步推導都替換最右邊的非終結符號

二義性

  1. 文法的二義性:如果對於一個文法,存在一個句子,對這個句子可以構造兩棵不同的分析樹,那麼我們稱這個文法爲二義的.
  2. 原因:最左推導和最右推導可以構造出兩顆不同的分析樹
  3. 消除二義性例子

遞歸下降分解

  1. 消除二義性(只有一棵分析樹),消除左遞歸(消除A=>Aa),提取左公因子
  2. 判斷是否爲LL(1),是則提取預測分析表,不是則不用遞歸下降來實現語法分析

自頂向下無法處理左遞歸的情況,需要消除左遞歸;自底向上可以處理左遞歸

消除左遞歸

  1. AAaB\rightarrow Aa|B可以消除爲: ABAA \rightarrow BA', AaAεA' \rightarrow aA'| \varepsilon
  2. 例子
  1. 多步左遞歸:由於兩步或多步推導而產生的左遞歸(S->A, A->S),化爲只有一條左遞歸

提取左公因子

  1. 方法:對每個非終結符號A找出它的可選產生式的最長公共前綴
  2. 例子

LL(n)

當前面步驟完成後,利於AAbcBca\rightarrow Abc |Bca,我們仍然是不知道要選擇哪個產生式,但是我們可以偷看輸入符號,偷看後幫助我們來選定產生式,LL(1)表示偷看1位,LL(n)表示偷看n位

LL(1)

  1. FIRST集
  • first(a)表示可以從a推導得到的串的首符號的集合

  • 求first(X)算法

    • 如果X是終結符號,first(X)={X},否則
    • XY1Y2...Yi\rightarrow Y_1Y_2...Y_i,first(YiY_i)也屬於first(X),如果i可能爲ε\varepsilon,first(Yi+1Y_{i+1})也屬於first(X),ε\varepsilon也屬於first(X)
  • 求右邊產生式的first(X1X2...XnX_1X_2...X_n

    • 加入first(X1X_1)非ε\varepsilon的符號
    • 如果first(X1X_1)有ε\varepsilon, first(X2X_2)非ε\varepsilon的符號也加入以此類推
  1. FOLLOW集
  • follow(A):跟在A右邊的終結符號的集合,可以幫助我們選擇恰當的產生式
  • 求follow算法
    - 將右端結束標記$加入follow集
    - 如果存在產生式 AaBβA \rightarrow aBβ, 那麼first(β)的所有非 ε\varepsilon 都加入到follow(B)中
    - 如果存在產生式 AaBβA \rightarrow aBβAaBA \rightarrow aB且first(β)包含 ε\varepsilon,那麼follow(A)的所有符號 都加入到follow(B)中
  1. LL(1)定義:第一個L表示輸入字符串從最左開始掃描,第二個L表示得到的推導是最左推導
    對文法的任意兩個不同的產生式AαβA \rightarrow α|β
  • 不存在終結符號a可以使得α和β都可以推導出以a開頭的串,α和β最多隻有一個可以推導出空串
  • 如果β可以推導出空串,那麼a不能推導出以follow(A)中讓你和終結符號開頭的串

等價於

  • first(α)\cap first(β)= ϕ\phi
  • ε\varepsilon∈first(β),那麼first(α)\cap follow(A)= ϕ\phi
  1. 構造預測分析表M步驟: 對每個產生式A\rightarrowa
  • 對first(A)的每個終結符號a,將產生式A\rightarrowa 加入到分析表M【A,a】
  • 如果first(A)中有ε\varepsilon ,那麼將follow(A)中的每個符號b都將產生式AεA \rightarrow \varepsilon加入到預測分析表M【A,b】中

例子

判斷是不是LL(1)文法:LL(1)文法沒有二義性,如果是二義文法,預測分析表中【X,i】會出現兩個產生式

  1. 分析表驅動的預測分析表:輸入緩衝區爲w$,壓入棧中爲S$, 根據預測分析表M,S遇到每個w是進行匹配還是輸出產生式,直到棧中爲空或報錯

例子

自底向上語法分析(串w規約爲文法開始符號S)

  1. 歸約:一個與某產生式體相匹配的特定子串被替換爲該產生式頭部的非終結符號
  2. 句柄:如果S=>aAw=>aβw,那麼緊跟a之後的β就是A\rightarrowβ的一個句)

如果文法沒有二義性,那麼每個句型都有且只有一個句柄
句柄右邊只有終結符號(小寫)
句子是不包含非終結符號的句型,句型可能包含非終結符號或終結符號或空串

  1. 移入規約分析
  • 使用棧保存歸約/掃描移入的文法符號:開始是$——輸入w$——結束$S
  • 移入:將下一個輸入符號移入到棧頂
  • 歸約:將句柄歸約到對應的非終結符號(A\rightarrowβ)
  • 規約分析例子:
    • id爲句柄,(F id1\rightarrow id_1),將id歸約
    • 移入下一個輸入符號id2id_2

LR(n)

  1. L表示最左掃描,R表示反向構造出最右推導,n表示最多向前看n個符號

LR語法分析表

  1. LR語法分析表的結構:
  • ACTION表項:狀態1,2,,,i; 終結符號a,,,

    • 移入:移入狀態j,把j壓入棧,將a移入
    • 歸約AβA \rightarrow β:將棧頂的β(句柄)歸約到A,根據GOTO表項壓入新狀態
    • 接受:接受輸入完成分析acc
    • 報錯:輸入發現語法錯誤err
  • GOTO表項:[IiI_i,A]=IjI_j,遇到非終結符號A從狀態i跳到狀態j

  1. 例子分析
  • 輸入移入id(狀態0),根據分析表跳到狀態s5s_5
  • 根據r6Fidr_6:F \rightarrow id歸約成F,根據GOTO[0,F]跳轉狀態3
  • 根據r4TFr_4:T \rightarrow F歸約成T,根據GOTO[0,F]跳轉狀態2
  • 繼續直到E$,acc
  1. LR(0)
    (1)增廣文法
    增廣文法
    (2)項集閉包CLOSURE:如果AαBβA\rightarrow α\cdot Bβ表示希望接下來的串是由Bβ推導出的串,首先是B推導出來的字串,因此加上B的各個產生式對應的項
  • 如果AαBβA\rightarrow α\cdot Bβ,B的產生式項有BγB\rightarrow γ,但BγB\rightarrow γ不在CLOSURE(I)中就加入CLOSURE(I)中
  • 將I中的各個項加入到CLOSURE(I)中

(3)項集規範族構造例子
在這裏插入圖片描述

(4)根據規範LR(0)構造LR(0)自動機

  • 初始狀態爲CLOSURE({SSS'\rightarrow \cdot S})對應的項集
  • 每個項集對應LR(0)自動機的一個狀態
  • 如果GOTO(I,X)=J,那麼從I到J有一個標號爲X的轉換

(5)根據LR(0)自動機分析
LR(0)自動機分析串

  • I0I_0開始取id,根據自動機跳轉到狀態5(I5I_5
  • I5I_5FidF\rightarrow \cdot id,知道句柄歸約爲F,返回I0I_0跳轉I3I_3
  • I3I_3TFT\rightarrow F\cdot,知道句柄歸約爲T,返回I0I_0跳轉I2I_2
  • 移入下一個 *,根據I2I_2中知道跳轉I7I_7
  • 移入下一個 idid,根據I7I_7中知道跳轉I5I_5
  • I5I_5FidF\rightarrow \cdot id,知道句柄歸約爲F,返回I7I_7跳轉I10I_{10}
  • I10I_{10}TTFT\rightarrow T*F\cdot,知道句柄歸約爲T,返回 I2I_2
  • I2I_2ETE\rightarrow T\cdot,知道句柄歸約爲E,返回 I0I_0 接受
    分析的步驟

LR(0)中可能存在歸約與移入的衝突,所以引入SLR確定應該進行移入還是歸約,例如存在E’->E(應該進行歸約),E->E+n(應該進行移入),所以遇到E時應該進行歸約還是移入,引入SLR1當$的時候歸約,+時候移入,只是狀態表中多了個接受狀態acc

  1. SLR(1)
    S表示簡單,L表示最左掃描,R表示反向構造出最右推導,n表示最多向前看n個符號
    (1)基本思想:要把α歸約成A,後面必須是follow(A)中的終結符號,否則只能移入
    (2)構造語法分析表算法:
    構造算法

(3)判斷是不是SLR(1):構造出來的項集是否有衝突(某個時刻存在兩個有效項要求執行不同的動作)

例子: SL=RRL\rightarrow L\cdot=R 和R \rightarrow L\cdot,一個遇到L後要求移入(β2β_2爲空),一個要求歸約(β2β_2不爲空)

有效項:存在一個推導過程S到αAw=>αβ1β2αβ_1β_2,那麼說Aβ1β2A \rightarrow β_1 \cdot β_2是可行前綴αβ1αβ_1的有效項
如果Aβ1β2A \rightarrow β_1 \cdot β_2是可行前綴αβ1αβ_1的有效項:
如果β2β_2不爲空的時候說明句柄尚未出現在棧中,應該移入
如果β2β_2等於空的時候說明句柄已經出現在棧中,應該歸約

SLR(1)引入LR(1)是因爲SLR中可能也存在着兩種衝突,第一種是移入與歸約的衝突(與LR(0)中的不一樣)例如I->if S ; I->S else S, 而且follow(I)={$,else},此時遇到else應該進行歸約,但是下面 I->S else S遇到else應該移入所以衝突;
另一種衝突是歸約與歸約衝突如A->a,B->a;此時應該歸約爲哪個

  1. LR(1):精確的說明了應該何時歸約
    L表示最左掃描,R表示反向構造出最右推導,n表示最多向前看n個符號
    (1) [A αβa\rightarrow α\cdotβ,a]:a表示要向前看的符號,按照A $\rightarrow $αβ進行歸約
發佈了92 篇原創文章 · 獲贊 40 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章