优先权问题

Trouble With Precedence

我正在尝试为相对简单的语法生成解析器,但我无法让我的优先级正常工作。

我已经设法减少到 15 个 shift/reduce 个错误,但我不知道如何修复剩下的几个 - 它们可能与我的优先级问题有关。

我有这样定义的语法:

%nonassoc T_LEN T_OPENPAREN T_CLOSEPAREN T_NUM T_ID T_QUOTE T_TRUE T_FALSE
%left T_GT T_GTE T_LT T_LTE T_EQ
%left T_OR
%left T_AND
%left T_NOT

Start           : Expression                                    { astRoot = new MainNode(  ); }
                ;

Expression      : Expression T_OR Expression                    { $$ = new OrNode( ,  ); }
                | Expression T_AND Expression                   { $$ = new AndNode( ,  ); }
                | Expression Expression                         { $$ = new AndNode( ,  ); }
                | T_NOT Expression                              { $$ = new NotNode(  ); }
                | T_GT Expression                               { $$ = new GreaterNode(  ); }
                | T_GTE Expression                              { $$ = new GreaterEqualNode(  ); }
                | T_LT Expression                               { $$ = new LessNode(  ); }
                | T_LTE Expression                              { $$ = new LessEqualNode(  ); }
                | T_EQ Expression                               { $$ = new EqualNode(  ); }
                | T_LEN T_OPENPAREN T_NUM T_CLOSEPAREN          { $$ = new LenNode( new IntegerNode(  ) ); }
                | T_OPENPAREN Expression T_CLOSEPAREN           { $$ = ; }
                | T_TRUE                                        { $$ = new BoolTrueNode; }
                | T_FALSE                                       { $$ = new BoolFalseNode; }
                | T_ID                                          { $$ = new IdentifierNode(  ); }
                | T_NUM                                         { $$ = new IntegerNode(  ); }
                | T_QUOTE                                       { $$ = new QuoteNode( new IdentifierNode(  ) ); }
                ;

尝试解析以下内容时,我没有得到我想要的值:

100 T_AND 200 T_AND 300 T_AND 400 T_OR 1000
output => And( "100", And( "200", And( "300", Or( "400", "1000" ) ) ) );
expect => Or( And( "100", And( "200", And( "300", "400" ) ) ), "1000" );

最后,我的解析器输出的相关部分是:

State 27 conflicts: 15 shift/reduce

0 $accept: Start $end

1 Start:       Expression

2 Expression:  Expression T_OR Expression
3            | Expression T_AND Expression
4            | Expression Expression
5            | T_NOT Expression
6            | T_GT Expression
7            | T_GTE Expression
8            | T_LT Expression
9            | T_LTE Expression
10           | T_EQ Expression
11           | T_LEN T_OPENPAREN T_NUM T_CLOSEPAREN
12           | T_OPENPAREN Expression T_CLOSEPAREN
13           | T_TRUE
14           | T_FALSE
15           | T_ID
16           | T_NUM
17           | T_QUOTE

State 27

    2 Expression: Expression . T_OR Expression
    3           | Expression . T_AND Expression
    4           | Expression . Expression
    4           | Expression Expression .

    T_LEN        shift, and go to state 1
    T_OPENPAREN  shift, and go to state 2
    T_NUM        shift, and go to state 3
    T_ID         shift, and go to state 4
    T_QUOTE      shift, and go to state 5
    T_TRUE       shift, and go to state 6
    T_FALSE      shift, and go to state 7
    T_GT         shift, and go to state 8
    T_GTE        shift, and go to state 9
    T_LT         shift, and go to state 10
    T_LTE        shift, and go to state 11
    T_EQ         shift, and go to state 12
    T_OR         shift, and go to state 25
    T_AND        shift, and go to state 26
    T_NOT        shift, and go to state 13

    T_LEN        [reduce using rule 4 (Expression)]
    T_OPENPAREN  [reduce using rule 4 (Expression)]
    T_NUM        [reduce using rule 4 (Expression)]
    T_ID         [reduce using rule 4 (Expression)]
    T_QUOTE      [reduce using rule 4 (Expression)]
    T_TRUE       [reduce using rule 4 (Expression)]
    T_FALSE      [reduce using rule 4 (Expression)]
    T_GT         [reduce using rule 4 (Expression)]
    T_GTE        [reduce using rule 4 (Expression)]
    T_LT         [reduce using rule 4 (Expression)]
    T_LTE        [reduce using rule 4 (Expression)]
    T_EQ         [reduce using rule 4 (Expression)]
    T_OR         [reduce using rule 4 (Expression)]
    T_AND        [reduce using rule 4 (Expression)]
    T_NOT        [reduce using rule 4 (Expression)]
    $default     reduce using rule 4 (Expression)

    Expression  go to state 27

据我所知,问题可能是由隐含的 and(规则 3 和 4)引起的。如果这是问题的根源,我该如何解决?

谢谢!

在写这个问题的时候,我才意识到隐含的可能是问题的根源。现在,对可能出现的问题有了更深入的了解,我能够编写正确的 google 查询,将我引导至 this post.

阅读答案后,解决方案就到位了。我选择了通过语法的显式优先级,而不是通过 bison 的优先级声明的隐式优先级。这给了我以下语法:

Start           : Expression                                    { astRoot = new MainNode(  ); }
                ;

Term            : T_TRUE                                        { $$ = new BoolTrueNode; }
                | T_FALSE                                       { $$ = new BoolFalseNode; }
                | T_ID                                          { $$ = new IdentifierNode(  ); }
                | T_NUM                                         { $$ = new IntegerNode(  ); }
                | T_QUOTE                                       { $$ = new QuoteNode( new IdentifierNode(  ) ); }
                | T_LEN T_OPENPAREN T_NUM T_CLOSEPAREN          { $$ = new LenNode( new IntegerNode(  ) ); }
                | T_OPENPAREN Expression T_CLOSEPAREN           { $$ = ; }
                ;

Prefix          : Term
                | T_NOT Prefix                                  { $$ = new NotNode(  ); }
                | T_GT Term                                     { $$ = new GreaterNode(  ); }
                | T_GTE Term                                    { $$ = new GreaterEqualNode(  ); }
                | T_LT Term                                     { $$ = new LessNode(  ); }
                | T_LTE Term                                    { $$ = new LessEqualNode(  ); }
                | T_EQ Term                                     { $$ = new EqualNode(  ); }
                ;

Factor          : Prefix
                | Prefix Factor                                 { $$ = new AndNode( ,  ); }
                ;

Andor           : Factor
                | Andor T_AND Factor                            { $$ = new AndNode( ,  ); }
                ;

Expression      : Andor
                | Expression T_OR Andor                         { $$ = new OrNode( ,  ); }
                ;

这给了我 0 shift/reduce 个冲突和我目前在所有测试中期望的值。同样以这种方式安排我的语法使语言的更微妙的细微差别变得明显,例如以下陈述的有效性:

T_NOT T_GT 100 => Not( Greater( "100" ) ) => valid
T_GT T_NOT 100 => Greater( Not( "100" ) ) => invalid

除非有人发现我提供的语法有任何隐藏的问题,否则我相信这已经完全解决了我的问题。