【问题标题】:In ANTLR, can I look-ahead for specific tokens without actually matching them?在 ANTLR 中,我可以在不实际匹配它们的情况下预测特定的令牌吗?
【发布时间】:2011-06-08 04:01:40
【问题描述】:

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

问题的确切细节是“END-ALL”子句。 该语言具有“IF”(由“END-IF”封闭)、“FOR”(由“END-FOR”封闭)等结构。

但可以选择使用“END-ALL”全局关闭所有此类开环(从而无需实际的“END-IF”或“END-FOR”子句)。

无论如何我可以正确地实现这个吗?

【问题讨论】:

    标签: antlr


    【解决方案1】:

    您可以通过在您的if(和for-)语句中创建一个布尔标志来跟踪是否需要使用ENDALL,或者前瞻是否足够。这个布尔标志被传递给匹配 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,要么只向前看是否存在此类令牌,​​但不使用它。

    关于谓词的更多信息:What is a 'semantic predicate' in ANTLR?

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

    脚本 1

    if 1 do
      print a
      if 2 do
        print b
        print c
        if 3 do
        end
      end
    end
    print d
    

    脚本 2

    if 1 do
      print a
      if 2 do
        print b
        print c
        if 3 do
    endall
    print d
    

    即以下AST:

    (使用graphviz-dev.appspot.com生成的图像)​​

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

    import org.antlr.runtime.*;
    import org.antlr.runtime.tree.*;
    import org.antlr.stringtemplate.*;
    
    public class Main {
      public static void main(String[] args) throws Exception {
        String source =
            "if 1 do        \n" +
            "  print a      \n" +
            "  if 2 do      \n" +
            "    print b    \n" +
            "    print c    \n" +
            "    if 3 do    \n" +
            "endall         \n" +
            "print d          ";
        System.out.println(source + "\n------------------\n");
        TLexer lexer = new TLexer(new ANTLRStringStream(source));
        TParser parser = new TParser(new CommonTokenStream(lexer));
        CommonTree tree = (CommonTree)parser.parse().getTree();
        DOTTreeGenerator gen = new DOTTreeGenerator();
        StringTemplate st = gen.toDOT(tree);
        System.out.println(st);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      相关资源
      最近更新 更多