ANTLR3语法与谓词不匹配规则

时间:2018-07-16 10:23:40

标签: java grammar identifier antlr3 lexer

我有一个组合语法,需要提供两个标识符词法分析器规则。 两个标识符可以同时使用。在语法上,Identifier1在Identifer2之前。

第一个标识符是静态的,而第二个标识符规则根据某个标志而改变(使用谓词)。

我希望第二个标识符在解析器规则中匹配。但是由于这两个标识符可能与某些常用输入匹配,因此它不会属于identifer2。

我创建了小语法以使其易于理解。语法为:

address => 'required'

如果我尝试将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')
;  

它显示错误: 第1:0行在“ abcabde”处缺少ID2

1 个答案:

答案 0 :(得分:1)

ID1 : (CHARS) *;
ID2 : (CHARS | ({flag}? '_'))* ;

对于ANTLR,这两个规则意味着:

  • 如果输入只是字符,则为ID1
  • 如果输入中混合了字符和_flag == true,则为ID2

请注意,如果flag == falseID2将永远不会被匹配。


Lexer遵循的两个基本规则是:

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

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

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