[英]Ambiguous Context-free grammar? / Shift/Reduce conflict in CUP
對於 C++ 的簡化版本,我有以下上下文無關語法。 當我使用 JFLEX 和 CUP 運行它時,我會得到如下錯誤列表:
Warning : *** Reduce/Reduce conflict found in state #173
between especificador ::= (*)
and programa ::= (*)
under symbols: {VOID, CHAR, FLOAT, DOUBLE, SIGNED, UNSIGNED, INT, SHORT, LONG}
Resolved in favor of the second production.
我認為問題出在 instrucoesIf 但我無法弄清楚
start with programa;
programa ::= especificador tipo ID programa2 | DEFINE ID num CRLF programa | ; verificar depois o ERRO
especificador ::= AUTO | STATIC | EXTERN | CONST | ;
tipo ::= VOID | CHAR | FLOAT | DOUBLE | SIGNED inteiro | UNSIGNED inteiro | inteiro;
inteiro ::= SHORT | INT | LONG;
programa2 ::= SEMICOLON programa | LBRACK num RBRACK SEMICOLON programa | LPAREN listaParametros RPAREN bloco programa | COMMA listaID programa;
listaID ::= ID declaracaoParam2 listaIDTail;
listaIDTail ::= SEMICOLON | COMMA listaID;
listaParametros ::= listaParamRestante | ;
listaParamRestante ::= declaracaoParam declParamRestante;
declaracaoParam ::= tipo ID declaracaoParam2;
declaracaoParam2 ::= LBRACK num RBRACK | ;
declParamRestante ::= COMMA listaParamRestante | ;
bloco ::= LBRACE conjuntoInst RBRACE | SEMICOLON conjuntoInst ;
conjuntoInst ::= programa conjuntoInst | instrucoes conjuntoInst | ;
instrucoes ::= ID expressao SEMICOLON | RETURN expr SEMICOLON | PRINTF LPAREN expr RPAREN SEMICOLON | SCANF LPAREN ID RPAREN SEMICOLON | BREAK SEMICOLON | IF LPAREN expr RPAREN instrucoes instrucoesIf;
instrucoesIf ::= ELSE instrucoes | ;
expressao ::= atribuicao | LBRACK expr RBRACK atribuicao | LPAREN exprList RPAREN | ;
atribuicao ::= operadorAtrib expr;
operadorAtrib ::= EQ | MULTEQ | DIVEQ | MODEQ | PLUSEQ | MINUSEQ;
expr ::= exprAnd exprOr;
exprList ::= expr exprListTail | ;
exprListTail ::= COMMA exprList | ;
exprOr ::= OR exprAnd exprOr | ;
exprAnd ::= exprEqual exprAnd2;
exprAnd2 ::= AND exprEqual exprAnd2 | ;
exprEqual ::= exprRelational exprEqual2;
exprEqual2 ::= EQEQ exprRelational exprEqual2 | NOTEQ exprRelational exprEqual2 | ;
exprRelational ::= exprPlus exprRelational2;
exprRelational2 ::= LT exprPlus exprRelational2 | LTEQ exprPlus exprRelational2 | GT exprPlus exprRelational2 | GTEQ exprPlus exprRelational2 | ;
exprPlus ::= exprMult exprPlus2;
exprPlus2 ::= PLUS exprMult exprPlus2 | MINUS exprMult exprPlus2 | ;
exprMult ::= exprUnary exprMult2;
exprMult2 ::= MULT exprUnary exprMult2 | DIV exprUnary exprMult2 | ;
exprUnary ::= PLUS exprParenthesis | MINUS exprParenthesis | exprParenthesis;
exprParenthesis ::= LPAREN expr RPAREN | primary;
primary ::= ID primaryID | num | literal;
primaryID ::= LBRACK primary RBRACK | LPAREN exprList RPAREN | ;
literal ::= STRING | CHAR;
num ::= NUM_INT | NUM_FLOAT;
CUP 是一個 LALR 解析器生成器,這意味着無需避免左遞歸,因此您可以使用更自然的語法風格; 無需將列表拆分為“開始”和“繼續”產生式,它們難以閱讀且容易出錯,而且通常不允許直接構建准確的語法樹。
您的語法中有很多沖突,但這顯然是模棱兩可的:
conjuntoInst ::= programa conjuntoInst | instrucoes conjuntoInst | ;
請注意, programa
也有一個空選項。 因此,在conjuntoInst
的開頭(或者實際上,在中間)可能有任意數量的空programa
。 您需要非常小心不能派生任何東西的非終端; 您必須避免在未定界的列表中使用它們,因為解析器無法判斷源文本中存在多少連續的空非終結符。
請注意,在 C++ 和 C 中不允許使用完全空的語句。 一個完全空洞的陳述會產生這種歧義。 空語句仍必須以;
結尾。 . 這使得擁有語句列表成為可能。
因此,對於 C 語句(包括塊)(省略了很多細節),通常的 model 是:
block ::= '{' statementList '}' ;
statementList ::= | statementList statement ;
statement ::= emptyStatement | expressionStatement | ifStatement | ...
| declaration
emptyStatement ::= ';'
expressionStatement ::= expression ';'
...
ifStatement ::= IF '(' expression ')' statement
| IF '(' expression ')' statement ELSE statement
declaration ::= modifiers type ID ...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.