golang实现简单LISP语言解析与执行的插件库gisp的使用

golang实现简单LISP语言解析与执行的插件库gisp的使用

概述

gisp是一个简单的(非标准)Lisp/Scheme到Go的编译器插件库。它提供了基本的LISP语言解析和执行功能。

特性

  • 基于Rob Pike的"Lexical Scanning in Go"实现的词法分析器
  • 简单的递归解析器,支持整数、浮点数、字符串和布尔值
  • 通过loop/recur实现尾调用优化(TCO)
  • 包含生成AST的REPL环境

安装与运行

构建并启动REPL

> go build && ./gisp
>>

启动后会进入REPL环境,你可以直接输入LISP表达式,程序会返回对应的Go AST。

编译LISP文件

> ./gisp filename.gsp

支持的功能

+, -, *, mod, let, if, ns, def, fn, 所有预定义的Go函数

示例代码

下面是一个完整的示例demo,展示如何使用gisp:

package main

import (
	"fmt"
	"github.com/jcla1/gisp"
)

func main() {
	// 初始化gisp环境
	env := gisp.NewEnv()
	
	// 定义一个简单的LISP表达式
	code := `(let ((a 10) (b 20)) (+ a b))`
	
	// 解析并执行表达式
	result, err := gisp.ParseAndEval(code, env)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	
	// 输出结果
	fmt.Println("Result:", result) // 输出: Result: 30
	
	// 定义并调用函数
	fnCode := `(def add (fn (x y) (+ x y)) (add 5 7)`
	fnResult, err := gisp.ParseAndEval(fnCode, env)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Function result:", fnResult) // 输出: Function result: 12
	
	// 使用条件语句
	ifCode := `(if (> 10 5) "10 is greater than 5" "10 is not greater than 5")`
	ifResult, err := gisp.ParseAndEval(ifCode, env)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("If result:", ifResult) // 输出: If result: 10 is greater than 5
}

进阶示例

下面是一个更复杂的示例,展示如何使用递归和尾调用优化:

package main

import (
	"fmt"
	"github.com/jcla1/gisp"
)

func main() {
	env := gisp.NewEnv()
	
	// 定义一个计算阶乘的函数,使用尾递归
	factorialCode := `
	(def factorial 
		(fn (n acc)
			(if (<= n 1)
				acc
				(recur (- n 1) (* n acc)))))
	(factorial 5 1)`
	
	result, err := gisp.ParseAndEval(factorialCode, env)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Factorial of 5:", result) // 输出: Factorial of 5: 120
	
	// 使用let创建局部变量
	letCode := `
	(let ((x 10)
	      (y 20))
		(* x y))`
	
	letResult, err := gisp.ParseAndEval(letCode, env)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Let result:", letResult) // 输出: Let result: 200
}

注意事项

  1. gisp是一个简单的LISP实现,不支持完整的LISP/Scheme标准
  2. 尾递归通过recur关键字实现,而不是直接调用函数名
  3. 环境变量(env)用于存储定义的函数和变量

许可证

MIT许可证


更多关于golang实现简单LISP语言解析与执行的插件库gisp的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现简单LISP语言解析与执行的插件库gisp的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang实现简单LISP解析与执行 - gisp库介绍

下面我将介绍一个简单的Golang实现的LISP解析与执行库gisp的基本使用方法和实现原理。

基本概念

gisp是一个轻量级的LISP解释器库,主要功能包括:

  • 解析LISP表达式
  • 执行LISP代码
  • 支持基本LISP函数和操作
  • 可扩展的函数注册机制

安装与使用

go get github.com/jcla1/gisp

基础示例

package main

import (
	"fmt"
	"github.com/jcla1/gisp"
)

