我正在使用以下简单语法来理解ANTLR。

grammar Example;
options {
language=Java;
}

ID  : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INT : '0'..'9'+
    ;
PLUS    :   '+';


ADDNUM  :
    INT PLUS INT;

prog    :    ADDNUM;


当我尝试在ANTLRWorks中为输入1+2运行语法时,在控制台中出现以下错误:


[16:54:08]解释... [16:54:08]在2:0时匹配令牌问题
NoViableAltException(''@ [1:1:令牌:(ID | INT | PLUS | ADDNUM);])


谁能帮我了解我要去哪里错了。

最佳答案

您可能没有将prog指示为ANTLRWorks中的开始规则。如果这样做,一切正常。

但是,您实际上不应该像ADDNUM中那样创建与表达式匹配的词法分析器规则:这应该是解析器规则:

grammar Example;

prog    : addExpr EOF;
addExpr : INT PLUS INT;
ID      : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
INT     : '0'..'9'+;
PLUS    : '+';




ANTLR规则

何时使用解析器,词法分析器或片段规则没有严格的规则,但这是它们通常用于以下用途:

词汇规则

词法分析器规则通常是语言的最小部分(字符串,数字,标识符,注释等)。尝试从1+2之类的输入创建词法分析器规则会导致问题,原因是:


如果您想从该标记中提取有意义的内容(例如,对其进行评估),则需要拆分该标记的内容,因为从该标记创建1个标记后,整个表达式中的文本将被“粘合”在一起;
当它们之间有空格时,您会遇到问题:1 +   2


表达式1+2是三个标记:INTPLUS和另一个INT

碎片规则

当您不希望使用“真实”令牌时,可以使用分片规则。例如,采用以下词法分析器规则:

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
FLOAT : '0'..'9'+ '.' '0'..'9'+;
INT   : '0'..'9'+;


在上述规则中,您使用了四次'0'..'9',因此可以将其放在单独的规则中

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | DIGIT)*
FLOAT : DIGIT+ '.' DIGIT+;
INT   : DIGIT+;
DIGIT : '0'..'9';


但是,您永远都不想创建DIGIT令牌:您只希望DIGIT被其他词法分析器规则使用。在这种情况下,您可以创建一个fragment规则:

ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | DIGIT)*
FLOAT : DIGIT+ '.' DIGIT+;
INT   : DIGIT+;
fragment DIGIT : '0'..'9';


这将确保永远不会有DIGIT令牌:并且因此永远不能在您的解析器规则中使用该令牌!

解析器规则

解析器规则将令牌粘合在一起:它们确保语言为syntactic valid (a.k.a. parsing)。为了强调,解析器规则可以使用其他解析器规则或词法分析器规则,但不能使用片段规则。



另请参见:ANTLR: Is there a simple example?

关于java - 无法解释ANTLRWorks输出,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9268651/

10-09 15:54