繁体   English   中英

有问题的简单 YACC 语法

[英]Simple YACC grammar with problems

我想实现一个简单的 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) }}
    ;

有人向我解释为什么它会给我这些错误?:

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

conflicts: 3 reduce/reduce

在评论中,澄清要求是:

NOT运算符应仅适用于AND的操作数,[操作数] 不应同时为NOT

该要求的第二部分有点奇怪,因为AND运算符被定义为左关联。 那将意味着

a AND NOT b AND NOT c

将是合法的,因为它被分组为(a AND NOT b) AND NOT c ,其中两个AND运算符都有一个正项。 但是旋转参数(这可能根本不会改变语义)会产生:

NOT b AND NOT c AND a

这是非法的,因为第一个分组( NOT b AND NOT c )包含两个NOT表达式。

其意图可能是任何连词( AND运算符的序列)至少包含一个正项。

这两种约束都是可能的,但不能使用运算符优先级声明来实现。

运算符优先级可用于解决歧义文法中的歧义(并且expr: expr OR expr肯定是歧义的,因为它允许OR在任一方向关联)。 但它不能用于导入对操作数的附加要求,特别是不能同时考虑两个操作数的要求 [注 1]。 为了做到这一点,你需要写出一个明确的语法。 幸运的是,这并不太难。

明确语法的基础是有时称为级联优先风格; 这有效地将优先级编码为规则,因此不需要优先级声明。 基本的布尔语法如下所示:

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

每个优先级都有一个相应的非终结符,并且这些级别是“级联”的,意思是除了最后一个级别之外,每个级别都包括下一个级别作为一个单元产品。

为了适应这种的要求,即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

对于第三个规则conjunctionconjunction: conjunction AND NOT atom )允许任意数量的NOT在操作数的一个列表的末尾将被添加的应用程序,但不允许连续NOT操作数在列表的开头。 第四条规则允许在开头有一个NOT

如果您更喜欢连词必须至少有一个正项的规则,您可以使用以下非常简单的改编:

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

在这个变体中, negative将匹配,例如NOT a AND NOT b AND NOT c 但是因为它不在级联中,所以该序列不会自动成为有效的表达式。 为了将它用作表达式,它需要是连接的一部分conjunction: negative AND atom ,这要求序列包含正数。

笔记

  1. %nonassoc优先级声明可用于拒绝相同优先级的运算符的链式使用。 这有点像黑客攻击,有时会产生意想不到的后果。 预期的用例是像 C 这样的语言中的运算符< ,它没有对链式比较进行特殊处理; 使用%nonassoc您可以声明在比较运算符的优先级中链接是非法的。

    但是%nonassoc仅在单个优先级内有效,并且只有在优先级中的所有运算符都需要相同处理时才有效。 如果预期的语法不完全符合这些要求,则有必要 - 与此语法一样 - 放弃使用优先级声明并写出明确的语法。

暂无
暂无

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

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