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

Go語言標準庫go/scanner包提供了Scanner來實現詞法單元掃描,它在FileSetFile抽象文件集合的基礎上進行詞法分析。

scanner.Scanner的公開接口定義如下:

type Scanner struct {
    // public state - ok to modify
    ErrorCount int // number of errors encountered
    // Has unexported fields
}

func (s *Scanner) Init(
    file *token.File, src []byte,
    err ErrorHandler, mode Mode,
)
func (s *Scanner) Scan() (
    pos token.Pos, tok token.Token, lit string,
)

Init方法用于初始化掃描器,其中file參數表示當前的文件(不包含代碼數據),src參數表示要分析的代碼,err參數表示用戶自定義的錯誤處理函數,mode參數可以控制是否掃描注釋部分。

Scan方法掃描一個詞法單元,3個返回值分別表示詞法單元的位置、詞法單元的值和詞法單元的文本表示。

要構造一個簡單的詞法掃描器測試程序,首先要構造Init方法的第一個參數所需的File對象。但是,File對象沒有公開的構造函數,只能通過FileSetAddFile方法間接構造File對象。

下面是一個簡單的詞法分析程序:

package main

import (
    "fmt"
    "go/scanner"
    "go/token"
)

func main() {
    var src = []byte(`println("你好,世界")`)

    var fset = token.NewFileSet()
    var file = fset.AddFile("hello.go", fset.Base(), len(src))

    var s scanner.Scanner
    s.Init(file, src, nil, scanner.ScanComments)

    for {
        pos, tok, lit := s.Scan()
        if tok == token.EOF {
            break
        }
        fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit)
    }
}

其中,src是要分析的代碼字符串。

首先通過token.NewFileSet方法創建一個文件集。這是因為詞法單元的位置信息必須通過文件集定位,并且需要通過文件集創建掃描器的Init方法所需的file參數。

然后調用fset.AddFile方法向fset文件集添加一個新的文件,文件名為hello.go,文件的長度就是要分析的代碼src的長度。

接著創建scanner.Scanner對象,并且調用Init方法初始化掃描器。Init方法的第一個參數file表示剛剛添加到fset的文件對象,第二個參數src表示要分析的代碼,第三個參數nil表示沒有自定義的錯誤處理函數,最后的scanner.ScanComments參數表示不忽略注釋。

因為要解析的代碼中有多個詞法單元,所以我們在一個循環中調用s.Scan方法依次解析每個詞法單元。如果返回的是token.EOF,則表示掃描到了文件末尾,否則輸出掃描返回的結果。輸出前,我們需要將掃描器返回的pos參數轉換為更詳細的帶文件名和行列號的位置信息,可以通過fset.Position(pos)方法完成。

運行以上程序的輸出結果如下:

hello.go:1:1    IDENT   "println"
hello.go:1:8    (        ""
hello.go:1:9    STRING  "\"你好,世界\""
hello.go:1:26   )        ""
hello.go:1:27   ;        "\n"

輸出結果的第一列表示詞法單元所在的文件和行列號,中間一列表示詞法單元的枚舉值,最后一列表示詞法單元在源文件中的原始內容。

主站蜘蛛池模板: 天气| 荔浦县| 延吉市| 巴彦县| 天长市| 闽侯县| 舞阳县| 建水县| 吉木萨尔县| 丹江口市| 丰顺县| 盐亭县| 江门市| 徐汇区| 汾西县| 庄浪县| 富民县| 乐陵市| 丰城市| 屯留县| 威海市| 通州区| 呼图壁县| 资源县| 墨竹工卡县| 仁化县| 张北县| 阳信县| 双桥区| 石嘴山市| 杭锦后旗| 陆河县| 会理县| 河津市| 伊通| 宜州市| 富源县| 大渡口区| 屯昌县| 塘沽区| 大兴区|