在ANTLR中,我是否可以在没有实际匹配的情况下前瞻特定令牌?

在ANTLR中,我是否可以在没有实际匹配的情况下前瞻特定令牌?,antlr,Antlr,基本上,我需要提前知道某个令牌是否存在,但不匹配它(即,使另一个解析器规则仍然可以匹配它) 问题的确切细节是一个“最终”条款。 该语言有“IF”(由“END-IF”关闭)、“FOR”(由“END-FOR”关闭)等结构 但可以选择使用“END-all”全局关闭所有此类开环(这样就不需要实际的“END-IF”或“END-for”子句) 我是否可以正确地实现这一点?您可以通过在if(和for-)语句中创建一个布尔标志来实现这一点,该语句跟踪是否需要使用结束符,或者向前看是否足够。此布尔标志被传递给与i

基本上,我需要提前知道某个令牌是否存在,但不匹配它(即,使另一个解析器规则仍然可以匹配它)

问题的确切细节是一个“最终”条款。 该语言有“IF”(由“END-IF”关闭)、“FOR”(由“END-FOR”关闭)等结构

但可以选择使用“END-all”全局关闭所有此类开环(这样就不需要实际的“END-IF”或“END-for”子句)


我是否可以正确地实现这一点?

您可以通过在
if
(和
for
-)语句中创建一个布尔标志来实现这一点,该语句跟踪是否需要使用
结束符
,或者向前看是否足够。此布尔标志被传递给与
if
代码块的结尾匹配的解析器规则

一个小演示:

grammar T;

options {
  output=AST;
}

tokens {
  BLOCK;
  ASSIGN;
}

@parser::members {
  private boolean flag = true;
}

parse
  :  block EOF -> block
  ;

block
  :  stat* -> ^(BLOCK stat*)
  ;

stat
  :  PRINT expression -> ^(PRINT expression)
  |  assignment
  |  ifStat
  ;

assignment
  :  ID '=' expression -> ^(ASSIGN ID expression)
  ;

ifStat
@init{
  boolean consumeEndAll = false;
  if(flag) {
    consumeEndAll = true;
    flag = false;
  }
}
@after {
  if(consumeEndAll) {
    flag = true;
  }
}
  :  IF expression DO block end[consumeEndAll] -> ^(IF expression block)
  ;

expression
  :  NUMBER
  |  TRUE
  |  FALSE
  |  ID
  ;

end [boolean consumeEndAll]
  :                                       END
  |                                       EOF
  |  {consumeEndAll}?=>                   ENDALL
  |  {input.LT(1).getType() == ENDALL}?=> { /* consume no token */ }
  ;

PRINT  : 'print';  
ENDALL : 'endall';
END    : 'end';
IF     : 'if';
DO     : 'do';
TRUE   : 'true';
FALSE  : 'false';
NUMBER : '0'..'9'+ ('.' '0'..'9'+)?;
ID     : ('a'..'z' | 'A'..'Z')+;
SPACE  : (' ' | '\t' | '\r' | '\n') {skip();};
end
规则(
{…}?=>
)中的谓词导致规则要么使用
ENDALL
,要么只向前看是否存在这样的令牌,但不使用它

有关谓词的更多信息:

由上述语法生成的解析器将为脚本1和脚本2生成相同的AST:

脚本1 脚本2 即以下内容:

(使用生成的图像)

您可以使用以下Java类来测试这一切:

import org.antlr.runtime.*;
导入org.antlr.runtime.tree.*;
导入org.antlr.stringtemplate.*;
公共班机{
公共静态void main(字符串[]args)引发异常{
字符串源=
“如果1需要\n”+
“打印文件\n”+
“如果2不需要\n”+
“打印b\n”+
“打印c\n”+
“如果3没有\n”+
“全部结束\n”+
“打印d”;
System.out.println(source+“\n-----------------\n”);
TLexer lexer=新的TLexer(新的AntlStringStream(源));
TParser parser=newtparser(newcommontokenstream(lexer));
CommonTree=(CommonTree)parser.parse().getTree();
DOTTreeGenerator gen=新的DOTTreeGenerator();
StringTemplate st=gen.toDOT(树);
系统输出打印LN(st);
}
}
if 1 do
  print a
  if 2 do
    print b
    print c
    if 3 do
    end
  end
end
print d
if 1 do
  print a
  if 2 do
    print b
    print c
    if 3 do
endall
print d