從零開始寫個編譯器吧 - 詞法分析器是一個狀態機

詞法分析器 Tokenizer 自己就是一個狀態機,生成這個狀態機有不少種方法,而我打算採起手寫的方式。由於 tao 語言的詞法仍是相對比較簡單的,手寫不成問題。
先新建一個LexicalAnalysis.java 於 src/com/taozeyu/taolan/analysis之中。java

package com.taozeyu.taolan.analysis;

public class LexicalAnalysis {
    private static enum State {
        Normal,
        Identifier, Sign, Annotation,
        String, RegEx, Space;
    }
}

看看其中定義的 State 枚舉類型,其中有6種類型與 Token 的類型對應。特別的,Normal 類型表示狀態能夠轉化成任何一種單詞類型的狀態。我仍是貼一張圖來描述着7種狀態吧。程序員

c9719a1388b2b27b96f700440bc20618_b.jpg

如圖所示,Normal 狀態做爲狀態機的初始狀態,也是各個其餘狀態的中轉狀態。狀態機不斷從源代碼(即一個字符串)中讀入一個一個字符,讀到不一樣的字符將使狀態機的狀態從一個狀態變化到另一個狀態。函數

例如,在 Normal 狀態下讀到了「#」將使狀態變爲 Annotation ,反過來若是繼續讀到一個「\n"即換行符號,則會從 Annotation 狀態回到 Normal 狀態。固然,對於 Identifier、 Sign、Space 的狀態變化更爲複雜一點,但僅憑當前讀入的那一個字符就能夠變化到正確的狀態(圖中沒有表現)。spa

此外,當源代碼讀完了,若是狀態機處於Normal狀態,此時應該生成一個EndSymbol。但若是此時不處於 Normal 狀態,那就有問題了,必須拋出一個異常。(這種狀況是程序員把源代碼自己寫錯了,例如最後一個字符串少右邊的"之類的。)
至此,我就能夠知道 LexicalAnalysis 類應該有那些函數可供(Parser)調用啦。code

package com.taozeyu.taolan.analysis;

public class LexicalAnalysis {
    private static enum State {
        Normal,
        Identifier, Sign, Annotation,
        String, RegEx, Space;
    }

    public LexicalAnalysis(Reader reader) {
        //TODO
    }

    Token read() throws IOException, LexicalAnalysisException {
        //TODO
    }
}

至此,語法分析器 Parser 能夠不斷調用 read() 函數來得到 Token 對象,直到讀到 EndSymbol 或拋出異常爲止。注意 read() 函數的聲明中 throws LexicalAnalysisException 這段。當這個異常被拋出,說明源代碼寫錯了。這不是編譯器的錯,而是程序員的錯,編譯器只管把這個錯報出來,讓程序員去改代碼。orm

固然對於程序員而言,這是個語法錯誤。可是既然我是在寫編譯器,我可能要把這些錯誤分得更細一點。由於這個錯誤是在單詞化(Tokenization)階段拋出的,所以咱們將其稱之爲詞法錯誤吧,以便區分。對象

相關文章
相關標籤/搜索