[英]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
,则每个解析器规则都会创建(并返回)一个名为retval
的ParserRuleReturnScope
实例:因此您可以将其用于您的目的:
// ...
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.