語義分析之一 屬性文法

2021-08-13 08:36:51 字數 3278 閱讀 2219

編譯原理的幾個核心階段:詞法分析、語法分析和語義分析,其實編譯的本質便是翻譯,其各個階段便是承擔不同的翻譯任務,詞法分析階段的任務是將程式輸入的字串流翻譯成語言認可的字元流(剔除空格和注釋等部分);語法分析便是將程式按照語言文法的規則構建成語法樹;語義分析便是在語法樹構建的基礎上完成語言規則的語義動作(型別檢查、作用域和可視性檢查、一致性檢查等)。

現今的程式語言絕大多數都是圖靈完備的,故而語法設計上幾乎很難出現決定性的差異,更多的語言特徵區別便是在語義動作上設計的不同所帶來的效果。其實語言的諸多優美特徵都是在語義階段新增進去的,比如c語言規定變數宣告部分必須在操作部分之前全部完成,而c++則可以在程式中隨時宣告變數,比如一些隱藏的型別轉換都是在語義分析階段完成的,所以某種意義上,語義分析也是語言設計和程式程式設計間的「銀彈」。所以相比於語法階段的樹擴充套件或圖搜尋之類的圖論知識的枯燥,語義分析階段可以看到很多和語言特性鮮活的對應關係。

我們知道,對於語言而言,無論變數、函式、過程在程式中都是用乙個識別符號來代替,但如果給定了乙個識別符號,我們如何確定這個識別符號的意義呢?其實這便引導出屬性文法的概念(其實語義分析的公式化有多種方式,比如操作語義學、公理語義學、屬性文法等,其中屬性文法最為直觀,也是當前絕大多數編譯器採用的編譯方式),比如變數有int\float\double之類的區別,那顯然給定乙個變數識別符號,必須要指明該識別符號的「資料型別屬性」,所以必須給所有識別符號配備一系列的屬性。利用識別符號的這些屬性,便可以用來配合此前構建的語法樹進行一系列的語義動作(型別檢查、可見性是否合法等)。

語義分析一般是和語法分析組合在一起執行的,語法分析完成前一步語法樹分析的構建(呼叫某個產生式完成一步規約,形成當前的樹節點),然後語義分析便接著呼叫相應產生式配備的語義動作或子程式,完成屬性文法所要求的語義動作(比如型別轉換或生成中間**)。所以對於屬性文法而言,屬性的加工和使用過程便是語義處理的意義。

形式上講,乙個屬性文法是乙個三元組,a=(g,v,f),乙個上下文無關文法g;乙個屬性的有窮集v和關於屬性的謂詞函式的有窮集f。每個斷言與文法的某產生式相聯。如果對g中的某一輸入串而言(句子),a中的所有斷言對該輸入串的語法樹結點的屬性全為真,則該串也是a語言中的句子,如下便是乙個關於屬性文法的例子

1. e→t1+t2  //謂詞,要求若是符合該產生式,則進行相加的兩元素必須都是整型

2. e→t1ort2

3. t→num //屬性加工,宣告該變數為整型,該識別符號資料型別屬性被賦值為「整型」

4. t→true

5. t→false

既然介紹完了屬性文法的屬性重要性,那麼如何利用這些屬性,便是語義分析的重要所在。下面便摘錄《編譯原理》一書中的幾個例子來演示屬性文法的語義處理加工。

1. 賦值語句的語義翻譯

(1) s→id∶=e 

(2) e→e1+e2

else

error}

(3) e→e1*e2

(4) e→-e1

(5) e→(e1)

(6) e→id ; //賦值語句

if p ≠ nil then

e.place=p.place

else error}

2. 型別轉換的語義處理

//對 e→e1*e2 進行型別轉換,比如如果int和float相乘,應該先將int轉換為float

e.place∶=newtemp;

if e1.type=int

ande2.type=int

then

begin emit(e.place,′∶=′,e1.place,′*i′, e2.place);

e.type∶=int

endelse

if e1.type=real

ande2.type=real

then

begin emit (e.place,′∶=′,e1.place,′*r′,e2.place);

e.type∶=real

endelse

if e1.type=int

ande2.type=real  then

begin t∶=newtemp;

emit(t,′∶=′,′itr′,e1.place); //先將e1通過itr操作轉換為float浮點數,利用臨時變數t儲存

emit(e.place,′∶=′,t,′*r′,e2.place);

e.type∶=real

endelse  /*e1·type=real

ande2.type=int*/

begin t∶=newtemp;

emit(t,′∶=′;′itr′,e2.place);

emit(e.place,′∶=′,e1.place,′*r′,t);

e.type∶=real

end;

3. 用數值表示bool值的語義翻譯

//有些語言中,0/1和true/false是可以混用的,有沒有奇怪為啥?其實這編譯語義分析階段的轉換工作

e→e1 or e2

{e.place∶=newtemp;

emit(e.place ′∶=′ e1.place ′or′ e2.place)}

e→e1 and e2

{e.place∶ =newtemp;

emit(e.place ′∶=′ e1.place ′and′ e2.place)}

e→not e1

{e.place∶ =newtemp:;

emit(e.place ′∶=′ ′not′ e1.place)}

e→(e1)

{e.place∶=e1.place}

e→id1 relop id2 //relop是指 < = >三操作符的任意乙個

{e.place∶=newtemp;

emit(′if′id1.place relop id2.place ′goto′ nextstat+3);

emit(e.place′∶=′′0′);

emit(′goto′nextstat+2);

emit(e.place′∶=′′1′)}

e→true

{e.place∶=newtemp;

emit(e.place′∶=′ ′1′)}//可以看到在語義翻譯階段,將true翻譯成了1

e→false

{e.place∶=newtemp;

emit(e.place ′∶=′ ′0′)}//將false翻譯成了0

基於屬性文法的語義計算

屬性文法是用來描述某些附加在乙個上下文無關文法中的屬性,這類屬性可以是值 型別 符號表的內容等等,而且這一屬性文法也帶有乙個語義規則用於描述屬性在文法中的終結符與非終結符之間所傳遞的資訊關聯。本文所要講授的是基於屬性文法的語義計算方法,乙個是通過遍歷分析樹進行語義計算 另乙個是在語法分析的同時進行語...

編譯原理 屬性文法和語義規則

乙個屬性文法形式上定義為乙個三元組 agag ag其中,g gg 表示乙個上下文無關文法。v vv 表示屬性的有窮集。e ee 表示屬性的斷言 語義規則 或謂詞的有窮集。屬性可以分為兩類 綜合屬性用於自下而上傳遞資訊 繼承屬性用於自上而下傳遞資訊 通常使用自底向上的方法,按照語義規則來計算各結點的綜...

語義分析 一

語義分析一般是和語法分析組合在一起執行的,語法分析完成前一步語法樹分析的構建 呼叫某個產生式完成一步規約,形成當前的樹節點 然後語義分析便接著呼叫相應產生式配備的語義動作或子程式,完成屬性文法所要求的語義動作 比如型別轉換或生成中間 所以對於屬性文法而言,屬性的加工和使用過程便是語義處理的意義。乙個...