編譯器設計-自下而上分析器-誤差恢復-語義分析

編譯器設計-自下而上分析器-誤差恢復-語義分析

Compiler Design - Bottom-Up Parser

Compiler Design - Error Recovery

Compiler Design - Semantic Analysis

一.Compiler Design - Bottom-Up Parser

自底向上的解析從樹的葉節點開始,向上工作直到到達根節點。在這裏,我們從一個句子開始,然後以相反的方式應用產生式規則,以達到開始符號。下面給出的圖像描述了可用的自下而上的解析器。
在這裏插入圖片描述
移位減少分析

Shift-reduce解析使用兩個獨特的步驟進行自底向上的解析。這些步驟稱爲移位步驟和減少步驟。

移位步驟:移位步驟是指輸入指針向前移動到下一個輸入符號,稱爲移位符號。這個符號被推到堆棧上。移位的符號被視爲解析樹的單個節點。

Reduce step:當解析器找到一個完整的語法規則(RHS)並將其替換爲(LHS)時,稱爲reducestep。當堆棧頂部包含句柄時發生這種情況。爲了減少,在堆棧上執行POP函數,該函數從句柄彈出,並用LHS非終端符號替換它。

LR分析器

LR解析器是一個非遞歸、移位減少、自底向上的解析器。它使用了大量的上下文無關語法,這使得它成爲最有效的語法分析技術。L R解析器也稱爲LR(k)解析器,其中L表示從左到右掃描輸入流;R表示反向構造最右邊的派生,k表示要做出決策的先行符號的數量。

有三種廣泛使用的算法可用於構造LR解析器:

SLR(1)
– Simple LR Parser:

Works on smallest class of grammar Few number of states, hence very small table Simple and fast construction

LR(1) – LR Parser:

Works on complete set of LR(1) Grammar Generates large table and large number of states Slow construction

LALR(1) – Look-Ahead LR Parser:

Works on intermediate size of grammar
Number of states are same as in SLR(1)

LR解析算法

這裏我們描述一個LR解析器的骨架算法:

token = next_token()

repeat forever

s = top of stack

if action[s, token] = “shift si” then

  PUSH token

  PUSH si 

  token = next_token()

else if action[s, token] = “reduce A::= β“ then

  POP 2 * |β| symbols

  s = top of stack

  PUSH A

  PUSH goto[s,A]

else if action[s, token] = “accept” then

  return

else

  error()

LL vs. LR
在這裏插入圖片描述
二.Compiler Design - Error Recovery

解析器應該能夠檢測並報告程序中的任何錯誤。當遇到錯誤時,解析器應該能夠處理它並繼續解析其餘的輸入。大多數情況下,解析器需要檢查錯誤,但在編譯過程的各個階段可能會遇到錯誤。一個程序在不同階段可能有以下幾種錯誤:

詞法:某個標識符的名稱鍵入不正確

語法:缺少分號或括號不平衡

語義:不兼容的值賦值

邏輯:代碼不可訪問,無限循環

可以在解析器中實現四種常見的錯誤恢復策略來處理代碼中的錯誤。

緊急模式

當解析器在語句中的任何地方遇到錯誤時,它將忽略語句的其餘部分,不處理從錯誤輸入到分隔符(如分號)的輸入。這是最簡單的錯誤恢復方法,而且還可以防止解析器開發無限循環。

語句模式

當解析器遇到錯誤時,它會嘗試採取糾正措施,以便語句的其餘輸入允許解析器提前解析。例如,插入一個缺少的分號,用分號替換逗號等等。解析器設計者在這裏必須小心,因爲一個錯誤的更正可能導致無限循環。

錯誤產品

編譯器設計器知道代碼中可能出現的一些常見錯誤。此外,設計人員可以創建要使用的擴充語法,作爲在遇到錯誤時生成錯誤構造的產品。

整體校正

解析器將手邊的程序視爲一個整體,並試圖找出程序的意圖,並試圖找出與之最接近的匹配項,這是無錯誤的。當錯誤的輸入(語句)X被饋送時,它會爲某個最接近的無錯誤語句Y創建一個解析樹。這可能允許解析器對源代碼進行最小的更改,但由於此策略的複雜性(時間和空間),它尚未在實踐中實現。

抽象語法樹

解析樹表示不容易被編譯器解析,因爲它們包含的細節比實際需要的多。以下面的解析樹爲例:
在這裏插入圖片描述
如果仔細觀察,我們會發現大多數葉節點都是父節點的單個子節點。在將信息傳送到下一階段之前,可以消除這些信息。通過隱藏額外信息,我們可以獲得如下所示的樹:
在這裏插入圖片描述
Abstract tree can be represented as:
在這裏插入圖片描述
ASTs是編譯器中重要的數據結構,具有最少的不必要信息。ASTs比解析樹更緊湊,編譯器可以很容易地使用它。

