Pyparsing中的递归

时间:2015-10-13 15:56:01

标签: python recursion pyparsing ebnf

我无法将此EBNF表达式转换为Pyparsing,任何想法?

token:: [A-Z]
P:: !|token;P|(P^P)|(P*P)

问题是当使用递归时,解释器失败。 这样的表达应该是有效的:

(ASD;!^FFF;!)
A;B;C;!
(((A;!^B;!)^C;D;!)*E;!)

2 个答案:

答案 0 :(得分:3)

要使用Pyparsing构建递归语法,您必须使用pyparsing的Forward类来从内到外思考。使用Forward,您可以为稍后定义的表达式定义空占位符。这是这个BNF的pyparsing的开始:

EXCLAM,SEMI,HAT,STAR = map(Literal,"!;^*")
LPAR,RPAR = map(Suppress,"()")
token = oneOf(list(alphas.upper()))

我使用Literal定义您的运算符,但是抑制分组(),我们将使用pyparsing Group将结果物理分组到子列表中。

现在我们使用Forward:

定义占位符表达式
expr = Forward()

现在我们可以使用这个占位符构建表达式(我们必须使用'<< ='作为赋值运算符,以便将expr维护为Forward,而不是反弹到表达式本身)。这是我的第一个传球,原样使用你的BNF:

expr <<= (EXCLAM | 
          token + SEMI + expr | 
          Group(LPAR + expr + HAT + expr + RPAR) | 
          Group(LPAR + expr + STAR + expr + RPAR))

这给出了这些结果:

(ASD;!^FFF;!)
  ^
Expected ";" (at char 2), (line:1, col:3)

A;B;C;!
['A', ';', 'B', ';', 'C', ';', '!']

(((A;!^B;!)^C;D;!)*E;!)
[[[['A', ';', '!', '^', 'B', ';', '!'], '^', 'C', ';', 'D', ';', '!'], '*', 'E', ';', '!']]

在您的BNF中似乎存在一条不成文的规则,即一个或多个令牌也可以存在,很容易修复为:

expr <<= (EXCLAM | 
          OneOrMore(token) + SEMI + expr | 
          Group(LPAR + expr + HAT + expr + RPAR) | 
          Group(LPAR + expr + STAR + expr + RPAR))

现在给予:

(ASD;!^FFF;!)
[['A', 'S', 'D', ';', '!', '^', 'F', 'F', 'F', ';', '!']]

A;B;C;!
['A', ';', 'B', ';', 'C', ';', '!']

(((A;!^B;!)^C;D;!)*E;!)
[[[['A', ';', '!', '^', 'B', ';', '!'], '^', 'C', ';', 'D', ';', '!'], '*', 'E', ';', '!']]

但看起来我们可以从额外的分组中受益,因此二进制分析的操作数会很快。和&#39; *&#39;运营商分组更清晰。所以我决定:

expr <<= (EXCLAM | 
          Group(OneOrMore(token) + SEMI + ungroup(expr)) | 
          Group(LPAR + expr + HAT + expr + RPAR) | 
          Group(LPAR + expr + STAR + expr + RPAR) )

我认为此版本的输出现在将更容易处理:

(ASD;!^FFF;!)
[[['A', 'S', 'D', ';', '!'], '^', ['F', 'F', 'F', ';', '!']]]

A;B;C;!
[['A', ';', 'B', ';', 'C', ';', '!']]

(((A;!^B;!)^C;D;!)*E;!)
[[[[['A', ';', '!'], '^', ['B', ';', '!']], '^', ['C', ';', 'D', ';', '!']], '*', ['E', ';', '!']]]

这是完整的脚本:

from pyparsing import *

EXCLAM,SEMI,HAT,STAR = map(Literal,"!;^*")
LPAR,RPAR = map(Suppress,"()")
token = oneOf(list(alphas.upper()))
expr = Forward()
expr <<= (EXCLAM | 
          Group(OneOrMore(token) + SEMI + ungroup(expr)) | 
          Group(LPAR + expr + HAT + expr + RPAR) | 
          Group(LPAR + expr + STAR + expr + RPAR) )

tests = """\
(ASD;!^FFF;!)
A;B;C;!
(((A;!^B;!)^C;D;!)*E;!)""".splitlines()

for t in tests:
    print t
    try:
        print expr.parseString(t).dump()
    except ParseException as pe:
        print ' '*pe.loc + '^'
        print pe
    print

最后一点:我认为&#34; AAA&#34;连续3次&#39; A&#39;令牌。如果您认为令牌是1个或更多alpha的单词分组,那么请更改OneOrMore(令牌)&#39;在表达到&#39; Word(alphas.upper())&#39; - 然后你会得到第一个测试用例的结果:

[[['ASD', ';', '!'], '^', ['FFF', ';', '!']]]

答案 1 :(得分:1)

这使得Lisp符号工作xD !!

namespace DataRetrieval.ViewModel
{
    class ParametersViewModel:BindableBase
    {
        public ParametersViewModel()
        {

            AParams = new WhereParams();
            Qtables = new QDatatables();
            for (int j = 0; j < 5;j++ )
            {


                for (int i = 0; i < 10; ++i)
                {
                    int[] numbers;
                    numbers = new int[3] { 1, 2, 3 };
                    var parameter = new WhereParam { ID = i, Name = "Name " + i.ToString() };

                    if (i == 2 || i == 4)
                    {
                        parameter.Type = ParamTypeEnum.datetimeType;
                    }
                    AParams.Add(parameter);
                }
                var qtable = new QDatatable {  ID=j, Name = j.ToString() + "QTable",  Params = AParams};
                Qtables.Add(qtable);
            }
        }
        private WhereParam _parameter;
        public WhereParam Parameter
        {
            get { return _parameter; }
            set
            {
                SetProperty(ref _parameter, value);
                }
        }
        private WhereParams _paramas;
        public WhereParams AParams
        {
            get { return _paramas; }
            set { SetProperty(ref _paramas, value); }
        }
        private QDatatables _qtables;
        public QDatatables Qtables
        {
            get { return _qtables; }
            set
            {
                SetProperty(ref _qtables, value);

            }
        }




    }
}