简体   繁体   English

有问题的简单 YACC 语法

[英]Simple YACC grammar with problems

I want to implement a simple YACC parser, but I have problems with my grammar:我想实现一个简单的 YACC 解析器,但我的语法有问题:

%union {
    s       string
    b       []byte
    t       *ASTNode
}

%token AND OR NOT
%token<s> STRING
%token<b> BYTES

%type<t> expr

%left AND
%left OR
%right NOT

%%

expr: '(' expr ')'              {{ $$ = $2 }}
    | expr AND expr             {{ $$ = NewASTComplexNode(OPND_AND, $1, $3) }}
    | expr AND NOT expr         {{ $$ = NewASTComplexNode(OPND_AND, $1, NewASTComplexNode(OPND_NOT, $4, nil)) }}
    | NOT expr AND expr         {{ $$ = NewASTComplexNode(OPND_AND, NewASTComplexNode(OPND_NOT, $2, nil), $4) }}
    | expr OR expr              {{ $$ = NewASTComplexNode(OPND_OR, $1, $3) }}
    | STRING                    {{ $$ = NewASTSimpleNode(OPRT_STRING, $1) }}
    | BYTES                     {{ $$ = NewASTSimpleNode(OPRT_BYTES, $1) }}
    ;

Cam someone explain me why it gives me these errors?:有人向我解释为什么它会给我这些错误?:

rule expr:  NOT expr AND expr  never reduced
1 rules never reduced

conflicts: 3 reduce/reduce

In a comment, it is clarified that the requirement is that:在评论中,澄清要求是:

The NOT operator should apply only to operands of AND and [the operands] shouldn't be both NOT . NOT运算符应仅适用于AND的操作数,[操作数] 不应同时为NOT

The second part of that requirement is a little odd, since the AND operator is defined to be left-associative.该要求的第二部分有点奇怪,因为AND运算符被定义为左关联。 That would mean that那将意味着

a AND NOT b AND NOT c

would be legal, because it is grouped as (a AND NOT b) AND NOT c , in which both AND operators have one positive term.将是合法的,因为它被分组为(a AND NOT b) AND NOT c ,其中两个AND运算符都有一个正项。 But rotating the arguments (which might not change the semantics at all) produces:但是旋转参数(这可能根本不会改变语义)会产生:

NOT b AND NOT c AND a

which would be illegal because the first grouping ( NOT b AND NOT c ) contains two NOT expressions.这是非法的,因为第一个分组( NOT b AND NOT c )包含两个NOT表达式。

It might be that the intention was that any conjunction (sequence of AND operators) contain at least one positive term.其意图可能是任何连词( AND运算符的序列)至少包含一个正项。

Both of these constraints are possible, but they cannot be achieved using operator precedence declarations.这两种约束都是可能的,但不能使用运算符优先级声明来实现。

Operator precedence can be used to resolve ambiguity in an ambiguous grammar (and expr: expr OR expr is certainly ambiguous, since it allows OR to associate in either direction).运算符优先级可用于解决歧义文法中的歧义(并且expr: expr OR expr肯定是歧义的,因为它允许OR在任一方向关联)。 But it cannot be used to import additional requirements on operands, particularly not a requirement which takes both operands into account [Note 1].但它不能用于导入对操作数的附加要求,特别是不能同时考虑两个操作数的要求 [注 1]。 In order to do that, you need to write out an unambiguous grammar.为了做到这一点,你需要写出一个明确的语法。 Fortunately, that's not too difficult.幸运的是,这并不太难。

The basis for the unambiguous grammar is what is sometimes called cascading precedence style;明确语法的基础是有时称为级联优先风格; this effectively encodes the precedence into rules, so that precedence declarations are unnecessary.这有效地将优先级编码为规则,因此不需要优先级声明。 The basic boolean grammar looks like this:基本的布尔语法如下所示:

expr: conjunction           /* Cascade to the next level */
    | expr OR conjunction
