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

本文使用的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 '' expecting '='

此时的语法分析树如下:
Antlr missing XXX at 与 mismatched input '' 的几种错误情况分析_第1张图片

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 ''

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的问题

你可能感兴趣的:(antlr)