簡體   English   中英

YACC Bison GLR 解析器不會在減少/減少沖突時分裂

[英]YACC Bison GLR parser won't split on a reduce/reduce conflict

我在 GLR 模式下在 GNU Bison 中准備了一個解析器。 它有一個減少/減少沖突,因此我打開 GLR 模式,期望它會拆分解析器並繼續發現哪些解析工作。 但它不這樣做:

%{
#include <stdio.h>
int yylex ();
void yyerror(const char* msg);
%}

%glr-parser
%start start
%%

/* With input:
  ({}=0)

   the parser ought to split.
*/

start: AssignmentExpressionNB '\n';

AssignmentExpressionNB:
    PrimaryExpressionNB
    | PrimaryExpressionNB '=' AssignmentExpression
    ;
AssignmentExpression:
      PrimaryExpression /* This one will be rejected fast */
    | ObjectAssignmentPattern '=' AssignmentExpression /* This must kept. */
    | PrimaryExpression '=' AssignmentExpression /* This must also kept. */
    ;

PrimaryExpressionNB: 
      '0'
    | '(' PrimaryExpression ')' { $$ = $2; }
    ;
PrimaryExpression:
      '{' '}' { $$= 42; }
    | PrimaryExpressionNB { $$ = $1; }
    ;

ObjectAssignmentPattern: '{' '}';

%%
void yyerror(const char* msg) { printf("%s\n", msg); }
int yylex () {
    int c;
    while ((c = getchar ()) == ' ' || c == '\t');
    return c == EOF ? 0 : c;
}
int main (int argc, char** argv) {
    yydebug=1;
    return yyparse();
}

不幸的是,它沒有拆分,而是通過 AssignmentExpression 的第一個替代方法將 {} 簡化為 PrimaryExpression,然后出現語法錯誤:

Starting parse
Entering state 0
Reading a token
({}=0)
Next token is token '(' ()
Shifting token '(' ()
Entering state 2
Reading a token
Next token is token '{' ()
Shifting token '{' ()
Entering state 6
Reading a token
Next token is token '}' ()
Shifting token '}' ()
Entering state 12
Reducing stack 0 by rule 9 (line 34):
   $1 = token '{' ()
   $2 = token '}' ()
-> $$ = nterm PrimaryExpression ()
Entering state 8
Reading a token
Next token is token '=' ()
syntax error
Error: popping nterm PrimaryExpression ()
Error: popping token '(' ()
Cleanup: discarding lookahead token '=' ()

我認為 GNU Bison 現在應該拆分解析以確定哪些有效(如果有多個成功的解析,那么讓我選擇哪個。)

有沒有辦法獲得替代品?

該示例無疑是語法錯誤; GLR 無法改變這一點。

語法中唯一允許使用括號的地方是

PrimaryExpressionNB: '(' PrimaryExpression ')' { $$ = $2; }

所以括號中的內容必須是PrimaryExpression 但是=僅在派生自AssignmentExpression的產品中被接受,而PrimaryExpression不能派生AssignmentExpression 所以=不能出現在PrimaryExpression中,因此{}=0不是PrimaryExpression 因此({}=0)不能從PrimaryExpressionNB派生,並且輸入無效。

{}=0也是無效的,因為開始符號只派生了AssignmentExpressionNB ,它必須以PrimaryExpressionNB ,而{}不是PrimaryExpressionNB 我認為這是故意的,並且NB代表“No Brace”之類的東西。

({})=0可以是一個AssignmentExpressionNB ,因為({})是一個PrimaryExpressionNB 但這不會遇到 reduce/reduce 沖突,也是因為AssignmentExpressionNB不能以PrimaryExpression ,因此只有一個包含=的可用產生式。

為了達到減少/減少沖突,我們需要({})={}=0 ,其中{}=0必須從PrimaryExpression派生。 然而,現在,語法顯示自己實際上是模棱兩可的,而不僅僅是不確定的。

關鍵的非終端是:

AssignmentExpression:
      PrimaryExpression /* This one will be rejected fast */
    | ObjectAssignmentPattern '=' AssignmentExpression /* This must kept. */
    | PrimaryExpression '=' AssignmentExpression /* This must also kept. */

那里的第一條評論不正確。 無論有沒有 GLR,自底向上的解析器都不需要“快速”拒絕第一個產生式。 它可以使選項保持打開狀態,直到遇到(或不遇到) = 如果沒有遇到= ,那么第一個產生式是唯一的可能性,並且立即減少AssignmentExpression 但如果有= ,則必須使用AssignmentExpression的其他兩個產生式之一。 問題是,其他兩個產生式完全沒有區別,在這種情況下,任何一個都可能是有效的解析。 Bison GLR 解析器不能容忍實際的歧義,因此它會在該點引發歧義錯誤(不是語法錯誤)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM