摘要:詞法分析器本身就是一個(gè)狀態(tài)機(jī),生成這個(gè)狀態(tài)機(jī)有很多種方法,而我打算采取手寫的方式。狀態(tài)機(jī)不斷從源代碼即一個(gè)字符串中讀入一個(gè)一個(gè)字符,讀到不同的字符將使?fàn)顟B(tài)機(jī)的狀態(tài)從一個(gè)狀態(tài)變化到另外一個(gè)狀態(tài)。
詞法分析器 Tokenizer 本身就是一個(gè)狀態(tài)機(jī),生成這個(gè)狀態(tài)機(jī)有很多種方法,而我打算采取手寫的方式。因?yàn)?tao 語言的詞法還是相對比較簡單的,手寫不成問題。
先新建一個(gè)LexicalAnalysis.java 于 src/com/taozeyu/taolan/analysis之中。
package com.taozeyu.taolan.analysis; public class LexicalAnalysis { private static enum State { Normal, Identifier, Sign, Annotation, String, RegEx, Space; } }
看看其中定義的 State 枚舉類型,其中有6種類型與 Token 的類型對應(yīng)。特別的,Normal 類型表示狀態(tài)可以轉(zhuǎn)化成任何一種單詞類型的狀態(tài)。我還是貼一張圖來描述著7種狀態(tài)吧。
如圖所示,Normal 狀態(tài)作為狀態(tài)機(jī)的初始狀態(tài),也是各個(gè)其他狀態(tài)的中轉(zhuǎn)狀態(tài)。狀態(tài)機(jī)不斷從源代碼(即一個(gè)字符串)中讀入一個(gè)一個(gè)字符,讀到不同的字符將使?fàn)顟B(tài)機(jī)的狀態(tài)從一個(gè)狀態(tài)變化到另外一個(gè)狀態(tài)。
例如,在 Normal 狀態(tài)下讀到了“#”將使?fàn)顟B(tài)變?yōu)?Annotation ,反過來如果繼續(xù)讀到一個(gè)“ "即換行符號,則會從 Annotation 狀態(tài)回到 Normal 狀態(tài)。當(dāng)然,對于 Identifier、 Sign、Space 的狀態(tài)變化更為復(fù)雜一點(diǎn),但僅憑當(dāng)前讀入的那一個(gè)字符就可以變化到正確的狀態(tài)(圖中沒有表現(xiàn))。
此外,當(dāng)源代碼讀完了,如果狀態(tài)機(jī)處于Normal狀態(tài),此時(shí)應(yīng)該生成一個(gè)EndSymbol。但如果此時(shí)不處于 Normal 狀態(tài),那就有問題了,必須拋出一個(gè)異常。(這種情況是程序員把源代碼本身寫錯(cuò)了,例如最后一個(gè)字符串少右邊的"之類的。)
至此,我就可以知道 LexicalAnalysis 類應(yīng)該有那些函數(shù)可供(Parser)調(diào)用啦。
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 可以不斷調(diào)用 read() 函數(shù)來獲得 Token 對象,直到讀到 EndSymbol 或拋出異常為止。注意 read() 函數(shù)的聲明中 throws LexicalAnalysisException 這段。當(dāng)這個(gè)異常被拋出,說明源代碼寫錯(cuò)了。這不是編譯器的錯(cuò),而是程序員的錯(cuò),編譯器只管把這個(gè)錯(cuò)報(bào)出來,讓程序員去改代碼。
當(dāng)然對于程序員而言,這是個(gè)語法錯(cuò)誤。但是既然我是在寫編譯器,我可能要把這些錯(cuò)誤分得更細(xì)一點(diǎn)。因?yàn)檫@個(gè)錯(cuò)誤是在單詞化(Tokenization)階段拋出的,因此我們將其稱之為詞法錯(cuò)誤吧,以便區(qū)分。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/64212.html
摘要:是的,這個(gè)系列將呈現(xiàn)一個(gè)完整的編譯器從無到有的過程。但在寫這個(gè)編譯器的過程中,我可不會偷工減料,該有的一定會寫上的。該語言的虛擬機(jī)將運(yùn)行于之上,同時(shí)編譯器將使用實(shí)現(xiàn)。我早有寫編譯器的想法之前沒寫過,故希望一邊寫編譯器一邊完成這個(gè)系列。 是的,這個(gè)系列將呈現(xiàn)一個(gè)完整的編譯器從無到有的過程。當(dāng)然,為了保證該系列內(nèi)容的簡潔(也為了降低難度),僅僅保證編譯器的最低要求,即僅能用。但在寫這個(gè)編譯...
摘要:上一章提到我要手寫詞法分析器這個(gè)狀態(tài)機(jī),嗯,那就讓我們開始吧。實(shí)際上,在狀態(tài)機(jī)不斷接受字符的過程中,會先調(diào)用將其緩存,并在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用生成。一個(gè)典型的狀態(tài)機(jī),處于不同狀態(tài),對于接受的參數(shù)進(jìn)行不同的操作。 上一章提到我要手寫詞法分析器這個(gè)狀態(tài)機(jī),嗯,那就讓我們開始吧。 public class LexicalAnalysis { private...
摘要:在之前的章節(jié)第章從零開始寫個(gè)編譯器吧開始寫詞法分析器中我有說,我將函數(shù)設(shè)計(jì)成主動調(diào)用的形式,而則是被動調(diào)用的形式。接下來本系列將進(jìn)入編寫語法分析器的階段,不過在此之前,我將抽出一點(diǎn)時(shí)間介紹一下語言本身。 上周周末旅游去了,就沒更新了,雖然回到海拔0m的地區(qū),不過目前似乎還在缺氧,所以本次就少更點(diǎn)吧。 這章將結(jié)束詞法分析的部分。 在之前的章節(jié)(第7章從零開始寫個(gè)編譯器吧 - 開始寫詞...
摘要:讀到一個(gè)非數(shù)字非英文字母非下劃線字符。此時(shí)立即跳轉(zhuǎn)回狀態(tài)。以一個(gè)雙引號開始,并以一個(gè)雙引號結(jié)束。另外,在讀和時(shí)源代碼不許結(jié)束,即讀到符號,若結(jié)束,則判定為詞法錯(cuò)誤。對于而言,也有一些其他的詞法錯(cuò)誤判定,如,不能換行。 對于非 Normal 狀態(tài),我只需要關(guān)心兩個(gè)過程: 何時(shí)從 Normal 跳轉(zhuǎn)到該狀態(tài); 何時(shí)從該狀態(tài)跳回 Normal 狀態(tài)。 在上一章中,我已經(jīng)寫好了從 Nor...
摘要:要為語言設(shè)計(jì)詞法分析器,首先得知道語言是一種什么樣的語言。,不過首先我們得把詞法分析器能生成的單詞類型定義好了。 要為 tao 語言設(shè)計(jì)詞法分析器,首先得知道 tao 語言是一種什么樣的語言。不過呢,我腦海里還沒有 tao 語言具體形象。我還是先貼一段 tao 語言的代碼,大概展示下這是怎么回事吧。 def say_hello_world(who) print hello ...
閱讀 2736·2021-11-11 17:21
閱讀 627·2021-09-23 11:22
閱讀 3591·2019-08-30 15:55
閱讀 1651·2019-08-29 17:15
閱讀 583·2019-08-29 16:38
閱讀 921·2019-08-26 11:54
閱讀 2517·2019-08-26 11:53
閱讀 2764·2019-08-26 10:31