給 go 語言新增中文關鍵字

astaxie發表於2020-02-18

在知乎上看到這個文章,非常有意思,轉過來給大家一起分享。

一、新增中文關鍵字

涉及檔案:

go\src\go\token\token.go

//新增string陣列
var tokens_zh = [...]string{
    BREAK:    "破",
    CASE:     "例",
    CHAN:     "道",
    CONST:    "靜",
    CONTINUE: "續",

    DEFAULT:     "默",
    DEFER:       "延",
    ELSE:        "另",
    FALLTHROUGH: "繼",
    FOR:         "於",

    FUNC:   "函",
    GO:     "去",
    GOTO:   "到",
    IF:     "若",
    IMPORT: "引",

    INTERFACE: "接",
    MAP:       "圖",
    PACKAGE:   "包",
    RANGE:     "範",
    RETURN:    "回",

    SELECT: "擇",
    STRUCT: "構",
    SWITCH: "轉",
    TYPE:   "型",
    VAR:    "變",
}


func init() {
    keywords = make(map[string]Token)
    for i := keyword_beg + 1; i < keyword_end; i++ {
        keywords[tokens[i]] = i
                //新增下面這一行
        keywords[tokens_zh[i]] = i
    }
}

go\src\cmd\compile\internal\syntax\scanner.go

//新增函式
func getZhTok(lit []byte) token {
    switch string(lit) {
    case "破": return _Break
    case "例": return _Case
    case "道": return _Chan
    case "靜": return _Const
    case "續": return _Continue
    case "默": return _Default
    case "延": return _Defer
    case "另": return _Else
    case "繼": return _Fallthrough
    case "於": return _For
    case "函": return _Func
    case "去": return _Go
    case "到": return _Goto
    case "若": return _If
    case "引": return _Import
    case "接": return _Interface
    case "圖": return _Map
    case "包": return _Package
    case "範": return _Range
    case "回": return _Return
    case "擇": return _Select
    case "構": return _Struct
    case "轉": return _Switch
    case "型": return _Type
    case "變": return _Var
    default: return 0
    }
}

func (s *scanner) ident() {
    s.startLit()

    // accelerate common case (7bit ASCII)
    c := s.getr()
    for isLetter(c) || isDecimal(c) {
        c = s.getr()
    }

    // general case
    if c >= utf8.RuneSelf {
        for s.isIdentRune(c, false) {
            c = s.getr()
        }
    }
    s.ungetr()

    lit := s.stopLit()

    // possibly a keyword
    if len(lit) >= 2 {
        if tok := keywordMap[hash(lit)]; tok != 0 && tokStrFast(tok) == string(lit) {
            s.nlsemi = contains(1<<_Break|1<<_Continue|1<<_Fallthrough|1<<_Return, tok)
            s.tok = tok
            return
        } else if tok := getZhTok(lit); tok != 0 { // 新增 else if
            s.nlsemi = contains(1<<_Break|1<<_Continue|1<<_Fallthrough|1<<_Return, tok)
            s.tok = tok
            return
        }
    }

    s.nlsemi = true
    s.lit = string(lit)
    s.tok = _Name
}

二、 新增中文內建型別和函式

新增一部分主要的,builtin.go 也有很多內建函式,暫不涉及。

涉及檔案

go\src\cmd\compile\internal\gc\universe.go

var basicTypes = [...]struct {
    name  string
    etype types.EType
}{
    {"int8", TINT8},
    {"整8", TINT8},
    {"int16", TINT16},
    {"整16", TINT16},
    {"int32", TINT32},
    {"整32", TINT32},
    {"int64", TINT64},
    {"整64", TINT64},
    {"uint8", TUINT8},
    {"無8", TUINT8},
    {"uint16", TUINT16},
    {"無16", TUINT16},
    {"uint32", TUINT32},
    {"無32", TUINT32},
    {"uint64", TUINT64},
    {"無64", TUINT64},
    {"float32", TFLOAT32},
    {"浮32", TFLOAT32},
    {"float64", TFLOAT64},
    {"浮64", TFLOAT64},
    {"complex64", TCOMPLEX64},
    {"復64", TCOMPLEX64},
    {"complex128", TCOMPLEX128},
    {"復128", TCOMPLEX128},
    {"bool", TBOOL},
    {"不二", TBOOL},
    {"string", TSTRING},
    {"字串", TSTRING},
}

//下面的新增需要修改lexinit1()
var typedefs = [...]struct {
    name     string
    etype    types.EType
    sameas32 types.EType
    sameas64 types.EType
}{
    {"int", TINT, TINT32, TINT64},
    {"整", TINT, TINT32, TINT64},
    {"uint", TUINT, TUINT32, TUINT64},
    {"無號", TUINT, TUINT32, TUINT64},
    {"uintptr", TUINTPTR, TUINT32, TUINT64},
    {"針", TUINTPTR, TUINT32, TUINT64},
}

