修改PLY解析器的堆栈

时间:2019-07-24 02:10:02

标签: yacc ply

试图修改已经推送到PLY / Yacc解析器堆栈的值。我在python 3上使用ply

基本上,我想在使用标记SWAP时反转前两个值。

想象我们有这个堆栈:

1234SWAP

我需要将其减少为:

1243

您写入p[0]的值将被压入堆栈,但是如何压入一个以上的值?

# this fails because it consume two values and pushes only one
# results into: `1`, `2`, `4`
def p_swap(p):
   'value : value value SWAP'
   p[0] = p[2]

# this was just a try... fails as well
def p_swap(p):
   'value : value value SWAP'
   p[0] = p[2]
   p[1] = p[1]

# this locked as a good idea since consumes only only value and modify the second in place
# it fails because the stack (negative indexes) are immutable:
# https://github.com/dabeaz/ply/blob/master/ply/yacc.py#L234
# results into: `1`, `2`, `3`, `3`
def p_swap(p):
   'value : value SWAP'
   p[0] = p[-1]
   p[-1] = p[1] # this is a NOP

p is an instance of this class

我猜它被设计为不可变的,以某种方式(正确的方式)执行解析,但是我却错过了:修改堆栈或设计解析器的正确方式是什么?

1 个答案:

答案 0 :(得分:0)

听起来您正在尝试创建一个stack-based language,例如Forth或Joy。如果是这样,则您不需要自底向上的解析器,也不必为自底向上的解析器生成器无法按您希望的方式工作而感到惊讶。

基于堆栈的语言大多只是令牌流。每个令牌都有某种堆栈效果,它们只是按顺序应用。除此之外,通常几乎没有语法结构。因此,实际上并没有解析语言。充其量是对它们进行标记化。

大多数基于堆栈的语言都包含某种嵌套控制结构,这些结构与上述严格不兼容(但不是全部;例如,请参阅Postscript)。但是,即使这些是如此简单,以至于真正的解析器也是不必要的。

当然,没有什么可以阻止您使用生成的解析器来解析普通语言。但是,如果这样做,您当然不应该期望能够访问解析器的内部数据结构。解析器堆栈由解析器以可能并不十分明显的方式使用,并且肯定不能受到干扰。如果要实现基于堆栈的语言解释器,则需要使用自己的值堆栈。 (或堆栈;许多基于堆栈的语言具有几个不同的堆栈,每个堆栈都有其自己的语义。)