我有一个组合语法,需要提供两个标识符词法分析器规则。 两个标识符可以同时使用。在语法中,Identifier1 位于 Identifer2 之前。
第一个标识符是静态的,而第二个标识符规则根据某些标志而变化。(使用谓词)。
我希望第二个标识符在解析器规则中匹配。但由于两个标识符都可能匹配一些常见的输入,因此它不属于 identifer2。
我创建了一些小语法以使其易于理解。语法如下:
@lexer::members
{
private boolean flag;
public void setFlag(boolean flag)
{
this.flag = flag;
}
}
identifier1 :
ID1
;
identifier2 :
ID2
;
ID1 : (CHARS) *;
ID2 : (CHARS | ({flag}? '_'))* ;
fragment CHARS
:
('a' .. 'z')
;
如果我尝试将 identifer2 规则匹配为:
ANTLRStringStream in = new ANTLRStringStream("abcabde");
IdTestLexer lexer = new IdTestLexer(in);
lexer.setFlag(true);
CommonTokenStream tokens = new CommonTokenStream(lexer);
IdTestParser parser = new IdTestParser(tokens);
parser.identifier2();
显示错误: 第 1:0 行在“abcabde”处缺少 ID2
最佳答案
ID1 : (CHARS) *;
ID2 : (CHARS | ({flag}? '_'))* ;
对于 ANTLR 这两条规则意味着:
- 如果输入只是字符,则为
ID1
- 如果输入混合字符和
_
和flag == true
,则为ID2
请注意,如果flag == false
,ID2
将永远不会匹配。
词法分析器遵循的两个基本规则是:
- 它匹配覆盖输入的最长子序列的标记
- 如果多个标记可以匹配相同的输入,请使用语法中第一个标记
我相信您的核心问题是误解了词法分析器和解析器之间的区别及其用法。您应该问自己的问题是:何时应将 'abcabde' 匹配为 ID1
,何时应匹配 ID2
?
- 始终
ID1
- 那么您的语法就和现在一样正确。 - 始终
ID2
- 那么您应该切换这两个规则 - 但请注意,在这种情况下,ID1
将永远不会匹配。 - 这取决于
flag
- 那么您需要根据您的逻辑修改谓词,仅切换下划线是不够的。 - 这取决于输入中标识符的使用位置 - 那么这不是词法分析器可以决定的,您需要在解析器而不是词法分析器中区分这两种标识符。形式上,词法分析器使用 regular language当您需要context-free language时来决定这样的标识符。
关于java - ANTLR3 语法与谓词不匹配规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51359630/