ANTLR3 语法不匹配规则与谓词

ANTLR3 grammar does not match rule with predicate

我有一个组合语法,我需要在其中提供两个标识符词法分析器规则。 两个标识符可以同时使用。 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 == falseID2 将永远不会匹配。


词法分析器遵循的两个基本规则是:

  • 它匹配覆盖输入的最长子序列的令牌
  • 如果多个标记可以匹配同一个输入,则使用语法中第一个出现的标记

我认为您的核心问题是误解了词法分析器和解析器之间的区别以及它们的用法。您应该问自己的问题是:何时应将 'abcabde' 匹配为 ID1,何时应匹配为 ID2

  • 总是ID1 - 那么你的语法就和现在一样正确。
  • 总是 ID2 - 那么你应该切换这两个规则 - 但请注意,在这种情况下 ID1 将永远不会被匹配。
  • 这取决于flag - 然后你需要根据你的逻辑修改谓词,仅仅切换下划线是不够的。
  • 这取决于标识符在输入中的使用位置 - 那么这不是词法分析器可以决定的,您需要在解析器而不是词法分析器中区分这两种标识符。形式上,词法分析器使用 regular language while you need context-free language 来决定这样的标识符。