java - ANTLR3 语法与谓词不匹配规则

标签 java grammar identifier antlr3 lexer

我有一个组合语法,需要提供两个标识符词法分析器规则。 两个标识符可以同时使用。在语法中,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当您需要context-free language时来决定这样的标识符。

关于java - ANTLR3 语法与谓词不匹配规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51359630/

相关文章:

Java TypedQuery 比直接查询 DB 慢得多

JavaScript 语法符号

facebook - 应用因 AdSupport.framework 而被拒绝

Java 扫描器和错误

ios - 应用被拒绝 "Reasons Program License Agreement PLA 3.3.12"

java - 如何使 "Enter"键的行为类似于在 JFrame 上提交

java - Xtext:这个异常是什么意思?

java - 执行由 Jasmin 生成的文件 .classes 时出错

java - 阅读和理解 AspectJ 切入点?

grammar - Xtext 从验证器获取项目根目录