【Interpreter】构建简单的解释器(第3部分—Go语言实现)
一、描述
在第二部分的基础上,扩展代码,实现可以解释包含任意数量的加法和减法的表达式,例如 “9 - 5 + 3 + 11”
二、代码
// Go 实现
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"unicode"
)
type TOKEN_TYPE int
const (
TYPE_NONE TOKEN_TYPE = iota
TYPE_INTEGER
TYPE_PLUS
TYPE_MINUS
TYPE_MUL
TYPE_DIV
TYPE_EOF
)
type Token struct {
TokenType TOKEN_TYPE
TokenValue interface{}
}
type Interpreter struct {
Text []rune
Pos int
CurrentToken Token
CurrentChar rune
}
func (interpreter *Interpreter) Advance() {
interpreter.Pos += 1
if interpreter.Pos > len(interpreter.Text)-1 {
interpreter.CurrentChar = 0
} else {
interpreter.CurrentChar = interpreter.Text[interpreter.Pos]
}
}
func StrToInt(s string) int {
if ret, err := strconv.Atoi(s); err == nil {
return ret
}
panic(fmt.Sprintf("Cannot convert %s to int!", s))
}
func (interpreter *Interpreter) Integer() int {
result := ""
for interpreter.CurrentChar != 0 && unicode.IsDigit(interpreter.CurrentChar) {
result += string(interpreter.CurrentChar)
interpreter.Advance()
}
return StrToInt(result)
}
func (interpreter *Interpreter) SkipSpace() {
for interpreter.CurrentChar != 0 && unicode.IsSpace(interpreter.CurrentChar) {
interpreter.Advance()
}
}
func (interpreter *Interpreter) GetNextToken() Token {
for interpreter.CurrentChar != 0 {
if unicode.IsSpace(interpreter.CurrentChar) {
interpreter.SkipSpace()
}
if unicode.IsDigit(interpreter.CurrentChar) {
return Token{TYPE_INTEGER, interpreter.Integer()}
}
if interpreter.CurrentChar == '+' {
interpreter.Advance()
return Token{TYPE_PLUS, '+'}
}
if interpreter.CurrentChar == '-' {
interpreter.Advance()
return Token{TYPE_MINUS, '-'}
}
panic("invalid text.")
}
return Token{TYPE_EOF, nil}
}
func (interpreter *Interpreter) Eat(token_type TOKEN_TYPE) {
if interpreter.CurrentToken.TokenType == token_type {
interpreter.CurrentToken = interpreter.GetNextToken()
} else {
panic("invalid token type.")
}
}
func (interpreter *Interpreter) Term() int {
token := interpreter.CurrentToken
interpreter.Eat(TYPE_INTEGER)
return token.TokenValue.(int)
}
func (interpreter *Interpreter) Expr() {
defer func() {
if r := recover(); r != nil {
fmt.Println("[ERROR] ", r)
}
}()
interpreter.CurrentToken = interpreter.GetNextToken()
result := interpreter.Term()
for {
if interpreter.CurrentToken.TokenType == TYPE_PLUS {
interpreter.Eat(TYPE_PLUS)
result += interpreter.Term()
} else if interpreter.CurrentToken.TokenType == TYPE_MINUS {
interpreter.Eat(TYPE_MINUS)
result -= interpreter.Term()
} else {
break
}
}
fmt.Println("> ", result)
}
func main() {
fmt.Println("------------------ <PART-3> ------------------")
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("[CALC]-> ")
text, _ := reader.ReadString('\n')
text = strings.ToLower(strings.TrimSpace(strings.TrimSuffix(text, "\n")))
if len(text) == 0 {
continue
}
if text == "exit" {
fmt.Println("-------------------程序已退出------------------")
fmt.Println("------------------- <END> --------------------")
os.Exit(0)
}
my_text := []rune(text)
my_interpreter := Interpreter{my_text, 0, Token{}, my_text[0]}
my_interpreter.Expr()
}
}
三、运行结果
------------------ <PART-3> ------------------
[CALC]-> 9 -5
> 4
[CALC]-> 9-5+3
> 7
[CALC]-> 9 - 5 + 3 + 11
> 18
[CALC]-> 9+2+
[ERROR] invalid token type.
[CALC]-> exit
-------------------程序已退出------------------
------------------- <END> --------------------
——2019-01-09——