編譯原理(二)——語法分析(二)

版權聲明:本文爲原創文章,未經博主允許不得用於商業用途。

語法分析

自底向上的語法分析

自底向上即從輸入字符串w產生文法開始符號S的過程,相當於從葉子節點反向構造語法分析樹。對輸入從左到右、自底向上的語法分析可以最終反向構造出一個最右推導。

歸約:將與某個產生式匹配的子串替換爲產生式頭部的非終結符號。

句柄:最右句型中和某個產生式匹配的子串,即若SrmαAwrmαβwS\underset{rm}{\Rightarrow}\alpha Aw\underset{rm}{\Rightarrow}\alpha \beta w,則β\beta就是ww的一個句柄。

  • 在最右句型中,由於按照從左到右的順序,句柄右側只有終結符號
  • 無二義性的文法中,句型的句柄唯一。

移入-歸約分析技術

移入-歸約技術中,使用一個棧保存已經歸約好的符號,開始時棧爲空(只包含$),通過不斷歸約棧中符號並移入新的符號完成自底向上的分析。且歸約時,句柄總在棧的頂部。

類似自頂向下語法分析,當語法出現二義性時會發生規約衝突,例如之前的if-then-else匹配問題,當輸入爲if-then時,分析器無法判斷後邊是否還有else語句,因此不能確定是否應該將if-else歸約爲stmt。

LR語法分析技術(簡單LR技術)

LR(k)中的LR和k分別代表從左向右掃描輸入字符、最右推導、每一步只需向前看k個輸入字符。由於可以"“向前看”,因此LR技術不需要回溯。"隨着“向前看”字符數的增加,狀態機的狀態數呈指數級增長,而k=1,2時已經可以解決絕大部分問題,因此只考慮這兩種情況。最簡單的LR技術即LR(0)LR(0)

  • :產生式加上在其中某處的一個點。(如AXYXA\rightarrow X\cdot YX,可以理解爲當前自動機已經完成了 點 前邊所有符號XX的移入/歸約,正準備解析 點 後面的符號YXYX,並且最後會規約爲​AA
  • 增廣文法:G的增光文法G’即在G中加入新的開始符號S’,和產生式SSS'\rightarrow S,而按照此產生式歸約的過程即表示已經將輸入串的所有符號規約到開始符號。
  • 項集閉包(closure):項集閉包可以看作需要自底向上構建到當前項集所需的最小項集合。
    • 對於CLOSURE(I)CLOSURE(I),初始化時I在集合中,通過不斷迭代下式計算出項集閉包:
      • 如果AαBβA\rightarrow \alpha\cdot B\beta在閉包中,且BγB\rightarrow \cdot \gamma,則將BγB\rightarrow \gamma加入到閉包中
  • GOTO函數GOTO(I,X)GOTO(I,X)表示通過I項集,接收到X後可以到達的狀態集合。(例如[AαXβ],AI[A\rightarrow \alpha\cdot X\beta],A\in I,則CLOSURE([AαXβ])CLOSURE([A\rightarrow \alpha X\cdot\beta])在集合中)
  • 項集族:項集族C表示一個增廣文法G‘所有的狀態集合,可一通過迭代下式計算:
    • 初始時,C={CLOSURE({[SS]})}C=\{CLOSURE(\{[S'\rightarrow S]\})\}
    • 對於C中的項集I,任一文法符號X,如果GOTO(I,X)GOTO(I,X)不在C中,則加入其中。

在LR(0)自動機中,每個狀態對應一個項集,如果其中:

  • 存在形如AαA\rightarrow \alpha\cdot的項,則表示可能找到了一個最右句型的句柄,接下來可以規約爲A。
  • 存在形如AαXA\rightarrow \alpha\cdot X的項,表示目前已接收的輸入如果接下來接收(移入)X則可能會規約爲A。

在實現時通過一個棧記錄已經移入/歸約的狀態序列並不斷查找分析表完成分析。

LR分析表

結構

LR分析表每行代表一個狀態,共包括兩個部分:ACTION和GOTO。

  • ACTION:ACTION部分的列表頭代表終結符,每個單元包含如下四種操作之一:
    • 移入j:將j狀態移入棧中
    • 歸約AβA\rightarrow \beta:按照此產生式將棧頂項歸約爲A
    • 接受:完成整個輸入串的分析,並接受此輸入
    • 報錯:出現語法錯誤,停止分析
  • GOTO:GOTO部分的表頭爲非終結符A,描述當前狀態接收到新歸約的A符號後的下一個狀態。則如果GOTO函數GOTO(Ii,A)=IjGOTO(I_i,A)=I_j,則GOTO[i,A]GOTO[i,A]表項爲j。
使用方法

使用LR分析表步驟如下:

  • 格局表示當前棧中內容和餘下的輸入內容,記作(s0s1...sm,aiai+1...an(s_0s_1...s_m,a_ia_{i+1}...a_n$)),可以看作時當前的上下文。分析的過程實際是格局不斷變化的過程。
  • 在當前格局,LR狀態機查找分析表ACTION[sm,ai]ACTION[s_m,a_i]獲取下一步的動作:
    • 移入s:將aia_i對應的狀態s移入棧中,並分析下一個符號,格局變爲(s0...sms,ai+1...an(s_0...s_ms,a_{i+1}...a_n$))
    • 歸約AβA\rightarrow \beta:將棧頂的β|\beta|個狀態規約爲A,進入新狀態GOTO[smr,A]GOTO[s_{m-r},A],格局變爲(s0...smrs,ai...an(s_0...s_{m-r}s,a_i...a_n$))
    • 接受
    • 報錯
  • LR分析器從初始棧s0s_0開始,不斷分析輸入,知道收到 接受/報錯 指令結束。

在這裏插入圖片描述

$\small{其中,s_i:移入狀態i,r_j:按照j產生式歸約} $

當輸入串爲idid+idid*id+id時,棧的改變如下:

  • 0
    • 初始棧中狀態爲0,下一個符號爲ididACTION[0,id]=s5ACTION[0,id]=s5,移入狀態5,格局中輸入變爲id+id*id+id$,接受符號爲idid
  • 0,5
    • ACTION[5,]=r6ACTION[5,*]=r6,因此按照產生式6(FidF\rightarrow id)歸約,接受符號變爲FF,回退並壓入GOTO[0,F]=3GOTO[0,F]=3,格局中輸入不變
  • 0,3
    • ACTION[3,]=r4ACTION[3,*]=r4,按照產生式4(TFT\rightarrow F)歸約,接受符號變爲TT,回退並壓入GOTO[0,T]=2GOTO[0,T]=2
  • 0,2
    • ACTION[2,]=s7ACTION[2,*]=s7,移入狀態7,格局中輸入變爲id+idid+id$,接受符號爲TT*
  • 0,2,7
    • ACTION[7,id]=s5ACTION[7,id]=s5,移入狀態5,格局中輸入變爲+id+id$,接受符號爲TidT*id

\vdots

  • 0,1
    • ACTION[1,ACTION[1,$]]=acc$,接受輸入,分析完成

構造SLR語法分析表

構造方法如下:

  • 首先構造G’的LR(0)項集規範族{I0,I1,...In}\{I_0,I_1,...I_n\}
  • 構造狀態i項集IiI_i對應的ACTION部分:
    • [Aαaβ]Ii[A\rightarrow\alpha\cdot a\beta]\in I_i,且GOTO(Ii,a)=IjGOTO(I_i,a)=I_j,則應該執行移入操作,ACTION[i,a]=jACTION[i,a]=移入j
    • [Aα]Ii[A\rightarrow\alpha\cdot]\in I_i,應該執行歸約,則對於FOLLOW(A)FOLLOW(A)中的所有a,ACTION[i,a]=AαACTION[i,a]=按照A\rightarrow\alpha歸約
    • [SS]Ii[S'\rightarrow S\cdot]\in I_i,則ACTION[i,ACTION[i,$]=acc=acc
  • 構造GOTO部分。
  • 將表中剩餘部分都填入errorerror

如果在構造SLR表過程中沒有衝突,則該文法爲SLR的。

更強大的LR語法分析器(LR(1))

考慮如下情況:項[Aα][A\rightarrow \alpha\cdot]出現在IiI_i中的條件爲BβAγB\rightarrow \beta\cdot A\gamma在項集中。

因此假設FOLLOW(A)={a}FIRST(γ)FOLLOW(A)=\{a\}\cup FIRST(\gamma),則按照當前語法,當A下一個符號爲FIRST(γ)FIRST(\gamma)時,可以歸約;當下一個符號爲a時,不應該進行歸約。

而LR(0)無法完成正確歸約。

因此需要往前預看一位符號的更強大分析器LR(1)解決此類規約問題。在LR(1)中可以根據下一個待分析符號準確判斷是否應該歸約。

  • :LR(1)中的項包含下一個符號,即形如[Aαβ,a][A\rightarrow \alpha\cdot \beta,a],a爲下一個符號,可以爲終結符或結束符$
  • 歸約:歸約時,下一項必須爲a時纔可以歸約
  • 移入:當β\beta不爲空時,不許考慮a,直接將a傳遞給下一個狀態。
  • CLOSURE:當由[AαBβ,a][A\rightarrow \alpha\cdot B\beta,a]加入[Bθ,b][B\cdot \theta,b]時,b需要爲下一個可接受字符,即FIRST(βα)FIRST(\beta\alpha)

LR(1)爲每一個向前看符號構造了新的狀態,可以看作比LR(0)多了一個自由度,因此狀態數多許多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章