C# ANTLR匹配解析器规则的一部分,即使它无法完全匹配该规则

C# ANTLR匹配解析器规则的一部分,即使它无法完全匹配该规则,c#,parsing,antlr,dsl,C#,Parsing,Antlr,Dsl,我从ANTLR开始,试图为一种非常简单的语言创建一个解析器。 目前我的语法定义为: /* * Parser Rules */ public compileUnit : DEFINE IDENTIFIER END_OF_STATEMENT { Console.WriteLine($IDENTIFIER.text); }; /* * Lexer Rules */ DEFINE : 'define'; // Basic tokens INT : '0'..'9'+; END

我从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;
但是,输入的
垃圾
也会导致打印出
垃圾
,就好像它是一个标识符一样

为什么
compileUnit
不抛出异常?
这可能是语法规则定义顺序的问题吗?

请记录在案,如果您想切换,这就是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;

这只是一个草稿。

此问题的解决方案是将解析器规则更改为(注意添加了
EOF
标记):

并重写解析器类的ReportError方法

public override void ReportError(Antlr.Runtime.RecognitionException e)
{
    base.ReportError(e);
    throw e;
}
现在,调用代码可以访问异常,开发可以继续


值得一提的是,在解决方案上遇到障碍后,我进行了快速搜索,找到了似乎相似的解决方案。这似乎不是ANTLR的一个非常明显的部分(即ANTLR如何处理BNF语法),也是平台新手的一个潜在绊脚石

你是说“垃圾”这个词?因为标识符的规则允许它。顺便说一句,标识符的正则表达式很奇怪——至少应该是
('a''z''a''a''z')(INT |'a''z''a''z''a''z'.')*
。哦,你是对的,加号不应该在那里。输入的“垃圾”应该被拒绝。从现在起,应该只允许“定义垃圾”;猜测部分开始,因为我不知道ANTLR(我使用自己的C#NLT套件--),但我会打印出
define
终端捕获的内容。你知道,简单的调试。只需确保打印
$DEFINE.text#$IDENTIFIER.text
(除空格外,任何分隔符都足以确保您知道哪个部分是哪个部分)。当我在正确的输入上打印DEFINE标记的值时,它会打印“DEFINE”。当在“垃圾”输入上执行时,它会打印“缺少定义”。我决定坚持使用ANTLR,因为它已经在我的项目中了,但是作为参考,请参阅下面我的答案和问题的解决方案。
public override void ReportError(Antlr.Runtime.RecognitionException e)
{
    base.ReportError(e);
    throw e;
}