我开始使用ANTLR并尝试使用非常简单的语言创建解析器。 目前我的语法定义为:
/*
* Parser Rules
*/
public compileUnit
: DEFINE IDENTIFIER END_OF_STATEMENT { Console.WriteLine($IDENTIFIER.text); };
/*
* Lexer Rules
*/
DEFINE : 'define';
// Basic tokens
INT : '0'..'9'+;
END_OF_STATEMENT : ';';
// Whitespace
WS : (' '|'\t'|'\r'|'\n')+ {Skip();} ;
// Sub-statement tokens
IDENTIFIER : ('a'..'z' | 'A'..'Z')+ (INT | ('a'..'z' | 'A'..'Z') | '_')*;
语言为CSharp3
。
当我尝试输入以下内容时,它可以正常工作,打印标识符名称:
define My_Identifier1;
但是,输入garbage
也会导致garbage
打印出来,就好像它是标识符一样。
为什么compileUnit
不会抛出异常?
这可能是语法规则定义顺序的问题吗?
答案 0 :(得分:1)
仅仅为了记录,如果你想转换,这就是它在NLT中的表现,有一些细微的差别,但没有什么难以理解的。
/*
* Parser Rules
*/
compileUnit -> DEFINE id:IDENTIFIER END_OF_STATEMENT
{{ Console.WriteLine(id); return null; }};
/*
* Lexer Rules
*/
"define" -> DEFINE;
/[0-9]+/ -> INT,Convert.ToInt32($text);
";" -> END_OF_STATEMENT;
// Whitespace
/[ \\t\\r\\n]+/ { };
// Sub-statement tokens
/[a-zA-z][a-zA-Z0-9_]*/ -> IDENTIFIER;
这只是草稿。
答案 1 :(得分:1)
此问题的解决方案是将解析器规则更改为(请注意添加EOF
令牌):
public compileUnit
: DEFINE IDENTIFIER END_OF_STATEMENT EOF { Console.WriteLine($IDENTIFIER.text); };
并覆盖解析器类的ReportError方法。
public override void ReportError(Antlr.Runtime.RecognitionException e)
{
base.ReportError(e);
throw e;
}
现在,调用代码可以访问异常并继续开发。
值得指出的是,在遇到解决方案后,我进行了快速搜索并找到this Stack Overflow question,这似乎是相似的。这似乎不是ANTLR的一个非常明显的部分(即ANTLR如何处理BNF语法)以及该平台的新手的潜在绊脚石。