2012-10-28 21 views
1

我正试图使用​​Java实现一个简单的Lisp表达式求值器。实际上有关于这个主题的大量信息,但看起来他们都使用两个单独的堆栈来获得结果。我想知道是否有可能只用一个堆栈来实现这样的程序,以及一些伪代码可能看起来像这样。Java中的Lisp表达式求值器(仅使用一个堆栈)

谢谢。

欲了解更多信息什么我谈论指

回答

3

两个链接到您提出一个非常重要的假设的解释:即+, - ,*等都是二元函数,也就是说,它们总是只有两个参数。在真正的Lisp中,你可以说(+ 1 2 3 4 5)来总结一堆数字。但是,如果您愿意接受简单的假设,即每个运营商的身份都是已知的,那么您绝对可以只用一个堆栈来完成此操作。关键是:将堆放倒。

您链接到有这样的堆栈的解释:

底部 - >(+ (- 2 1) 4) < - 顶部(我们推动并从这里流行)

但是,你也可以阅读你的表达倒退,从权,并建立堆栈是这样的:

顶 - >(+ (- 2 1) 4) < - 底部

那么你基本上得到RPN,逆波兰式。 RPN在堆叠中的表现非常好。

的算法是这样的:

  • 如果你看到一个括号,忽略它
  • 如果你看到一个操作数,将其推入堆栈
  • 如果你看到一个运营商,调用它。操作员弹出尽可能多的值,然后将其结果推送到堆栈上

取例如(+ (- 2 1) 4)。下面是该算法将操作:

堆栈:阅读:)操作:括号忽略。 左:(+ (- 2 1) 4

堆栈:阅读:4操作:操作数压入堆栈。左:(+ (- 2 1)

堆栈:阅读:)操作:括号忽略。 左:(+ (- 2 1

堆栈:阅读:1操作:操作数压入堆栈。 左:(+ (- 2

堆栈:读:2操作:操作数压入堆栈。 左:(+ (-

堆栈:读:-操作:操作员调用。它会从堆栈中弹出2和1,然后将2-1=1推到其上。 左:(+ (

堆栈:阅读:(操作:括号忽略。 左:(+

堆栈:阅读:+操作:操作者调用。它会从堆栈中弹出1和4,然后将1+4=5推到其上。 左:(

堆栈:阅读:(操作:括号忽略。 左:什么

完成!结果如预期的那样是5。

PS关于忽略括号。只要你输入的表达式格式良好,这可以很好地工作,但是它可能会采用非格式表达式,并给它们无意义的值。例如(+ - + 1 2 3 4)被解释为(+ (- (+ 1 2) 3) 4)。如果你想防止这种行为,只需将圆括号插入堆栈。当调用操作符时,弹出参数,加上一个额外的标记。 确保该标记是近距离的,否则会抛出错误。一旦你有结果,将其推入堆栈。 确保您读入的下一个标记是开放标记,然后丢弃它

PPS这一切都变得复杂得多,如果在真实的Lisp中,函数的参数本身可以是函数。然后,您不需要RPN依赖的操作符/操作数之间的便捷区分,并且您需要更多地关注括号作为分组元素。我不知道你是否可以做一个完整的Lisp表达式求值器,它只有一个堆栈,可变参数和函数作为操作数。