我正在尝试使用Java实现一个简单的Lisp表达式求值程序。实际上有关于这个主题的大量信息,但似乎它们都使用两个单独的堆栈来得出结果。我想知道是否有可能只使用一个堆栈实现这样的程序,以及一些伪代码可能是什么样的。
感谢。
有关我正在谈论的内容的更多信息,请参阅
答案 0 :(得分:3)
你链接的两个解释器都做了一个非常重要的假设:+, - ,*等都是二进制函数,也就是说,它们总是只有两个参数。在真正的Lisp中,你可以说(+ 1 2 3 4 5)
来总结一堆数字。但是,如果你愿意接受每个运算符的arity已知的简化假设,那么你肯定只用一个堆栈就可以做到这一点。关键:翻转堆栈。
你链接的解释器有这样的堆栈:
bottom - > ( + ( - 2 1 ) 4 )
< - top(我们从此处推送)
但是,您也可以从右侧向后读取表达式,并像这样构建堆栈:
top - > ( + ( - 2 1 ) 4 )
< - bottom
然后你基本上得到RPN,反向抛光表示法。 RPN非常适合堆栈。
算法是这样的:
以( + ( - 2 1 ) 4 )
为例。以下是算法的运作方式:
堆叠: 为空 阅读: )
操作:括号被忽略。 左: ( + ( - 2 1 ) 4
堆叠: 为空 阅读: 4
操作:操作数被推送到堆叠。 左: ( + ( - 2 1 )
堆叠: 4 阅读: )
操作:括号被忽略。 左: ( + ( - 2 1
堆叠: 4 阅读: 1
操作:操作数被推送到堆叠。 左: ( + ( - 2
堆叠: 1 4 阅读: 2
操作:操作数被推送到堆叠。 左: ( + ( -
Stack: 2 1 4 阅读: -
操作:运算符已被调用。它会从堆栈中弹出2和1,然后将2-1=1
推到它上面。 左: ( + (
堆叠: 1 4 阅读: (
操作:括号被忽略。 左: ( +
Stack: 1 4 阅读: +
操作:运算符被调用。它会从堆栈弹出1和4,然后将1+4=5
推到它上面。 左: (
堆叠: 5 阅读: (
操作:括号被忽略。 左: 没有
完成!结果是5,正如预期的那样。
关于忽略括号的PS。只要您输入的表达式格式正确,这将完美地工作,但它可以采用非格式良好的表达式并赋予它们无意义的值。例如(+ - + 1 2 3 4)
被解释为(+ (- (+ 1 2) 3) 4)
。如果您想要阻止此行为,只需将紧密括号推入堆栈即可。当需要调用操作符时,弹出参数,再加上一个额外的标记。 确保令牌是紧密的,否则会抛出错误。获得结果后,将其推入堆栈。 确保您读入的下一个令牌是开放式的,然后将其丢弃。
答案 1 :(得分:0)