【问题标题】:ANTLR3 grammar does not match rule with predicateANTLR3 语法与谓词不匹配规则
【发布时间】:2018-07-16 10:23:40
【问题描述】:

我有一个组合语法,我需要提供两个标识符词法分析器规则。 两个标识符可以同时使用。 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

【问题讨论】:

    标签: java grammar identifier antlr3 lexer


    【解决方案1】:
    ID1 : (CHARS) *;
    ID2 : (CHARS | ({flag}? '_'))* ;
    

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

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

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


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

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

    我相信您的核心问题是误解了词法分析器和解析器之间的区别及其用法。您应该问自己的问题是:“abcabde”何时应匹配为ID1,何时匹配为ID2

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 1970-01-01
      • 2015-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      相关资源
      最近更新 更多