抽象語法樹(AST)


 

1.簡介

抽象語法樹(abstract syntax code,AST)是源代碼的抽象語法結構的樹狀表示,樹上的每個節點都表示源代碼中的一種結構,這所以說是抽象的,是因為抽象語法樹並不會表示出真實語法出現的每一個細節,比如說,嵌套括號被隱含在樹的結構中,並沒有以節點的形式呈現。抽象語法樹並不依賴於源語言的語法,也就是說語法分析階段所采用的上下文無文文法,因為在寫文法時,經常會對文法進行等價的轉換(消除左遞歸,回溯,二義性等),這樣會給文法分析引入一些多余的成分,對后續階段造成不利影響,甚至會使合個階段變得混亂。因些,很多編譯器經常要獨立地構造語法分析樹,為前端,后端建立一個清晰的接口。

 

百度百科版本

 

在計算機科學中,抽象語法樹(Abstract Syntax Tree,AST),或簡稱語法樹(Syntax tree),是源代碼語法結構的一種抽象表示。它以樹狀的形式表現編程語言的語法結構,樹上的每個節點都表示源代碼中的一種結構。
之所以說語法是“抽象”的,是因為這里的語法並不會表示出真實語法中出現的每個細節。比如,嵌套括號被隱含在樹的結構中,並沒有以節點的形式呈現;而類似於if-condition-then這樣的條件跳轉語句,可以使用帶有兩個分支的節點來表示。和抽象語法樹相對的是具體語法樹(通常稱作分析樹)。一般的,在源代碼的翻譯和編譯過程中,語法分析器創建出分析樹。一旦AST被創建出來,在后續的處理過程中,比如語義分析階段,會添加一些信息。

 

2.實例

 

  • 四則運算表達式:1+3*(4-1)+2

 

其抽象語法樹為:

 

 

  • 代碼1:

 

<letter>
  <address>
    <city>ShiChuang</city>
  </address>
  <people>
    <id>12478</id>
    <name>Nosic</name>
  </people>
</letter>

 

其抽象語法樹為:

 

 

  • 代碼2:

 

while b != 0
{
    if a > b
        a = a-b
    else
        b = b-a
}
return a

 

其抽象語法樹為:

 

 

  • 代碼3:

 

sum=0
for i in range(0,100)
    sum=sum+i
end

 

其抽象語法樹為:

 

 

3.為什么需要抽象語法樹

 

當在源程序語法分析工作時,是在相應程序設計語言的語法規則指導下進行的。語法規則描述了該語言的各種語法成分的組成結構,通常可以用所謂的前后文無關文法或與之等價的Backus-Naur范式(BNF)將一個程序設計語言的語法規則確切的描述出來。前后文無關文法有分為這么幾類:LL(1),LR(0),LR(1), LR(k) ,LALR(1)等。每一種文法都有不同的要求,如LL(1)要求文法無二義性和不存在左遞歸。當把一個文法改為LL(1)文法時,需要引入一些隔外的文法符號與產生式。

 

例如,四則運算表達式的文法為:

 

文法1.1:

 

E->T|EAT
T->F|TMF
F->(E)|i
A->+|-
M->*|/

 

改為LL(1)后為:

 

E->TE'
E'->ATE'|e_symbol
T->FT'
T'->MFT'|e_symbol
F->(E)|i
A->+|-
M->*|/

 

例如,當在開發語言時,可能在開始的時候,選擇LL(1)文法來描述語言的語法規則,編譯器前端生成LL(1)語法樹,編譯器后端對LL(1)語法樹進行處理,生成字節碼或者是匯編代碼。但是隨着工程的開發,在語言中加入了更多的特性,用LL(1)文法描述時,感覺限制很大,並且編寫文法時很吃力,所以這個時候決定采用LR(1)文法來描述語言的語法規則,把編譯器前端改生成LR(1)語法樹,但在這個時候,你會發現很糟糕,因為以前編譯器后端是對LL(1)語樹進行處理,不得不同時也修改后端的代碼。

 

抽象語法樹的第一個特點為:不依賴於具體的文法。無論是LL(1)文法,還是LR(1),或者還是其它的方法,都要求在語法分析時候,構造出相同的語法樹,這樣可以給編譯器后端提供了清晰,統一的接口。即使是前端采用了不同的文法,都只需要改變前端代碼,而不用連累到后端。既減少了工作量,也提高的編譯器的可維護性。

 

抽象語法樹的第二個特點為:不依賴於語言的細節。在編譯器家族中,大名鼎鼎的gcc算得上是一個老大哥了,它可以編譯多種語言,例如c,c++,java,ADA,Object C, FORTRAN, PASCAL, COBOL等等。在前端gcc對不同的語言進行詞法,語法分析和語義分析后,產生抽象語法樹形成中間代碼作為輸出,供后端處理。要做到這一點,就必須在構造語法樹時,不依賴於語言的細節,例如在不同的語言中,類似於if-condition-then這樣的語句有不同的表示方法

 

在c中為:

 

if(condition)
{
    do_something();
}

 

 在fortran中為:

 

If condition then
    do_somthing()
end if

 

在構造if-condition-then語句的抽象語法樹時,只需要用兩個分支節點來表於,一個為condition,一個為if_body。如下圖:

 

 

在源程序中出現的括號,或者是關鍵字,都會被丟掉。

如果覺得此篇文章對你有幫助,關注我的公眾號【人人皆是程序員】就是對我最大的鼓勵與認可!

 

把你的手放在滾熱的爐子上一分鍾,感覺起來像一小時。坐在一個漂亮姑娘身邊整整一小時,感覺起來像一分鍾。這就是相對論。

——愛因斯坦


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM