PLP: 4.2/4.3 Attribute Gramma閱讀筆記3

構造AST在compiler中是否是一個必不可少的步驟? 由於attribute grammar和one-pass compiler或者說語法制導翻譯(syntax-directed translation,SDT)聯繫很緊密,所以attribute grammar和這個問題有存在間接的的關係。

答案是構造AST並不是一個必要的步驟(可以思考構造AST的目的是什麼),甚至在計算機資源極其有限的幾十年前,one-pass compiler還是一個比較普遍的做法。

什麼是Attribute Grammars

Attribute Grammars were invented by Donald Knuth as a way to unify all of the stages of compiling into one. They give a formal way to pass semantic information (types, values, etc.) around a parse tree.

注:再次跪拜Don Knuth大神

首先attribute grammars被提出來用於將多個編譯步驟整合成一個,例如你要編譯數學表達式(3+4)3(3 + 4) * 3,此時就沒有必要生成AST併爲其生成binary了。“attribute grammar + 語法制導”就直接將該表達式的值evaluate出來了。針對應用場景使用合適的方法纔是王道,否則就可能像見識少的我一樣,把特例當做通用解法使用

Attribute Grammar爲何能夠做到將不同的編譯階段整合成一個呢?Attribute Grammar就是在Grammar上擴充了Attriute的文法,核心就在於這些Attribute。Attribute可以是類型,可以中間代碼,也可以是表達式的值。我們就可以根據這些attributed的文法,將類型檢查,中間代碼生成以及表達式求值融合到parser中。甚至於一些constant folding,available expressioin也可以融合進去。

Attribute Grammar的核心在於這些Attribute,而關於Attribute如何定義以及如何evaluate則視問題不同而不同

下面我摘PLP中的一個AG的示例,簡單的複述一下整個過程。
EE+TE \rightarrow E+T
EETE \rightarrow E-T
ETE \rightarrow T
TTFT \rightarrow T*F
TT÷FT \rightarrow T\div F
TFT \rightarrow F
FFF \rightarrow -F
F(E)F \rightarrow (E)
FdigitF \rightarrow digit

上面的文法用於生成一個數學運算式,我們可以在其上附着一些attribute,如下所示:
1. E1E2+T1.\ E_1 \rightarrow E_2 + T
Attribute: E1.val:=sum(E2.val,T.val)\rhd E_1.val := sum(E_2.val, T.val)

2. E1E2T2.\ E_1 \rightarrow E_2 - T
Attribute: E1.val:=difference(E2.val,T.val)\rhd E_1.val := difference(E_2.val, T.val)

3. ET3.\ E \rightarrow T
Attribute: E.val:=T.val\rhd E.val := T.val

4. T1T2F4.\ T_1 \rightarrow T_2 * F
Attribute: T1.val:=product(T2.val,F.val)\rhd T_1.val := product(T_2.val,F.val)

5. T1T2÷T5.\ T_1 \rightarrow T_2 \div T
Attribute: T1.val:=quotient(T2.val,F.val)\rhd T_1.val := quotient(T_2.val,F.val)

6. TF6.\ T \rightarrow F
Attribute: T.val:=F.val\rhd T.val := F.val

7. F1F27.\ F_1 \rightarrow -F_2
Attribute: F1.val:=additiveinverse(F2.val)\rhd F_1.val := additive_inverse(F_2.val)

8. F(E)8.\ F \rightarrow (E)
Attribute: F.val:=E.val\rhd F.val := E.val

9. Fdigit9.\ F \rightarrow digit
Attribute: F.val:=digit.val\rhd F.val := digit.val

使用\rhd開頭的可以稱爲Semantic Functions(與PLP稍有不同),針對上述AG,這些semantic functions只是簡單的數學運算,它們的參數都來源於當前文法內部。

至此我們就可以知道Attriubte Grammar的作用是將***文法和一些有意義的sematic function粘和起來***。這些semantic function都是人爲賦予的,我們同樣可以在代碼生成階段,將sematic function替換爲一段段machine code。

Evaluate Attributes

PLP將evaluate attribute稱作Parse Tree的annotation(或decoration),一個簡單的示例如下圖所示:
示例
注:圖片摘自PLP 4.3

從上圖中我們可以看到整個evaluate的過程就是後序遞歸下降,最終我們得到結果8,這個Parse Tree不是必須的,並且運算符號的優先級已經在parse的時候隱含的處理了。

Synthesized Attributes

對於數學運算式對應的Attribute Grammar,我們可以稱之爲Synthesized Attributes

Syntathesized Attributes: their values are calculated (synthesized) only in productions in which their symbol appears on the left-hand side. This means that the attribute flow - the pattern in which information moves from node to node - is entirely bottom-up.

Synthesized Attributes又稱之爲S-attribute,龍書翻譯成綜合屬性和S屬性,注意終結符的屬性值來源於scanner。

Inherited Attributes

與Synthesized Attributes對應的另外一種屬性是Inherited Attributes,又稱之爲L屬性(L意思是Left-To-Right)。

In general, we can imagine attributes whose values are calculated when their symbol is on the right-hand side of the current production. Such attributes are said to be inherited.

Inherited Attributes能夠將context information從上至下,從左至右進行傳遞,一個比較典型的Inherited Attributes應用是Symbol Table和Type check。

下面給出一個既含有S屬性又包含L屬性的例子,這個例子主要用於automatic type evaluation,stst表示symbol table。

1. S::=DEC1.\ S::=DEC
Attribute:  S.st=DEC.st\rhd\ S.st=DEC.st

2. S::=S1 DEC2.\ S::=S_1\ DEC
Attribute:  S.st=S1.st+DEC.st\rhd\ S.st=S_1.st + DEC.st

3. DEC::=T L3.\ DEC::=T\ L
Attribute:  L.type=T.type;DEC.st=L.st\rhd\ L.type=T.type;DEC.st=L.st

4. T::=int4.\ T::=int
Attribute:  T.type=int\rhd\ T.type=int

5. T::=string5.\ T::=string
Attribute:  T.type=string\rhd\ T.type=string

6. L::=id6.\ L::=id
Attribute:  L.st=(id.name,L.type)\rhd\ L.st=(id.name, L.type)

7. L::=L1,id7.\ L::=L_1, id
Attribute:  L1.type=L.type;L.st=L1.st+(id.name,L.type)\rhd\ L_1.type=L.type;L.st=L_1.st + (id.name, L.type)

其中屬性ststS屬性,而屬性typetypeL屬性。對於下面的兩行代碼,對應的decorated tree如下所示。

int a, b, c;
string s;

在這裏插入圖片描述
從上圖中我們可以清楚的看到,L屬性typetype沿着topbottomtop\rightarrow bottomleftrightleft\rightarrow right傳遞,S屬性stst沿着bottomupbottom\rightarrow up的方式傳遞。

在parse的時候這裏有一個準則,
When we get to a node during parsing,

  • we must have all of the information we need to evaluate its inherited attributes.
  • Before we leave the node we must have all of the information we need to evaluate its synthesized attributes.

讀書的重點在於思考和理解,否則無疑是向腦子裏傾倒垃圾

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