在Go语言中解析s表达式

huangapple go评论65阅读模式
英文:

Parsing s-expressions in Go

问题

这是一个链接,指向lis.py,如果你不熟悉的话:http://norvig.com/lispy.html

我正在尝试在Go语言中实现一个小型的Lisp解释器。我受到了Peter Norvig在Python中实现的Lis.py Lisp解释器的启发。

我的问题是,我无法想到一种相对高效的解析s表达式的方法。我曾考虑过使用一个计数器,当遇到"("时递增1,遇到")"时递减1。这样,当计数器为0时,就知道你得到了一个完整的表达式。

但问题是,这意味着你必须为每个表达式循环一次,这会导致解释器在处理大型程序时非常慢。

如果有其他替代的想法,那就太好了,因为我想不到更好的方法。

英文:

Here's a link to lis.py if you're unfamiliar: http://norvig.com/lispy.html

I'm trying to implement a tiny lisp interpreter in Go. I've been inspired by Peter Norvig's Lis.py lisp implementation in Python.

My problem is I can't think of a single somewhat efficient way to parse the s-expressions. I had thought of a counter that would increment by 1 when it see's a "(" and that would decrement when it sees a ")". This way when the counter is 0 you know you've got a complete expression.

But the problem with that is that it means you have to loop for every single expression which would make the interpreter incredibly slow for any large program.

Any alternative ideas would be great because I can't think of any better way.

答案1

得分: 1

在Rosetta code上有一个用Go语言实现的S表达式解析器:

S-expression parser in Go

这可能会给你解决问题的思路。

英文:

There is an S-expression parser implemented in Go at Rosetta code:

S-expression parser in Go

It might give you an idea of how to attack the problem.

答案2

得分: 1

你可能需要一个名为"Sexpr"的接口,并确保你的符号和列表数据结构与该接口匹配。然后,你可以利用一个S表达式只是"一个单独的符号"或"一个S表达式列表"的事实。

也就是说,如果第一个字符是"(",那么它不是一个符号,而是一个列表,所以开始累积一个[]Sexpr,在每次读取到一个包含的Sexpr时,直到在输入流中遇到一个")"为止。任何包含的列表都已经消耗了它的终止符")"。

如果它不是"(",那么你正在读取一个符号,所以读取直到遇到一个非符号构成字符,取消消耗它并返回该符号。

英文:

You'd probably need to have an interface "Sexpr" and ensure that your symbol and list data structures matches the interface. Then you can use the fact that an S-expression is simply "a single symbol" or "a list of S-expressions".

That is, if the first character is "(", it's not a symbol, but a list, so start accumulating a []Sexpr, reading each contained Sexpr at a time, until you hit a ")" in your input stream. Any contained list will already have had its terminal ")" consumed.

If it's not a "(", you're reading a symbol, so read until you hit a non-symbol-constituent character, unconsume it and return the symbol.

答案3

得分: 0

在2022年,您还可以测试eigenhombre/l1,这是由John Jacobsen用Go语言编写的一个小型Lisp 1

它在"(Yet Another) Lisp In Go"中进行了介绍。

它在提交 b3a84e1中包含了对S表达式的解析和测试。

func TestSexprStrings(T *testing.T) {
	var tests = []struct {
		input sexpr
		want  string
	}{
		{Nil, "()"},
		{Num(1), "1"},
		{Num("2"), "2"},
		{Cons(Num(1), Cons(Num("2"), Nil)), "(1 2)"},
		{Cons(Num(1), Cons(Num("2"), Cons(Num(3), Nil))), "(1 2 3)"},
		{Cons(
			Cons(
				Num(3),
				Cons(
					Num("1309875618907812098"),
					Nil)),
			Cons(Num(5), Cons(Num("6"), Nil))), "((3 1309875618907812098) 5 6)"},
	}
英文:

In 2022, you can also test eigenhombre/l1, a small Lisp 1 written in Go, by John Jacobsen .

It is presented in "(Yet Another) Lisp In Go"

It does include in commit b3a84e1 a parsing and tests for S-expressions.

func TestSexprStrings(T *testing.T) {
	var tests = []struct {
		input sexpr
		want  string
	}{
		{Nil, "()"},
		{Num(1), "1"},
		{Num("2"), "2"},
		{Cons(Num(1), Cons(Num("2"), Nil)), "(1 2)"},
		{Cons(Num(1), Cons(Num("2"), Cons(Num(3), Nil))), "(1 2 3)"},
		{Cons(
			Cons(
				Num(3),
				Cons(
					Num("1309875618907812098"),
					Nil)),
			Cons(Num(5), Cons(Num("6"), Nil))), "((3 1309875618907812098) 5 6)"},
	}

huangapple
  • 本文由 发表于 2015年7月9日 04:14:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/31302815.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定