亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

從零開始寫個編譯器吧 - 開始寫詞法分析器(1)

littleGrow / 2905人閱讀

摘要:上一章提到我要手寫詞法分析器這個狀態(tài)機,嗯,那就讓我們開始吧。實際上,在狀態(tài)機不斷接受字符的過程中,會先調(diào)用將其緩存,并在適當(dāng)?shù)臅r機調(diào)用生成。一個典型的狀態(tài)機,處于不同狀態(tài),對于接受的參數(shù)進行不同的操作。

上一章提到我要手寫詞法分析器這個狀態(tài)機,嗯,那就讓我們開始吧。

    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
            return null;
        }

        private State state;
        private final LinkedList tokenBuffer = new LinkedList<>();
        private StringBuilder readBuffer = null;
        
        private void refreshBuffer(char c) {
            readBuffer = new StringBuilder();
            readBuffer.append(c);
        }

    private void createToken(Type type) {
        Token token = new Token(type, readBuffer.toString());
        tokenBuffer.addFirst(token);
        readBuffer = null;
    }
        
        private boolean readChar(char c) throws LexicalAnalysisException {
            //TODO 狀態(tài)機邏輯...
        }
    }

于是我又添加了一點代碼??梢钥吹剑曳胖?readChar() 函數(shù)的 TODO 不管,又添加了一個 readChar(char c) 的函數(shù)。因為我有這么一個考慮:對于readChar()方法而言,這個是一個被動調(diào)用的函數(shù),外部調(diào)用一下,就讀到一個Token。這樣設(shè)計,今后寫 Parser 時讀取 Token 會要簡單許多。而readChar(char c)是一個主動調(diào)用的函數(shù),它的實現(xiàn)部分直接處理接受的參數(shù) char 就行了,而且也不必立即返回 Token。這樣我在寫 readChar(char c) 本身的時候會簡單許多。

實際上,在狀態(tài)機不斷接受字符的過程中,會先調(diào)用 readBuffer.append(...) 將其緩存,并在適當(dāng)?shù)臅r機調(diào)用 createToken(...) 生成 Token。

至此,readChar(char c) 就變成了一個純粹用于實現(xiàn)狀態(tài)機功能的函數(shù)了。讓我們開始寫這個函數(shù)吧。

    private State state;

    private boolean readChar(char c) throws LexicalAnalysisException {
    
        boolean moveCursor = true;
        Type createType = null;
    
        if(state == State.Normal) {
            
        } else if(state == State.Identifier) {
            
        } else if(state == State.Sign) {
        
        } else if(state == State.Annotation) {
            
        } else if(state == State.String) {
            
        } else if(state == State.RegEx) {
        
        } else if(state == State.Space) {
            
        }
        
        if(createType != null) {
            createToken(createType);
        }
        return moveCursor;
    }

一個典型的狀態(tài)機,處于不同狀態(tài),對于接受的參數(shù) char 進行不同的操作。同時,我可以通過 state = ?; 來改變狀態(tài)機的狀態(tài)。

這個函數(shù)會返回一個 boolean 類型的變量,即 moveCursor,這個變量表示,在讀完當(dāng)前 char 之后,是否移動游標(biāo)讀取下一個字符。如果為 false,則該函數(shù)的下一次調(diào)用的參數(shù)與前一次調(diào)用的參數(shù)會一模一樣(因為游標(biāo)沒有移動嘛)。

最自然的情況下 moveCursor == true,就是讀了一個字符以后再讀下一個字符嘛。

嗯,然后開始填充這些 if-else 之間的空白吧,先從 Normal 狀態(tài)開始。

private boolean readChar(char c) throws LexicalAnalysisException {

    boolean moveCursor = true;
    Type createType = null;
    
    if(state == State.Normal) {
        if(inIdentifierSetButNotRear(c)) {
            state = State.Identifier;
        }
        else if(SignParser.inCharSet(c)) {
            state = State.Sign;
        }
        else if(c == "#") {
            state = State.Annotation;
        }
        else if(c == """ | c == """) {
            state = State.String;
        }
        else if(c == "`") {
            state = State.RegEx;
        }
        else if(include(Space, c)) {
            state = State.Space;
        }
        else if(c == "
") {
            createType = Type.NewLine;
        }
        else if(c == "