func main() {
	// 创建解释器实例
	interpreter := gisp.New()

	// 执行简单LISP表达式
	result, err := interpreter.EvalString("(+ 1 2 3)")
	if err != nil {
		panic(err)
	}
	fmt.Println(result) // 输出: 6

	// 定义变量
	_, err = interpreter.EvalString("(define x 10)")
	if err != nil {
		panic(err)
	}

	// 使用变量
	result, err = interpreter.EvalString("(* x 2)")
	if err != nil {
		panic(err)
	}
	fmt.Println(result) // 输出: 20

	// 定义函数
	_, err = interpreter.EvalString("(define (square n) (* n n))")
	if err != nil {
		panic(err)
	}

	// 调用函数
	result, err = interpreter.EvalString("(square 5)")
	if err != nil {
		panic(err)
	}
	fmt.Println(result) // 输出: 25
}

核心功能实现

1. 表达式解析

gisp使用递归下降法解析LISP表达式:

func parse(lexer *Lexer) (interface{}, error) {
	token := lexer.Next()
	switch token.Type {
	case TokenEOF:
		return nil, io.EOF
	case TokenLParen:
		return parseList(lexer)
	case TokenRParen:
		return nil, errors.New("unexpected )")
	case TokenSymbol:
		return Symbol(token.Text), nil
	case TokenNumber:
		num, err := strconv.ParseFloat(token.Text, 64)
		if err != nil {
			return nil, err
		}
		return num, nil
	case TokenString:
		return token.Text[1 : len(token.Text)-1], nil
	default:
		return nil, fmt.Errorf("unexpected token: %v", token)
	}
}

2. 执行环境

gisp使用环境(Environment)来管理变量和函数:

type Environment struct {
	parent *Environment
	vars   map[string]interface{}
	funcs  map[string]Function
}

func (e *Environment) DefineVar(name string, value interface{}) {
	e.vars[name] = value
}

func (e *Environment) LookupVar(name string) (interface{}, bool) {
	val, ok := e.vars[name]
	if !ok && e.parent != nil {
		return e.parent.LookupVar(name)
	}
	return val, ok
}

3. 内置函数实现

gisp提供了一些基本的内置函数:

func addBuiltins(env *Environment) {
	env.funcs["+"] = func(args []interface{}) (interface{}, error) {
		sum := 0.0
		for _, arg := range args {
			num, ok := arg.(float64)
			if !ok {
				return nil, errors.New("+ expects numbers")
			}
			sum += num
		}
		return sum, nil
	}

	env.funcs["define"] = func(args []interface{}) (interface{}, error) {
		// 实现变量和函数定义
		// ...
	}
}

扩展自定义函数

可以很方便地扩展自定义函数:

func main() {
	interpreter := gisp.New()
	
	// 注册自定义函数
	interpreter.AddFunction("greet", func(args []interface{}) (interface{}, error) {
		if len(args) != 1 {
			return nil, errors.New("greet expects 1 argument")
		}
		name, ok := args[0].(string)
		if !ok {
			return nil, errors.New("greet expects a string")
		}
		return "Hello, " + name + "!", nil
	})
	
	// 使用自定义函数
	result, err := interpreter.EvalString("(greet \"World\")")
	if err != nil {
		panic(err)
	}
	fmt.Println(result) // 输出: Hello, World!
}

性能考虑

对于简单的LISP解释器,性能通常不是首要考虑因素,但gisp做了一些优化:

  1. 使用哈希表快速查找变量和函数
  2. 避免不必要的内存分配
  3. 简单的字节码缓存机制

限制

当前版本的gisp有一些限制:

  1. 不支持宏(macro)
  2. 错误处理较为简单
  3. 性能不如编译型LISP实现

总结

gisp提供了一个简单但功能完整的LISP解释器实现,适合嵌入到Golang项目中作为脚本语言使用。通过扩展自定义函数,可以实现各种领域特定功能。

如果需要更完整的LISP实现,可以考虑其他成熟的Golang LISP项目如:

希望这个介绍对您理解和使用gisp有所帮助!

回到顶部