使用 pyparsing 的递归表达式

发布于 2024-10-09 20:50:04 字数 472 浏览 0 评论 0原文

我试图弄清楚如何执行左关联表达式,其中递归(不包含在任何内容中)表达式是可能的。例如,我想做:

expr + OP + expr

1 x 2 x 3 等 2 个操作解析为 (expr OP expr) OP expr 结果。

如果我尝试阻止无限递归解析expr,我可以执行以下操作:

expr -> Group(simple_expr + OP + expr)
      | simple_expr

但随后我会得到expr OP(expr OR expr)结果。

如何强制左侧装订?

编辑:我知道 operatorPrecedence 但当运算符为 "IS" +Optional("NOT") 或类似操作符时,它似乎无法正确匹配。

I'm trying to figure out how to do a left-associative expression where recursive (not-enclosed in anything) expressions are possible. For example, I'd like to do:

expr + OP + expr

that parses 2 operations like 1 x 2 x 3 into (expr OP expr) OP expr result.

If I try to prevent expr parsing from infinite recursion, i can do something like:

expr -> Group(simple_expr + OP + expr)
      | simple_expr

but then I'd get the expr OP (expr OR expr) result.

How do I force left-side binding?

Edit: I know about the operatorPrecedence but when the operator is "IS" + Optional("NOT") or similar, it doesn't seem to match properly.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

亣腦蒛氧 2024-10-16 20:50:04

下面是一个示例解析操作,它将采用令牌的平面列表并将它们嵌套起来,就像左递归解析一样:

from pyparsing import *

# parse action -maker
def makeLRlike(numterms):
    if numterms is None:
        # None operator can only by binary op
        initlen = 2
        incr = 1
    else:
        initlen = {0:1,1:2,2:3,3:5}[numterms]
        incr = {0:1,1:1,2:2,3:4}[numterms]

    # define parse action for this number of terms,
    # to convert flat list of tokens into nested list
    def pa(s,l,t):
        t = t[0]
        if len(t) > initlen:
            ret = ParseResults(t[:initlen])
            i = initlen
            while i < len(t):
                ret = ParseResults([ret] + t[i:i+incr])
                i += incr
            return ParseResults([ret])
    return pa


# setup a simple grammar for 4-function arithmetic
varname = oneOf(list(alphas))
integer = Word(nums)
operand = integer | varname

# ordinary opPrec definition
arith1 = operatorPrecedence(operand,
    [
    (None, 2, opAssoc.LEFT),
    (oneOf("* /"), 2, opAssoc.LEFT),
    (oneOf("+ -"), 2, opAssoc.LEFT),
    ])

# opPrec definition with parseAction makeLRlike
arith2 = operatorPrecedence(operand,
    [
    (None, 2, opAssoc.LEFT, makeLRlike(None)),
    (oneOf("* /"), 2, opAssoc.LEFT, makeLRlike(2)),
    (oneOf("+ -"), 2, opAssoc.LEFT, makeLRlike(2)),
    ])

# parse a few test strings, using both parsers
for arith in (arith1, arith2):
    print arith.parseString("A+B+C+D+E")[0]
    print arith.parseString("A+B+C*D+E")[0]
    print arith.parseString("12AX+34BY+C*5DZ+E")[0]

打印:(

正常)

['A', '+', 'B', '+', 'C', '+', 'D', '+', 'E']
['A', '+', 'B', '+', ['C', '*', 'D'], '+', 'E']
[['12', 'A', 'X'], '+', ['34', 'B', 'Y'], '+', ['C', '*', ['5', 'D', 'Z']], '+', 'E']

(类似 LR)

[[[['A', '+', 'B'], '+', 'C'], '+', 'D'], '+', 'E']
[[['A', '+', 'B'], '+', ['C', '*', 'D']], '+', 'E']
[[[[['12', 'A'], 'X'], '+', [['34', 'B'], 'Y']], '+', ['C', '*', [['5', 'D'], 'Z']]], '+', 'E']

Here is an example parse action that will take the flat lists of tokens and nest them as if parsed left-recursively:

from pyparsing import *

# parse action -maker
def makeLRlike(numterms):
    if numterms is None:
        # None operator can only by binary op
        initlen = 2
        incr = 1
    else:
        initlen = {0:1,1:2,2:3,3:5}[numterms]
        incr = {0:1,1:1,2:2,3:4}[numterms]

    # define parse action for this number of terms,
    # to convert flat list of tokens into nested list
    def pa(s,l,t):
        t = t[0]
        if len(t) > initlen:
            ret = ParseResults(t[:initlen])
            i = initlen
            while i < len(t):
                ret = ParseResults([ret] + t[i:i+incr])
                i += incr
            return ParseResults([ret])
    return pa


# setup a simple grammar for 4-function arithmetic
varname = oneOf(list(alphas))
integer = Word(nums)
operand = integer | varname

# ordinary opPrec definition
arith1 = operatorPrecedence(operand,
    [
    (None, 2, opAssoc.LEFT),
    (oneOf("* /"), 2, opAssoc.LEFT),
    (oneOf("+ -"), 2, opAssoc.LEFT),
    ])

# opPrec definition with parseAction makeLRlike
arith2 = operatorPrecedence(operand,
    [
    (None, 2, opAssoc.LEFT, makeLRlike(None)),
    (oneOf("* /"), 2, opAssoc.LEFT, makeLRlike(2)),
    (oneOf("+ -"), 2, opAssoc.LEFT, makeLRlike(2)),
    ])

# parse a few test strings, using both parsers
for arith in (arith1, arith2):
    print arith.parseString("A+B+C+D+E")[0]
    print arith.parseString("A+B+C*D+E")[0]
    print arith.parseString("12AX+34BY+C*5DZ+E")[0]

Prints:

(normal)

['A', '+', 'B', '+', 'C', '+', 'D', '+', 'E']
['A', '+', 'B', '+', ['C', '*', 'D'], '+', 'E']
[['12', 'A', 'X'], '+', ['34', 'B', 'Y'], '+', ['C', '*', ['5', 'D', 'Z']], '+', 'E']

(LR-like)

[[[['A', '+', 'B'], '+', 'C'], '+', 'D'], '+', 'E']
[[['A', '+', 'B'], '+', ['C', '*', 'D']], '+', 'E']
[[[[['12', 'A'], 'X'], '+', [['34', 'B'], 'Y']], '+', ['C', '*', [['5', 'D'], 'Z']]], '+', 'E']
聊慰 2024-10-16 20:50:04

Pyparsing 生成左解析树。添加语义操作以在解析 expr 后立即编辑解析树。

Pyparsing produces left parse trees. Add a semantic action to edit the parse tree right after expr has been parsed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文