conjunction
    : term                  /* Continue the cascade */
    | conjunction AND term
term: atom                  /* NOT is a prefix operator */
    | NOT term              /* which is not what you want */
atom: '(' expr ')'
    | STRING

Each precedence level has a corresponding non-terminal, and the levels "cascade" in the sense that each one, except the last, includes the next level as a unit production.每个优先级都有一个相应的非终结符,并且这些级别是“级联”的,意思是除了最后一个级别之外,每个级别都包括下一个级别作为一个单元产品。

To adapt this to the requirement that NOT be restricted to at most one operand of an AND operator, we can write out the possibilities more or less as you did in the original grammar, but respecting the cascading style:为了适应这种的要求,即NOT被限制的最多一个操作数AND运算符,我们可以写出来的可能性或多或少,你在原来的语法一样,但尊重级联样式:

expr: conjunction
    | expr OR conjunction
conjunction
    : atom                     /* NOT is integrated, so no need for 'term' */
    | conjunction AND atom
    | conjunction AND NOT atom /* Can extend with a negative */
    | NOT atom AND atom        /* Special case for negative at beginning */
    
atom: '(' expr ')'            
    | STRING

The third rule for conjunction ( conjunction: conjunction AND NOT atom ) allows any number of NOT applications to be added at the end of a list of operands, but does not allow consecutive NOT operands at the beginning of the list.对于第三个规则conjunctionconjunction: conjunction AND NOT atom )允许任意数量的NOT在操作数的一个列表的末尾将被添加的应用程序,但不允许连续NOT操作数在列表的开头。 A single NOT at the beginning is allowed by the fourth rule.第四条规则允许在开头有一个NOT

If you prefer the rule that a conjunction has to have at least one positive term, you can use the following very simple adaptation:如果您更喜欢连词必须至少有一个正项的规则,您可以使用以下非常简单的改编:

expr: conjunction
    | expr OR conjunction
conjunction
    : atom                     /* NOT is integrated, so no need for 'term' */
    | conjunction AND atom
    | conjunction AND NOT atom
    | negative AND atom        /* Possible initial list of negatives */
negative                       /* This is not part of the cascade */
    : NOT atom
    | negative AND NOT atom
atom: '(' expr ')'            
    | STRING

In this variant, negative will match, for example, NOT a AND NOT b AND NOT c .在这个变体中, negative将匹配,例如NOT a AND NOT b AND NOT c But because it's not in the cascade, that sequence doesn't automatically become a valid expression.但是因为它不在级联中,所以该序列不会自动成为有效的表达式。 In order for it to be used as an expression, it needs to be part of conjunction: negative AND atom , which requires that the sequence include a positive.为了将它用作表达式,它需要是连接的一部分conjunction: negative AND atom ,这要求序列包含正数。

Notes笔记

  1. The %nonassoc precedence declaration can be used to reject chained use of operators from the same precedence level. %nonassoc优先级声明可用于拒绝相同优先级的运算符的链式使用。 It's a bit of a hack, and can sometimes have unexpected consequences.这有点像黑客攻击,有时会产生意想不到的后果。 The expected use case is operators like < in languages like C which don't have special handling for chained comparison;预期的用例是像 C 这样的语言中的运算符< ,它没有对链式比较进行特殊处理; using %nonassoc you can declare that chaining is illegal in the precedence level for comparison operators.使用%nonassoc您可以声明在比较运算符的优先级中链接是非法的。

    But %nonassoc only works within a single precedence level, and it only works if all the operators in the precedence level require the same treatment.但是%nonassoc仅在单个优先级内有效,并且只有在优先级中的所有运算符都需要相同处理时才有效。 If the intended grammar does not fully conform to those requirements, it will be necessary -- as with this grammar -- to abandon the use of precedence declarations and write out an unambiguous grammar.如果预期的语法不完全符合这些要求,则有必要 - 与此语法一样 - 放弃使用优先级声明并写出明确的语法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM