为什么Antlr发现这个语法模棱两可?
我正在为Java的一个子集创建语法,似乎遇到了一个问题,ANTLR认为我的语法不明确(或者,我认为这至少是错误背后的原因) 以下是我语法的相关部分:为什么Antlr发现这个语法模棱两可?,antlr,Antlr,我正在为Java的一个子集创建语法,似乎遇到了一个问题,ANTLR认为我的语法不明确(或者,我认为这至少是错误背后的原因) 以下是我语法的相关部分: expr : (op=MINUS | op=NOT) expr exprPrime -> ^(Expr $op expr exprPrime) | NEW ID OPEN_PAREN CLOSE_PAREN exprPrime -> ^(Expr NEW ID OPEN_PAREN CLOSE_PAREN exprP
expr : (op=MINUS | op=NOT) expr exprPrime -> ^(Expr $op expr exprPrime)
| NEW ID OPEN_PAREN CLOSE_PAREN exprPrime -> ^(Expr NEW ID OPEN_PAREN CLOSE_PAREN exprPrime)
| ID exprPrime -> ^(Expr ID exprPrime)
| THIS exprPrime -> ^(Expr THIS exprPrime)
| INTEGER exprPrime -> ^(Expr INTEGER exprPrime)
| NULL exprPrime -> ^(Expr NULL exprPrime)
| TRUE exprPrime -> ^(Expr TRUE exprPrime)
| FALSE exprPrime -> ^(Expr FALSE exprPrime)
| OPEN_PAREN expr CLOSE_PAREN exprPrime -> ^(Expr OPEN_PAREN expr CLOSE_PAREN exprPrime)
;
// remove left recursion via exprPrime
exprPrime : (op=PLUS | op=MINUS | op=MULT | op=DIV | op=LT | op=LEQ | op=GT | op=GEQ | op=EQ | op=NEQ | op=AND | op=OR | op=NOT) expr exprPrime
-> ^(ExprPrime $op expr exprPrime)
| DOT ID OPEN_PAREN (expr (COMMA expr)*)? CLOSE_PAREN exprPrime
-> ^(ExprPrime DOT ID OPEN_PAREN (expr (COMMA expr)*)? CLOSE_PAREN exprPrime)
|
-> ^(Epsilon)
;
/*------------------------------------------------------------------
* LEXER RULES
*------------------------------------------------------------------*/
CLASS : 'class' ;
PUBLIC : 'public' ;
STATIC : 'static' ;
EXTENDS : 'extends' ;
NEW : 'new' ;
THIS : 'this' ;
NULL : 'null' ;
IF : 'if' ;
ELSE : 'else' ;
WHILE : 'while' ;
MAIN : 'main' ;
TRUE : 'true' ;
FALSE : 'false' ;
RETURN : 'return' ;
SYSO : 'System.out.println' ;
OPEN_BRACKET : '{' ;
CLOSE_BRACKET : '}' ;
OPEN_SQUARE : '[' ;
CLOSE_SQUARE : ']' ;
OPEN_PAREN : '(' ;
CLOSE_PAREN : ')' ;
ASSIGN : '=' ;
COMMA : ',' ;
DOT : '.' ;
SEMICOLON : ';' ;
STRING_TYPE : 'String' ;
INTEGER_TYPE : 'int' ;
VOID_TYPE : 'void' ;
BOOLEAN_TYPE : 'boolean' ;
PLUS : '+' ;
MINUS : '-' ;
MULT : '*' ;
DIV : '/' ;
LT : '<' ;
LEQ : '<=' ;
GT : '>' ;
GEQ : '>=' ;
EQ : '==' ;
NEQ : '!=' ;
AND : '&&' ;
OR : '||' ;
NOT : '!' ;
ID : LETTER (LETTER | DIGIT)* ;
INTEGER : (NON_ZERO_DIGIT DIGIT*) | ZERO ;
WHITESPACE : ('\t' | ' ' | '\r' | '\n'| '\u000C')+ { $channel = HIDDEN; } ;
COMMENT : (('/*' .* '*/') | ('//' .* '\n')) { $channel = HIDDEN; } ;
fragment ZERO : '0' ;
fragment DIGIT : '0'..'9' ;
fragment NON_ZERO_DIGIT : '1'..'9' ;
fragment LETTER : 'a'..'z' | 'A'..'Z' ;
warning(200): MiniJava.g:101:11: Decision can match input such as "NEQ" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "EQ" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "MULT" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "DIV" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "GEQ" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "NOT" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "LT" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "LEQ" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "DOT" using multiple alternatives: 2, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "OR" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "PLUS" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "AND" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "MINUS" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
warning(200): MiniJava.g:101:11: Decision can match input such as "GT" using multiple alternatives: 1, 3
As a result, alternative(s) 3 were disabled for that input
行号都指向带有exprprome定义的行(为了简洁起见,我省略了上面的大部分gramar,如果我需要发布更多,请告诉我)。创建exprprome本身是为了避免“expr”中的左递归
你知道我如何修改语法来消除歧义吗?我甚至不确定我是否理解歧义是什么。歧义在于
exprprome
的第三个选项将匹配任何内容-空规则始终成功,并且从不推进输入。要消除歧义,您可以从定义中删除该选项,并将所有出现的exprprome
替换为exprprome?
您的语法可以最小化以显示其歧义:
grammar T; // line 1
// 2
expr // 3
: MINUS expr exprPrime // 4
; // 5
// 6
exprPrime // 7
: MINUS expr exprPrime // 8
| // epsilon // 9
; // 10
// 11
MINUS : '-'; // 12
INTEGER : '0'..'9'+; // 13
根据此语法生成解析器将导致以下警告:
[20:38:15] warning(200): T.g:8:2:
Decision can match input such as "MINUS" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
[20:38:15] error(201): T.g:8:2: The following alternatives can never be matched: 2
第一部分指出,在语法的第8行,生成的解析器可以采用两个“路径”来匹配标记减号(第8行和第9行上的替代项都匹配减号!)。这就是歧义(在你的语法中,还有很多很多)。第二部分通知您,由于这种模糊性,生成的解析器将无法采用第二种选择(该路径被禁用)
还有一件事:通过匹配同一备选方案中的所有运算符,您无法使*
具有比-
更高的优先级。所有正确的递归产生式使得语法很难理解。我会这样做:
// ...
tokens {
UNARY_MINUS;
PARAMS;
INVOKE;
}
parse
: expr EOF
;
expr
: or_expr
;
or_expr
: and_expr (OR^ and_expr)*
;
and_expr
: rel_expr (AND^ rel_expr)*
;
rel_expr
: eq_expr ((LT | GT | LEQ | GEQ)^ eq_expr)?
;
eq_expr
: add_expr ((EQ | NEQ)^ add_expr)?
;
add_expr
: mult_expr ((PLUS | MINUS)^ mult_expr)*
;
mult_expr
: unary_expr ((MULT | DIV)^ unary_expr)*
;
unary_expr
: MINUS atom -> ^(UNARY_MINUS atom)
| atom
;
atom
: NEW ID OPEN_PAREN params CLOSE_PAREN -> ^(NEW ID params)
| (ID -> ID) (invoke -> ^(ID invoke))?
| THIS
| INTEGER
| NULL
| TRUE
| FALSE
| OPEN_PAREN expr CLOSE_PAREN -> expr
;
invoke
: DOT ID OPEN_PAREN params CLOSE_PAREN invoke? -> ^(INVOKE ID params invoke?)
;
params
: (expr (COMMA expr)*)? -> ^(PARAMS expr*)
;
// ...
没有歧义,所有运算符都有适当的优先级(或
是最低的,一元运算符是最高的(当然原子更高…)。使用expr
规则解析输入,如“x.foo(9,y)&(1==2 | | | true)+2+3+4==333”
,将导致以下结果:
这与Python有什么关系吗?@tMC:我怀疑他正在使用的编程语言就是这种语言。它可能有一些相关性;那些发布答案的人,如果他们愿意的话,可以把他们的建议放在Python中。是的,对不起。我认为在这里包含python标记没有多大意义。我的许多其他ANTLR问题都涉及到python与ANTLR的交互,我有点心不在焉地添加了它。从exprprome
中删除第三个选项,并用exprprome?
替换exprprome
将无法修复它。非常有用且信息丰富。我得研究修理这东西。谢谢@圣诞老人,不客气。注意,我犯了一些(小)错误。我用一套正确的规则编辑了我的答案。我刚刚注意到有什么地方出错,然后返回,结果发现你已经更新了答案以修复它。谢谢你的帮助!我相当肯定它现在可以工作了(没有答案,我的旧测试用例似乎可以在AntlWorks中工作……现在我只需要稍微调整一下我的类型检查器)。