官术网_书友最值得收藏!

  • 用Go語言自制解釋器
  • (德)索斯藤·鮑爾
  • 1026字
  • 2022-06-17 10:50:31

1.2 定義詞法單元

首先要做的是定義詞法分析器輸出的詞法單元。這里先定義少量的詞法單元,之后在擴展詞法分析器時再添加更多的定義。

第一次要解析的Monkey語言代碼如下所示:

let five = 5;
let ten = 10;

let add = fn(x, y) {
  x + y;
};

let result = add(five, ten);

來詳細看看,這個例子中包含哪些類型的詞法單元。首先,有510這樣的數字,這很明顯;之后是xyaddresult這樣的變量名。最后Monkey語言中還有一些單詞,它們既不是數字也不是變量名,例如letfn。當然,還有很多特殊字符,如(){}=,;

這些數字都是整數,將按字面量處理,并賦予其一個單獨的類型。在詞法分析器或語法分析器中,數字的值是5還是10并不重要,只要知道它是一個數字就行。變量名也是如此,都統一用作標識符。除此之外還有一些單詞,看起來像標識符但實際上不是,這些稱為關鍵字,也是Monkey語言的一部分。后面在語法分析階段遇到letfn這樣的關鍵字時,都會特殊處理,所以它們不能與標識符歸為一類。最后的特殊字符也會單獨列出來,其中每個特殊字符都會有相應的處理方式,例如在源代碼中,括號會對代碼的含義產生很大影響。

基于這些分析,現在來定義Token數據結構。它需要哪些字段呢?正如剛剛看到的,肯定需要一個類型屬性,這樣就可以區分“整數”和“右括號”這樣不同的詞法單元。然后還需要一個字段用于保存詞法單元的字面量,以便后續步驟復用,比如對于表示數字的詞法單元,這個字段能記錄510這樣的信息。

新建一個token包,以便定義Token結構和TokenType類型:

// token/token.go

package token

type TokenType string

type Token struct {
    Type    TokenType
    Literal string
}

TokenType類型定義成了字符串,這樣我們就可以使用各種TokenType值,而根據TokenType值能區分不同類型的詞法單元。使用字符串對調試也有幫助,會讓調試更容易,而無須再使用許多樣板和輔助函數,只需打印一個字符串即可。當然,與使用intbyte類型相比,使用字符串會導致程序在性能上有損失。但對于本書而言,使用字符串完全沒有問題。

從剛剛的分析中可以看到,Monkey語言中的詞法單元類型并不多。這意味著可以將所有的TokenType都定義為常量,所以在上面的代碼中可以再添加以下內容:

// token/token.go

const (
    ILLEGAL = "ILLEGAL"
    EOF     = "EOF"

    // 標識符+字面量
    IDENT = "IDENT" // add, foobar, x, y, ...
    INT   = "INT"   // 1343456

    // 運算符
    ASSIGN = "="
    PLUS   = "+"

    // 分隔符
    COMMA     = ","
    SEMICOLON = ";"

    LPAREN = "("
    RPAREN = ")"
    LBRACE = "{"
    RBRACE = "}"

    // 關鍵字
    FUNCTION = "FUNCTION"
    LET      = "LET"
)

如你所見,上面的代碼中還出現了ILLEGALEOF這兩種特殊類型。這兩種類型在之前的示例中并沒有遇到,卻是必不可少的。ILLEGAL表示遇到未知的詞法單元或字符,EOF則表示文件結尾(End Of File),用于通知后續章節會介紹的語法分析器停機。

目前一切順利,下面準備開始編寫詞法分析器。

主站蜘蛛池模板: 巫溪县| 荔浦县| 天台县| 广昌县| 新绛县| 商洛市| 阳信县| 五常市| 汶川县| 平谷区| 将乐县| 宣汉县| 龙海市| 新安县| 贡嘎县| 祁门县| 千阳县| 辛集市| 金乡县| 来宾市| 临夏县| 营口市| 丽水市| 龙游县| 射洪县| 饶阳县| 博乐市| 东方市| 郧西县| 南安市| 前郭尔| 大同县| 潞西市| 泽普县| 清丰县| 宝清县| 尖扎县| 大冶市| 五寨县| 盈江县| 庆元县|