繁体   English   中英

获取活跃的 Antlr 规则

[英]Get active Antlr rule

是否可以获取调用操作方法的“活动”ANTLR 规则?

类似于 Antlr-Pseudo-Code 中的这个日志函数,它应该显示一些规则的开始和结束位置,而无需在每次 log() 调用时交出 $start- 和 $end-tokens:

@members{
  private void log() {
    System.out.println("Start: " + $activeRule.start.pos +
                       "End: " + $activeRule.stop.pos);
  }
}

expr: multExpr (('+'|'-') multExpr)* {log(); }
    ;

multExpr
    : atom('*' atom)* {log(); }
    ;

atom: INT
    | ID {log(); }
    | '(' expr ')'
    ;

(对于 Antlr4)

我在谷歌上搜索如何获取活动规则的名称并找到了这篇文章。 经过更多研究,我发现了如何做到这一点:

    prog:   statement[this.getRuleNames() /* parser rule names */]* EOF
        ;
    
    statement [String[] rule_names]
        locals [String rule_name]
        @after { System.out.println("The statement is a " + $rule_name + " : `" + $text + "`"); }
        :   stmt_a[rule_names] {$rule_name = $stmt_a.rule_name;}
        ;   
    stmt_a [String[] rule_names] returns [String rule_name]
        :   'stmt_a' { $rule_name = rule_names[$ctx.getRuleIndex()]; }
        ;

更通用的解决方案将上下文传递给周围规则,您可以从中提取有关最后一个活动规则的所有信息。

文件规则名称RuleName.g4

grammar RuleName;

prog
    @init {System.out.println("Last update 1026");}
    :   statement[this.getRuleNames() /* parser rule names */]* EOF
    ;

statement [String[] rule_names]
    locals [String rule_name, ParserRuleContext context]
    @after { $rule_name = rule_names[$context.getRuleIndex()];
             System.out.println("The statement is a " + $rule_name + " : `" + $text + "`" + " from " + $start + " to " + $stop); }
    :   stmt_a {$context = (ParserRuleContext)$stmt_a.context;}
    |   stmt_b {$context = (ParserRuleContext)$stmt_b.context;}
    |   stmt_c {$context = (ParserRuleContext)$stmt_c.context;}
    ;

stmt_a returns [Stmt_aContext context]
    :   'stmt_a' more { $context = $ctx; }
    ;

stmt_b returns [Stmt_bContext context]
    :   'stmt_b' more { $context = $ctx; }
    ;

stmt_c returns [Stmt_cContext context]
    :   'stmt_c' more { $context = $ctx; }
    ;
 
more
    :   ID+
    ;

ID : [A-Z] ;
WS : [ \t]+ -> channel(HIDDEN) ;
NL : [\r\n]+ -> skip ;

文件input.txt

stmt_c X Y Z
stmt_a A B C
stmt_b D E F

执行 :

$ export CLASSPATH=".:/usr/local/lib/antlr-4.9-complete.jar"
$ alias a4='java -jar /usr/local/lib/antlr-4.9-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ a4 -no-listener RuleName.g4 
$ javac RuleName*.java
$ grun RuleName prog -tokens input.txt 
[@0,0:5='stmt_c',<'stmt_c'>,1:0]
[@1,6:6=' ',<WS>,channel=1,1:6]
[@2,7:7='X',<ID>,1:7]
[@3,8:8=' ',<WS>,channel=1,1:8]
[@4,9:9='Y',<ID>,1:9]
[@5,10:10=' ',<WS>,channel=1,1:10]
[@6,11:11='Z',<ID>,1:11]
...
[@21,39:38='<EOF>',<EOF>,4:0]
Last update 1026
The statement is a stmt_c : `stmt_c X Y Z` from [@0,0:5='stmt_c',<3>,1:0] to [@6,11:11='Z',<4>,1:11]
The statement is a stmt_a : `stmt_a A B C` from [@7,13:18='stmt_a',<1>,2:0] to [@13,24:24='C',<4>,2:11]
The statement is a stmt_b : `stmt_b D E F` from [@14,26:31='stmt_b',<2>,3:0] to [@20,37:37='F',<4>,3:11]

不,无法获得解析器当前所在规则的名称。要意识到解析器规则默认情况下只是返回void Java 方法。 从 Java 方法中,您毕竟无法在运行时(在此方法内部时)找到它的名称。

如果您在语法的options { ... }中设置output=AST ,则每个解析器规则都会创建(并返回)一个名为retvalParserRuleReturnScope实例:因此您可以将其用于您的目的:

// ...

options {
  output=AST;
}

// ...

@parser::members{
  private void log(ParserRuleReturnScope rule) {
    System.out.println("Rule: "    + rule.getClass().getName() +  
                       ", start: " + rule.start +
                       ", end: "   + rule.stop);
  }
}

expr: multExpr (('+'|'-') multExpr)*    {log(retval);}
    ;

multExpr
    : atom('*' atom)*                   {log(retval);}
    ;

atom: INT
    | ID                                {log(retval);}
    | '(' expr ')'
    ;
// ...

然而,这不是一件非常可靠的事情:在下一版本的 ANTLR 中,变量的名称很可能会发生变化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM