Antlr missing XXX at 与 mismatched input '<EOF>' 的几种错误情况分析

本文探讨ANTLR词法分析器在处理特定文法时可能遇到的歧义问题,通过两个实例详细分析了如何诊断和解决由词法识别错误引起的语法分析失败。首先,讨论了属性文件例子中字符串和ID识别的混淆,接着分析了CSV解析中提前遍历所有词法单元导致的EOF问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文使用的Antlr版本为4.7.2

1 词法规则有歧义导致

1.1问题背景

demo来自第七章的第一节,属性文件的例子。我将原始文法修改后如下。

grammar Demo;

file : prop+;
prop : ID '=' STRING;

ID : [a-z]+;
STRING : [a-z0-9]+;

在控文法控制台中验证输入文本,产生错误。

输入:

abc=abc

错误提示:

line 1:4 missing STRING at 'abc'
line 1:7 mismatched input '<EOF>' expecting '='

此时的语法分析树如下:
在这里插入图片描述

1.2 分析

输入字符流abc=abc后,由于长期未使用相关工具及进行理论复习。根据文法文件中文法,错误的认为生成的单词流为id,=,string。并按此顺序匹配。以为是遇到ID,匹配到abc,= 匹配到字符=,最后遇到STRING去匹配STRING的词法定义。

翻书后,想了想,这个一定是数据单词识别错误问题。回想整个过程是 符号流->单词流->语法树。通过生成器生成代码后先打印看看单词流都是什么类型的。

public class AntlrTest {
    public static void main(String[] args) throws Exception{
        String input = "abc=abc";
        CharStream charStream = CharStreams.fromString(input);
        DemoLexer demoLexer = new DemoLexer(charStream);
        System.out.println(demoLexer.getAllTokens());
    }
}

输出如下

[[@-1,0:2='abc',<2>,1:0], [@-1,3:3='=',<1>,1:3], [@-1,4:6='abc',<2>,1:4]]

尖括号内容表示了单词的类型。根据词法分析器中的源码可以看到类型如下。

	public static final int
		T__0=1, ID=2, STRING=3;

因此说明等号后的abc被识别为ID。所以后续在根据文法进行语法分析的时候遇到STRING是无法找到的。所以在前文中的文法描述下STRING输入只能是数字才会避免这种问题。

1.3 总结

  • 整体工作过程要清楚
  • 单词类型要明确

2 调用Lexer的getAllTokens导致

2.1 问题背景

练习第8章CSV的例子,简化文法后,如下。

grammar Demo;
csv : WORD;
WORD : [0-9a-z]+;
WS :   [ \t\n]+ -> skip ;

测试代码

public class AntlrTest {
    public static void main(String[] args) throws Exception{
        String input = "1";
        CharStream charStream = CharStreams.fromString(input);
        DemoLexer demoLexer = new DemoLexer(charStream);
        System.out.println(demoLexer.getAllTokens());
        CommonTokenStream commonTokenStream = new CommonTokenStream(demoLexer);
        DemoParser demoParser = new DemoParser(commonTokenStream);
        demoParser.csv();
    }
}

错误输出

line 1:1 missing WORD at '<EOF>'

2.2 分析

一开始产生这个问题觉得很奇怪。去掉代码demoLexer.getAllTokens()后恢复正常。随后查看getAllTokens的源码。getAllTokens是调用lexer的nextToken方法获取下一个词法符号

public List<? extends Token> getAllTokens() {
	List<Token> tokens = new ArrayList<Token>();
	Token t = nextToken();
	while ( t.getType()!=Token.EOF ) {
		tokens.add(t);
		t = nextToken();
	}
	return tokens;
}

nextToken内部,当_hitEOF为真时会返回EOF。调用getAllTokens后,_hitEOF标记会被置为true,

if (_hitEOF) {
	emitEOF();
	return _token;
}

调用demoParser.csv();生成语法分树时,同样会从token流中获取单词,这时由于调用了getAllTokens,再次获取时会得到EOF。match方法调用getCurrentToken得到的是EOF。因此就产生了后续的missing WORD at ‘’ 异常。最后删除getAllTokens调用恢复正常。

public Token match(int ttype) throws RecognitionException {
		Token t = getCurrentToken();
		if ( t.getType()==ttype ) {
			if ( ttype==Token.EOF ) {
				matchedEOF = true;
			}
			_errHandler.reportMatch(this);
			consume();
		}
		else {
			t = _errHandler.recoverInline(this);
			if ( _buildParseTrees && t.getTokenIndex()==-1 ) {
				// we must have conjured up a new token during single token insertion
				// if it's not the current symbol
				_ctx.addErrorNode(createErrorNode(_ctx,t));
			}
		}
		return t;
	}
	
"main@1" prio=5 tid=0x1 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
	  at org.antlr.v4.runtime.Parser.match(Parser.java:198)
	  at antcode.DemoParser.csv(DemoParser.java:119)
	  at complie.AntlrTest.main(AntlrTest.java:20)

"Finalizer@759" daemon prio=8 tid=0x3 nid=NA waiting
  java.lang.Thread.State: WAITING
	  at java.lang.Object.wait(Object.java:-1)
	  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
	  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	  at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler@760" daemon prio=10 tid=0x2 nid=NA waiting
  java.lang.Thread.State: WAITING
	  at java.lang.Object.wait(Object.java:-1)
	  at java.lang.Object.wait(Object.java:502)
	  at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
	  at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"Signal Dispatcher@758" daemon prio=9 tid=0x4 nid=NA runnable
  java.lang.Thread.State: RUNNABLE

2.3 总结

避免在获取parseTree之前调用lexer的getAllTokens()方法,方式出现遇到EOF获取不到TOKEN的问题

<think>好的,我现在需要帮助用户解决一个语法错误问题,具体是“mismatched input '{' expecting <EOF>”。首先,我得理解这个错误信息的含义。根据用户提供的引用资料,比如引用[3]中提到,当分析器遇到不符合文法的输入时,会提示期待某个符号却遇到了另一个符号。这里的错误显示期望的是<EOF>(即输入结束),但实际遇到了左花括号'{',这说明在语法分析器预期输入应该结束的地方,却出现了意外的字符。 接下来,我需要考虑可能的原因。根据引用[2]中的分析,类似的错误通常是因为语法规则中某些部分没有正确终止,或者结构不完整。例如,用户可能在代码中漏掉了闭合的括号或分号,导致分析器在期望输入结束时遇到了其他符号。比如,在写一个代码块时,可能忘记闭合前面的括号或引号,导致后面的'{'被误认为是多余的。 然后,我需要检查用户的语法定义。根据引用[4]中的示例,正确的词法规则定义包括ID、INT、换行符和空白符的处理。如果用户的语法规则中存在未正确闭合的结构,比如未闭合的字符串或括号,可能导致分析器提前终止,从而在遇到'{'时报错。例如,如果规则中某个产生式缺少闭合的括号,分析器可能在解析到某个点时认为输入应该结束,但实际遇到了'{'。 另外,引用[5]提到添加定制的词法语法错误处理可以帮助定位问题。用户可能需要检查他们的语法文件,特别是花括号相关的部分,确保所有结构都正确闭合。例如,检查是否有未闭合的括号、方括号或花括号,或者是否在规则中错误地使用了<EOF>,导致分析器提前期望结束。 可能的解决方案包括:检查语法文件中是否有未闭合的结构,确保所有括号、引号等符号成对出现;确认在语法规则中正确使用了终结符和非终结符的顺序;使用ANTLR的工具如TestRig来逐步调试输入,查看语法分析树的结构,找出具体哪个规则导致了错误。 最后,用户可能需要提供一个具体的语法规则片段,以便更准确地诊断问题。但根据现有信息,常见的解决步骤应该是检查语法结构是否完整,确保所有符号正确闭合,并使用工具进行验证和调试。</think>### 语法错误 `mismatched input '{' expecting <EOF>` 分析及解决步骤 #### 1. 错误原因分析错误表示**语法分析器在预期输入结束的位置遇到了未闭合的结构或多余的符号**。例如: - **未闭合的括号/引号**:如漏写 `)`、`}` 或字符串未闭合,导致分析器认为代码未结束。 - **语法规则顺序错误**:某些语法规则可能被错误地提前终止,使得后续符号无法被解析。 - **词法/语法规则冲突**:词法规则未正确定义,导致 `{` 未被识别为合法符号[^2][^3]。 --- #### 2. 具体解决步骤 ##### 步骤1:检查未闭合的结构 - **示例代码**: ```java if (x > 0 { // 缺少闭合的 ')' System.out.println("Hello"); } ``` 错误提示 `mismatched input '{'`,因为 `if` 条件缺少右括号 `)`,分析器期望输入结束却遇到了 `{`[^3]。 ##### 步骤2:验证语法规则 - **检查语法文件**(如 `.g4`)中相关规则: ```antlr4 block : '{' statement* '}'; // 确保 '{' 和 '}' 成对定义 ``` 若规则中未正确定义 `}` 的闭合,会导致分析器提前期望 `<EOF>`。 ##### 步骤3:处理词法规则冲突 - **确保 `{` 被正确定义为终结符**: ```antlr4 LBRACE : '{'; // 明确声明 '{' 为词法符号 RBRACE : '}'; ``` 若未定义,`{` 可能被错误解析为其他符号(如标识符)[^4]。 ##### 步骤4:使用工具调试 - **通过 ANTLR TestRig 可视化分析**: ```bash antlr4 MyGrammar.g4 javac MyGrammar*.java echo "input_code" | grun MyGrammar startRule -tree ``` 观察语法树在何处中断,定位未闭合的结构[^5]。 --- #### 3. 示例修正 **错误代码**: ```java public class Test { public static void main(String[] args { System.out.println("Missing ')'"); } } ``` **修正后**: ```java public class Test { public static void main(String[] args) { // 补充缺失的 ')' System.out.println("Corrected"); } } ``` --- #### 4. 扩展建议 - **添加错误恢复机制**:在语法规则中覆盖 `mismatched input` 错误,提供更友好的提示。 - **严格测试边界情况**:针对符号闭合、嵌套结构设计测试用例。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值