可配置文法分析器開發紀事(四) 構造一個真正能用的狀態機器(上)

來源:互聯網
上載者:User

本來說這一篇文章要把構造確定性狀態機器和look ahead講完的,當我真正要寫的時候發現東西太多,只好分成兩篇了。上一篇文章說道一個基本的狀態機器是如何構造出來的,但是根據第一篇文章的說法,這設計一次的文法是為了直接構造出文法樹服務的,所以必然在執行狀態機器的時候就要獲得構造文法樹的一切資訊。如果自己開發過類似的東西就會知道,類似LALR這種東西,你可以很容易的把整個字串分析完判斷他是不是屬於這個LALR狀態機器描述的這個集合,但是你卻不能拿到文法分析所走的路徑,也就是說你很難直接拿到那顆分析樹。沒有分析樹肯定是做不出文法樹的。因此我們得把一些資訊插入到狀態機器裡面,才能最終把分析樹(並不一定真的要表達成樹,像上一篇文章的“分析路徑”(其實就是分析樹的一種可能的表達形式)所確定的文法樹構造出來。

就像《構造Regex引擎》一般給狀態機器添加資訊的方法,就是把一些附加的資料加到狀態與狀態之間的跳轉箭頭裡面去。為了形象的表達這個事情,我就拿第一篇文章的四則運算式子來舉例。在這裡我為了大家方便,重複一下這個文法的內容(除去了語樹書聲明):

token NAME = "[a-zA-Z_]/w*";token NUMBER = "/d+(./d+)";token ADD = "/+";token SUB = "-";token MUL = "/*";token DIV = "//";token LEFT = "/(";token RIGHT = "/)";token COMMA = ",";    rule NumberExpression Number        = NUMBER : value;    rule FunctionExpression Call        = NAME : functionName "(" [ Exp : arguments { "," Exp : arguments } ] ")";    rule Expression Factor        = !Number | !Call;    rule Expression Term        = !Factor;        = Term : firstOperand "*" Factor : secondOperand as BinaryExpression with { binaryOperator = "Mul" };        = Term : firstOperand "/" Factor : secondOperand as BinaryExpression with { binaryOperator = "Div" };    rule Expression Exp        = !Term;        = Exp : firstOperand "+" Term : secondOperand as BinaryExpression with { binaryOperator = "Add" };        = Exp : firstOperand "-" Term : secondOperand as BinaryExpression with { binaryOperator = "Sub" };

那麼我們把這個文發轉成狀態機器之後,要給跳轉加上什麼呢?從直覺上來說,跳轉的時候我們會有六種要乾的事情:

1、Create:這個文法建立的文法樹節點是某個類型的(區別於在這一刻給這個問法建立一個返回什麼類型的文法樹節點)

2、Set:給建立的文法樹節點的某個成員變數設定一個指定的值

3、Assign:給建立的文法樹節點的某個成員變數設定這一次跳轉的符號產生的文法樹節點(譬如說Exp = Exp: firstOperand “+” Term: secondOperand,走Term的時候,一個文法樹節點就會被assign給那個叫做secondOperand的成員變數)

4、Using:使用這一次跳轉的符號產生的文法樹節點來做這次文法的傳回值(譬如說Factor = !Number | !Caller這一條)

5、Shift:略

6、Reduce:略

在這裡我們並沒有標記整個文法從哪一個非終結符開始,因為在實際過程中,其實分析師可以從任何一個文法開始的。譬如說寫IDE的時候,我們可能在某些情況下僅僅只需要分析一個運算式。所以考慮到每一個非終結符都有可能被用到,因此我們的“Token流開始”和“Token流結束”就會在每一個非終結符的狀態機器中都出現。因此在第一步建立Epsilon PDA(下推自動機)的時候,就可以先直接產生。在這裡我們拿Exp做例子:

本欄目更多精彩內容:http://www.bianceng.cn/Programming/cplus/

雙虛線代表的是Token流和Token流結束,這並不是我們現在關心的事情。在剩下的轉換中,實現是具有輸入的轉換,而虛線則是沒有輸入的轉換(一般稱為epsilon邊)。

在這裡我們要明確一個概念——分析路徑。分析路徑代表的是token在“流”過狀態機器的時候,狀態是如何跳轉的。因此對於實際的分析過程,分析路徑其實就是分析樹的一種表達形式。而在狀態機器裡面,分析路徑則代表一條從開始到結尾的可能的路徑。譬如說在這裡,分析路徑可以有三條:

$e –> e1 –> e2 –> e$

$e –> e3 –> e8 –> e7 –> e6 –> e5 –> e4 –> e$

$e –> e9 –> e14 –> e13 –> e12 –> e11 –> e10 –> e$

因此我們可以清楚,一條路徑上是不能出現多個create的,否則你就不知道應該建立的是什麼了。當然create和using都不能同時出現,using也不能有多個。而且由於create和set都是在描述這個非終結符(在這裡是Exp)所建立的文法樹節點的類型和屬性,跟執行他們的時機無關,所以其實在同一條分析路徑裡面,create和set放在哪裡都沒關係。就譬如說在上面的第二條分析路徑裡面,create是在e6->e5裡面標記出來的。就算他移動到了e3->e8,做的事情也一樣。反正只要一條路徑上標記了create,那麼他在這條路徑被確定之後,就一定會create所指定的具體類型的文法樹節點。這是相當重要的,因為在後面的分析中,我們很可能需要移動create和set的具體位置。

跟上一篇文章說的一樣,接下來的一步就是去除epsilon邊了。結果如下:

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。