3

我正在尝试使用 python pyparsing 进行解析。我在制作递归解析器时遇到了困难。

让我解释一下问题

我想制作元素的笛卡尔积。语法是

cross({elements },{element})

我以更具体的方式

cross({a},{c1}) or cross({a,b},{c1}) or cross({a,b,c,d},{c1}) or 

所以一般形式是第一组将有n个元素(a,b,c,d)。第二组将有一个元素,因此最终输出将是笛卡尔积。

语法是递归的,因为它可以像

cross(cross({a,b},{c1}),{c2})

这意味着将 a、b 与 c1 交叉。让我们说结果我们y。我们再次将它与 c2 交叉

这可以直到 n 级 cross(cross(cross(cross......

我想要的是使用 setparseAction 初始化对象

所以我会有2节课

class object1(object):
     This will be used by a,b,c,d 

class object2(object):
       This will hold cross elements

我需要帮助,我无法制作递归解析器。

4

3 回答 3

6

您应该查看其他语言的定义,以了解通常如何处理。

例如,看看乘法是如何定义的。

它不是

{expression} * {expression}

因为递归很难处理,并且没有隐含的从左到右的顺序。你更经常看到的是类似的东西

{term} + {factor}
{factor} * {unary-expression}

这将优先级和从左到右的顺序放在运算符周围。

查看http://www.cs.man.ac.uk/~pjj/bnf/c_syntax.bnf之类的内容,以了解此类事物的常见结构示例。

于 2009-03-11T13:14:33.687 回答
4

我同意@S.Lott 你应该重新考虑你的语法。

可以使用以下方法引入递归定义Forward()

from pyparsing import (Literal, Word, OneOrMore, Forward, nums, alphas)

def BNF():
    """
    element      :: id
    elements     :: '{' element [ ',' element ]+ '}' 
                  | 'cross' '(' elements ',' '{' element '}' ')'
    """
    lcb, rcb, lb, rb, comma = [Literal(c).suppress() for c in '{}(),']
    element  = Word(alphas, alphas+nums+"_") # id
    elements = Forward()
    elements << ((lcb + element + OneOrMore(comma + element) + rcb) 
                 | (Literal('cross') + lb + elements + comma
                    + lcb + element + rcb + rb))
    return elements

print BNF().parseString("cross(cross({a,b},{c1}),{c2})")

输出:

['cross', 'cross', 'a', 'b', 'c1', 'c2']
于 2009-03-11T14:24:58.477 回答
3

我不知道这是否有帮助,但这里是你在 lepl 中做你想做的事情的方法。由于语法似乎是正确的,我认为它很容易翻译成 pyparsing。

from lepl import *

def compile_parser():

    class Cross(Node): pass

    word = Token('[a-z0-9]+')
    par, en, bra, ket = [~Token('\\'+c) for c in '(){}']
    comma = ~Token(',')

    cross  = Delayed()
    vector = bra & word[1:,comma] & ket                 > list
    arg    = vector | cross
    cross += ~word('cross') & par & arg[2,comma] & en   > Cross

    parser = cross.string_parser()
    return lambda expr: parser(expr)[0]


if __name__ == '__main__':

    parser = compile_parser()
    print parser('cross({a},{c1})')
    print parser('cross({a,b},{c1})')
    print parser('cross({a,b,c,d},{c1})')
    print parser('cross(cross({a,b},{c1}),{c2})')

输出是:

Cross
 +- [u'a']
 `- [u'c1']

Cross
 +- [u'a', u'b']
 `- [u'c1']

Cross
 +- [u'a', u'b', u'c', u'd']
 `- [u'c1']

Cross
 +- Cross
 |   +- [u'a', u'b']
 |   `- [u'c1']
 `- [u'c2']
于 2009-11-04T12:08:47.280 回答