var builtinFuncs = [...]struct {
    name string
    op   Op
}{
    {"append", OAPPEND},
    {"附加", OAPPEND},
    {"cap", OCAP},
    {"容量", OCAP},
    {"close", OCLOSE},
    {"關閉", OCLOSE},
    {"complex", OCOMPLEX},
    {"複數", OCOMPLEX},
    {"copy", OCOPY},
    {"複製", OCOPY},
    {"delete", ODELETE},
    {"刪除", ODELETE},
    {"imag", OIMAG},
    {"虛部", OIMAG},
    {"len", OLEN},
    {"長度", OLEN},
    {"make", OMAKE},
    {"構建", OMAKE},
    {"new", ONEW},
    {"新建", ONEW},
    {"panic", OPANIC},
    {"報警", OPANIC},
    {"print", OPRINT},
    {"列印", OPRINT},
    {"println", OPRINTN},
    {"換行列印", OPRINTN},
    {"real", OREAL},
    {"實部", OREAL},
    {"recover", ORECOVER},
    {"復原", ORECOVER},
}

var unsafeFuncs = [...]struct {
    name string
    op   Op
}{
    {"Alignof", OALIGNOF},
    {"取對齊", OALIGNOF},
    {"Offsetof", OOFFSETOF},
    {"取偏移", OOFFSETOF},
    {"Sizeof", OSIZEOF},
    {"取大小", OSIZEOF},
}

func lexinit() {
       // 新增對應 true、false、nil、iota 的中文詞,其中iota是希臘第9個字母,象形一下^-^
    s = builtinpkg.Lookup("真")
    s.Def = asTypesNode(nodbool(true))
    asNode(s.Def).Sym = lookup("true")
    asNode(s.Def).Name = new(Name)
    asNode(s.Def).Type = types.Idealbool

    s = builtinpkg.Lookup("假")
    s.Def = asTypesNode(nodbool(false))
    asNode(s.Def).Sym = lookup("false")
    asNode(s.Def).Name = new(Name)
    asNode(s.Def).Type = types.Idealbool

    s = builtinpkg.Lookup("無")
    var v1 Val
    v1.U = new(NilVal)
    s.Def = asTypesNode(nodlit(v1))
    asNode(s.Def).Sym = s
    asNode(s.Def).Name = new(Name)

    s = builtinpkg.Lookup("丨")
    s.Def = asTypesNode(nod(OIOTA, nil, nil))
    asNode(s.Def).Sym = s
    asNode(s.Def).Name = new(Name)
}


func lexinit1() {
    s = builtinpkg.Lookup("錯誤")
    s.Def = asTypesNode(typenod(types.Errortype))
    asNode(s.Def).Name = new(Name)

    s = builtinpkg.Lookup("位元組")
    s.Def = asTypesNode(typenod(types.Bytetype))
    asNode(s.Def).Name = new(Name)

    s = builtinpkg.Lookup("字元")
    s.Def = asTypesNode(typenod(types.Runetype))
    asNode(s.Def).Name = new(Name)

        // typedefs的修改,程式碼需要修改成 的下面的樣子
    // backend-dependent builtin types (e.g. int).
    for _, s := range typedefs {
        s1 := builtinpkg.Lookup(s.name)

        t := types.Types[s.etype]
        if t == nil {
            sameas := s.sameas32
            if Widthptr == 8 {
                sameas = s.sameas64
            }

            simtype[s.etype] = sameas
            minfltval[s.etype] = minfltval[sameas]
            maxfltval[s.etype] = maxfltval[sameas]
            minintval[s.etype] = minintval[sameas]
            maxintval[s.etype] = maxintval[sameas]

            t = types.New(s.etype)
            t.Sym = s1
            types.Types[s.etype] = t
            if s.etype != TANY && s.etype != TSTRING {
                dowidth(t)
            }
        }
        s1.Def = asTypesNode(typenod(t))
        asNode(s1.Def).Name = new(Name)
        s1.Origpkg = builtinpkg

        //dowidth(t)
    }
}

三、 新增中文命令

例項:新增 “執行” 為 “run” 的同義命令

go 執行 test.go 等效 go run test.go

go.exe 的命令是通過解析 UsageLine 的文字來識別的。

例如:run 命令 UsageLine: "go run [build flags] [-exec xprog] package [arguments...]"

"go "後面,"["前面第一個詞 匹配就可以了

可以在路徑 go\src\cmd\go\下搜尋 UsageLine,查詢其他命令,進行修改新增。

涉及檔案

go\src\cmd\go\internal\run\run.go

var CmdZhRun = &base.Command{
    UsageLine: "go 執行 [build flags] [-exec xprog] package [arguments...]",
    Short:     "編譯 和 執行 Go 程式",
    Long: `
See also: go build.
    `,
}

func init() {
    CmdRun.Run = runRun // break init loop
    CmdZhRun.Run = runRun

    work.AddBuildFlags(CmdRun)
    work.AddBuildFlags(CmdZhRun)
    CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
    CmdZhRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
}

go\src\cmd\go\main.go

func init() {
    base.Go.Commands = []*base.Command{

        run.CmdRun,
        run.CmdZhRun,

}

四、 測試

本來想連 main、init 的函式名也加個中文的,但牽扯比較多,暫時作罷。

test.go

 main
 "fmt"
 main() {
     a []位元組 = []位元組("啦啦")
     長度(字串(a)) == 6 {
        列印("嘻嘻")
    }  {
        fmt.Println("哈嘍")
    }
}

命令

go 執行 test.go

輸出

嘻嘻

原文地址:zhuanlan.zhihu.com/p/106104002

更多原創文章乾貨分享,請關注公眾號
  • 給 go 語言新增中文關鍵字
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章