使用Golang创建解释器
简而言之
筆者半年前开始自学Python,为了更深入理解编程,决定自己动手制作一个解释器。选择Go语言的原因是想接触静态类型语言,并且觉得Go语言很流行。本文将参考《用Go创建解释器》进行开发。由于已经完成第一章的阅读,下面我将进行总结。
第一章,解析文字和句子
字句解析是什么意思?
将源代码转换为令牌序列被称为”词法分析”。
let x = 5 + 5;

解析器字句
- 令牌的定义
type Token struct {
Type string
Literal string
}
const (
ILLEGAL = "ILLEGAL" // 未知の文字列
EOF = "EOF" // 終わりを示す
IDENT = "IDENT" // 識別子
INT = "INT" // 数値型
ASSIGN = "="
PLUS = "+"
[...]
)
- Lexer(词法分析器)
type Lexer struct {
input string
position int // 読み込んでる文字
readPosition int // 次に読み込む文字
ch byte // 検査中の文字
}
func New(input string) *Lexer {
// Lexerに引数inputをセットしreturn
l := &Lexer{input: input}
l.readChar()
return l
}
func (l *Lexer) readChar() {
// 入力が終わったらchを0に
if l.readPosition >= len(l.input) {
l.ch = 0
// まだ終わっていない場合readPositionをchにセット
} else {
l.ch = l.input[l.readPosition]
}
// positionを次に進める
l.position = l.readPosition
// readpositonを次に進める
l.readPosition += 1
}
func (l *Lexer) NextToken() token.Token {
var tok token.Token
// トークンを生成する
switch l.ch {
case '=':
tok = newToken(token.ASSIGN, l.ch)
case '+':
tok = newToken(token.PLUS, l.ch)
case '-':
tok = newToken(token.MINUS, l.ch)
[...]
l.readChar()
return tok
}
func newToken(tokenType TokenType, ch byte) Token {
return Token{Type: tokenType, Literal: string(ch)}
}
现在可以生成令牌了,但是仍需要逐个字符生成令牌。
let five = 5;
let ten = 10;
let add = fn(x, y) {
x + y;
};
let result = add(five, ten):
对于像上述的句子进行分析仍然存在一些问题。
- 由于只能一次解析一个字符,所以使用 let(关键字)会引发错误。与 1 相同,使用 five(标识符)也会引发错误。解析数字。
首先,我们需要实现一个函数来判断字符是否为英文字母1或2,并且实现一个函数来读取并推进字符,直到遇到非英文字母。
// 非英字まで読み込みを進める
func (l *Lexer) readIdentifier() string {
position := l.position
// for文でisLetter関数からfalseが返ってくるまで読み込みを進める
for isLetter(l.ch) {
l.readChar()
}
// 最初の文字から非英字まで進めたpositionまでを返す
return l.input[position:l.position]
}
// 判断する関数
func isLetter(ch byte) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z'
}
使用这两个函数,给NextToken()的switch语句添加分支,就可以成功生成字符串的标记。
然后需要对变量声明(如let)和函数声明(如fn)进行分类。
[...]
FUNCTION = "FUNCTION"
LET = "LET"
var keywords = map[string]TokenType{
"fn": FUNCTION,
"let": LET,
}
func LookupIdent(ident string) TokenType {
// readIdentifierで読み込んだ文字列を引数にとり、キーワードに存在する場合は適切なTypeを返す
if tok, ok := keywords[ident]; ok {
return tok
}
// 識別子の場合
return IDENT
}
与 isLetter 相同的是,将其分辨为数字令牌。代码将被省略。
在第一章的最后实现REPL。
REPL的实现
REPL 是什么?
阅读
E 评价
打印
循环
REPL是上述的缩写。在解释型语言中非常常见,它接收输入、进行评估并重复输出结果。
const PROMPO = ">>"
func Start(in io.Reader, out io.Writer) {
// scannerの生成
scanner := bufio.NewScanner(in)
for {
fmt.Printf(PROMPO)
scanned := scanner.Scan()
if !scanned {
return
}
// 入力を受け取る
line := scanner.Text()
// 解析器に入力された文字列を入れる
l := lexer.New(line)
// 文字列を評価し出力、これを繰り返す。
for tok := l.NextToken(); tok.Type != token.EOF; tok = l.NextToken() {
fmt.Printf("%+v\n", tok)
}
}
}
以上是第一章的结束。这是我第一次以这种形式总结和分享所学到的内容,我觉得这种方式能够加深理解,非常有意义。接下来,我将继续更新第二章。