[英]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.