三.Compiler Design - Semantic Analysis

在語法分析階段,我們學習瞭解析器如何構造解析樹。在那個階段構造的純解析樹通常對編譯器沒有用處,因爲它不攜帶任何關於如何計算樹的信息。上下文無關語法的產生,決定了語言的規則,不適應如何解釋它們。

For example

E → E + T

上面的CFG產品沒有與之相關聯的語義規則,它無法幫助理解產品。

語義學

語言的語義爲其結構提供了意義,如標記和語法結構。語義有助於解釋符號、它們的類型以及它們之間

CFG + semantic rules = Syntax Directed Definitions

For example:

int a = “value”;

不應在詞彙和語法分析階段出現錯誤,因爲它在詞彙和結構上都是正確的,但應在賦值類型不同時產生語義錯誤。這些規則由語言的語法設定,並在語義分析中進行評估。語義分析應完成以下任務:

範圍分辨率

類型檢查

數組綁定檢查

語義錯誤

我們已經提到了一些語義分析器需要識別的語義錯誤:

類型不匹配

未聲明的變量

保留標識符誤用。

作用域中變量的多重聲明。

訪問範圍外變量。

實際參數與形式參數不匹配。

屬性語法

屬性語法是上下文無關語法的一種特殊形式,它將一些附加信息(屬性)附加到一個或多個非終端,以提供上下文敏感信息。每個屬性都有定義良好的值域,如integer、float、character、string和expressions。

屬性語法是爲上下文無關語法提供語義的一種媒介,它可以幫助指定編程語言的語法和語義。屬性語法(當被視爲解析樹時)可以在樹的節點之間傳遞值或信息。

Example:

E → E + T { E.value = E.value + T.value }

CFG的右邊部分包含語義規則,這些規則指定如何解釋語法。這裏,將非終端E和T的值相加,結果被複制到非終端E。

語義屬性可以在解析時從其域中分配給其值,並在分配或條件時進行計算。根據屬性獲取值的方式,它們可以大致分爲兩類:合成屬性和繼承屬性。

綜合屬性

這些屬性從其子節點的屬性值中獲取值。爲了說明這一點,假設以下產品:

S → ABC

如果S從它的子節點(A、B、C)中獲取值,則它被稱爲合成屬性,因爲ABC的值被合成爲S。

如前一個示例(E→E+T)所示,父節點E從其子節點獲取其值。合成屬性從不從其父節點或任何同級節點獲取值。

繼承的屬性

與合成屬性不同,繼承屬性可以從父屬性和/或兄弟屬性中獲取值。在接下來的製作中,

S → ABC

A可以從S、B和C中獲取值。B可以從S、A和C中獲取值。同樣,C可以從S、A和B中獲取值。

擴展:根據語法規則將非終端擴展爲終端時
在這裏插入圖片描述
歸約:根據語法規則將一個終端歸約爲其對應的非終端。語法樹從上到下和從左到右進行分析。每當進行約簡時,我們都會應用相應的語義規則(動作)。

語義分析使用語法導向的翻譯來執行上述任務。

語義分析器從其前一階段(語法分析)接收AST(抽象語法樹)。

語義分析器將屬性信息附加到AST中,稱爲屬性AST。

屬性是兩個元組值,<attribute name,attribute value>

For example:

int value = 5;<type, “integer”><presentvalue, “5”>

對於每個產品,我們都附加一個語義規則。

S屬性SDT

如果SDT只使用合成屬性,則稱爲S屬性SDT。這些屬性使用S屬性的SDTs進行評估,這些sdt在產品(右側)之後編寫語義操作。
在這裏插入圖片描述
如上所述,S屬性的sdt中的屬性在自下而上的解析中求值,因爲父節點的值依賴於子節點的值。

L屬性SDTs

這種形式的SDTs既使用合成屬性,也使用繼承屬性,並且限制不從正確的兄弟節點獲取值。

在L屬性的SDTs中,非終端可以從其父節點、子節點和同級節點獲取值。在下面的生產中

S → ABC

S可以取A、B和C(合成)的值。A只能從S獲取值。B可以從S獲取值,A可以從S、A和B獲取值。任何非終端都不能從其右邊的同級中獲取值。

L屬性SDT中的屬性是通過深度優先和從左到右的解析方式計算的。
在這裏插入圖片描述
我們可以得出結論,如果一個定義是S屬性的,那麼它也是L屬性的,因爲L屬性的定義包含S屬性的定義。

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