簡體   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