【Interpreter】构建简单的解释器(第2部分—Go语言实现)

【Interpreter】构建简单的解释器(第2部分—Go语言实现)

一、描述

  1. 允许输入多位数整数,例如 “12+3”
  2. 添加忽略空白字符的方法,让计算器可以处理带有空白字符的输入,如 “12 + 3”
  3. 扩展代码,可以使用 ‘-’ 代替 ‘+’ 来处理像 “7-5” 这样的减法

二、代码

// 综合以上三个问题,使用 Go 简单实现
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"

	"unicode"
)

type TokenType int

const (
	NONE TokenType = iota
	INTEGER
	PLUS
	MINUS
	EOF
)

type Token struct {
	Type  TokenType
	Value interface{}
}

type Interpreter struct {
	Text         []rune
	Pos          int
	CurrentToken Token
	CurrentChar  rune
}

func NewToken(t TokenType, v interface{}) Token {
	return Token{
		Type:  t,
		Value: v,
	}
}

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) RuneToDigit() int {

	result := ""

	for interpreter.CurrentChar != 0 && unicode.IsDigit(interpreter.CurrentChar) {
		result += string(interpreter.CurrentChar)
		interpreter.Advance()

	}

	return StrToInt(result)
}

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 (interpreter *Interpreter) SkipWhiteSpace() {
	for interpreter.CurrentChar != 0 && unicode.IsSpace(interpreter.CurrentChar) {
		interpreter.Advance()
	}
}

func (interpreter *Interpreter) Eat(token_type TokenType) {
	if interpreter.CurrentToken.Type == token_type {
		interpreter.CurrentToken = interpreter.GetNextToken()
	} else {
		panic(fmt.Sprintf("invalid token type: %s", interpreter.Text))
	}
}

func (interpreter *Interpreter) GetNextToken() Token {

	for interpreter.CurrentChar != 0 {
		if unicode.IsSpace(interpreter.CurrentChar) {
			interpreter.SkipWhiteSpace()
			continue
		}

		if unicode.IsDigit(interpreter.CurrentChar) {
			return NewToken(INTEGER, interpreter.RuneToDigit())
		}

		if interpreter.CurrentChar == '+' {
			interpreter.Advance()
			return NewToken(PLUS, "+")
		}

		if interpreter.CurrentChar == '-' {
			interpreter.Advance()
			return NewToken(MINUS, "-")
		}

		panic(fmt.Sprintf("invalid input: %s", string(interpreter.Text)))
	}

	return NewToken(EOF, nil)
}

func (interpreter *Interpreter) Expr() {

	defer func() {
		if r := recover(); r != nil {
			fmt.Println("[ERROR] ", r)
		}
	}()

	interpreter.CurrentToken = interpreter.GetNextToken()

	left := interpreter.CurrentToken
	interpreter.Eat(INTEGER)

	op_token := interpreter.CurrentToken

	if op_token.Type == PLUS {
		interpreter.Eat(PLUS)
	} else {
		interpreter.Eat(MINUS)
	}

	right := interpreter.CurrentToken
	interpreter.Eat(INTEGER)

	result := 0

	if op_token.Type == PLUS {
		result = left.Value.(int) + right.Value.(int)
	} else {
		result = left.Value.(int) - right.Value.(int)
	}

	fmt.Println(result)
}

func main() {

	fmt.Println("------------ PART-2 --------------")

	reader := bufio.NewReader(os.Stdin)

	for {
		fmt.Print("[CALC]-> ")
		text, _ := reader.ReadString('\n')
		// convert CRLF to LF
		text = strings.ToLower(strings.TrimSpace(strings.TrimSuffix(text, "\n")))
		// fmt.Println(text)
		if 0 == len(text) {
			continue
		}

		text = strings.ToLower(text)

		if text == "exit" {
			fmt.Println("退出成功!")
			fmt.Println("------------------------------------")
			os.Exit(0)
		}

		my_text := []rune(text)
		my_interpreter := Interpreter{my_text, 0, Token{}, my_text[0]}

		my_interpreter.Expr()
	}
}

三、运行结果

------------ PART-2 --------------
[CALC]-> 12+3
15
[CALC]-> 12-3
9
[CALC]-> 123 + 100
223
[CALC]->   123 + 100  
223
[CALC]-> 123 - 100
23
[CALC]->    123   - 100
23
[CALC]-> 12 3  - 100
[ERROR]  invalid token type
[CALC]-> exit
退出成功!
------------------------------------

——2019-01-02——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值