ANTLR4 在到达文件末尾之前由于解析错误而成功终止解析的情况
A case where ANTLR4 terminates parsing successfully before the end of file is reached due to a parsing error
我在单独的文件中给了ANTLR4下面的解析器和词法分析器语法(指BNF语法的简单语法)
parser grammar BNFParser;
options {tokenVocab = BNFLexer;}
compileUnit
: grammar_rule+
;
grammar_rule : NON_TERMINAL COLON (OR? grammar_rule_alternative)* SEMICOLON
;
grammar_rule_alternative : (NON_TERMINAL|TERMINAL)+
;
和
lexer grammar BNFLexer;
TERMINAL : [A-Z][A-Za-z0-9_]*;
NON_TERMINAL : [a-z][A-Za-z0-9_]*;
OR : '|';
COLON : ':';
SEMICOLON : ';';
WS
: [ \t\r\n]+ -> skip
;
主程序
private static void Main(string[] args) {
StreamReader reader = new StreamReader(args[0]);
AntlrInputStream stream = new AntlrInputStream(reader);
BNFLexer lexer = new BNFLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
BNFParser parser = new BNFParser(tokens);
IParseTree root = parser.compileUnit();
Console.WriteLine(root.ToStringTree());
}
还提供了以下用于测试语法的测试文件
compileunit : x a
;
x : S b
;
S : compileunit f
;
请注意词法分析器语法,非终结符以小写字母开头,而终结符以大写字母开头。这个给定的语法有错误。第三条规则使用大写字母 ( S ) 来定义非终结符 S。预期的行为是将此报告为错误。相反,通过使用前 2 条规则并忽略 S 的第三条规则,解析成功而不报告任何错误。我也看到了生成的文件,我注意到以下
try {
EnterOuterAlt(_localctx, 1);
{
State = 7;
_errHandler.Sync(this);
_la = _input.La(1);
do {
{
{
State = 6; grammar_rule();
}
}
State = 9;
_errHandler.Sync(this);
_la = _input.La(1);
} while ( _la==NON_TERMINAL );
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.ReportError(this, re);
_errHandler.Recover(this, re);
}
上面的代码表明解析器期望在 grammar_rule 的开头有一个非终结符号,这正是我所期望的。但是,如果不是这种情况会发生什么?另一个奇怪的问题是,包含词法分析器识别的标记的 CommonTokenStream 对象只包含直到第二条规则结束的标记,而不包含第三条规则 (S) 的标记。这是正确的行为吗?
将 EOF 标记添加到您的主要规则 (compileUnit
)。这将强制解析器使用 EOF 之前的所有输入,如果不完全匹配则报告错误。
我在单独的文件中给了ANTLR4下面的解析器和词法分析器语法(指BNF语法的简单语法)
parser grammar BNFParser;
options {tokenVocab = BNFLexer;}
compileUnit
: grammar_rule+
;
grammar_rule : NON_TERMINAL COLON (OR? grammar_rule_alternative)* SEMICOLON
;
grammar_rule_alternative : (NON_TERMINAL|TERMINAL)+
;
和
lexer grammar BNFLexer;
TERMINAL : [A-Z][A-Za-z0-9_]*;
NON_TERMINAL : [a-z][A-Za-z0-9_]*;
OR : '|';
COLON : ':';
SEMICOLON : ';';
WS
: [ \t\r\n]+ -> skip
;
主程序
private static void Main(string[] args) {
StreamReader reader = new StreamReader(args[0]);
AntlrInputStream stream = new AntlrInputStream(reader);
BNFLexer lexer = new BNFLexer(stream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
BNFParser parser = new BNFParser(tokens);
IParseTree root = parser.compileUnit();
Console.WriteLine(root.ToStringTree());
}
还提供了以下用于测试语法的测试文件
compileunit : x a
;
x : S b
;
S : compileunit f
;
请注意词法分析器语法,非终结符以小写字母开头,而终结符以大写字母开头。这个给定的语法有错误。第三条规则使用大写字母 ( S ) 来定义非终结符 S。预期的行为是将此报告为错误。相反,通过使用前 2 条规则并忽略 S 的第三条规则,解析成功而不报告任何错误。我也看到了生成的文件,我注意到以下
try {
EnterOuterAlt(_localctx, 1);
{
State = 7;
_errHandler.Sync(this);
_la = _input.La(1);
do {
{
{
State = 6; grammar_rule();
}
}
State = 9;
_errHandler.Sync(this);
_la = _input.La(1);
} while ( _la==NON_TERMINAL );
}
}
catch (RecognitionException re) {
_localctx.exception = re;
_errHandler.ReportError(this, re);
_errHandler.Recover(this, re);
}
上面的代码表明解析器期望在 grammar_rule 的开头有一个非终结符号,这正是我所期望的。但是,如果不是这种情况会发生什么?另一个奇怪的问题是,包含词法分析器识别的标记的 CommonTokenStream 对象只包含直到第二条规则结束的标记,而不包含第三条规则 (S) 的标记。这是正确的行为吗?
将 EOF 标记添加到您的主要规则 (compileUnit
)。这将强制解析器使用 EOF 之前的所有输入,如果不完全匹配则报告错误。