我无法搞清楚antlr3 API,因此我可以在一些javascript代码中生成并使用解析树。当我使用antlrWorks(他们的IDE)打开语法文件时,解释器能够向我显示解析树,它甚至是正确的。
我在使用antlr3运行时跟踪有关如何在我的代码中获取此解析树的资源方面遇到了很多困难。我一直在搞乱运行时和Parser文件中的各种函数,但无济于事:
var input = "(PR=5000)",
cstream = new org.antlr.runtime.ANTLRStringStream(input),
lexer = new TLexer(cstream),
tstream = new org.antlr.runtime.CommonTokenStream(lexer),
parser = new TParser(tstream);
var tree = parser.query().tree;
var nodeStream = new org.antlr.runtime.tree.CommonTreeNodeStream(tree);
nodeStream.setTokenStream(tstream);
parseTree = new org.antlr.runtime.tree.TreeParser(nodeStream);
由于antlrWorks可以显示自己没有任何树语法的解析树,并且因为我已经读过antlr自动从语法文件生成一个解析树,我假设我可以通过一些运行时函数访问这个基本的解析树我可能不知道。我这个想法是否正确?
答案 0 :(得分:7)
HugeAntlrs写道:
由于antlrWorks可以显示自己没有任何树语法的解析树,并且因为我已经读过antlr自动从语法文件生成一个解析树,我假设我可以通过一些运行时函数访问这个基本的解析树我可能不知道。我这个想法是否正确?
不,那是不正确的。 ANTLR创建一个平坦的,1维的标记流。
ANTLRWorks在解释某些来源时动态创建自己的解析树。您无法访问此树(不使用Javascript或使用Java)。您必须定义您认为应该是(子)树的根的标记和/或定义需要从AST中删除的标记。查看以下问答,解释如何创建正确的AST:How to output the AST built using ANTLR?
由于SO上还没有正确的JavaScript演示,这里有一个快速演示。
以下语法使用以下运算符解析布尔表达式:
其中not
具有最高优先级。
当然有true
和false
,表达式可以用括号分组。
grammar Exp;
options {
output=AST;
language=JavaScript;
}
parse
: exp EOF -> exp
;
exp
: orExp
;
orExp
: andExp (OR^ andExp)*
;
andExp
: eqExp (AND^ eqExp)*
;
eqExp
: unaryExp (IS^ unaryExp)*
;
unaryExp
: NOT atom -> ^(NOT atom)
| atom
;
atom
: TRUE
| FALSE
| '(' exp ')' -> exp
;
OR : 'or' ;
AND : 'and' ;
IS : 'is' ;
NOT : 'not' ;
TRUE : 'true' ;
FALSE : 'false' ;
SPACE : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;} ;
上面的语法产生一个AST,可以将其输入下面的树木行走者:
tree grammar ExpWalker;
options {
tokenVocab=Exp;
ASTLabelType=CommonTree;
language=JavaScript;
}
// `walk` returns a string
walk returns [expr]
: exp {expr = ($exp.expr == 1) ? 'True' : 'False';}
;
// `exp` returns either 1 (true) or 0 (false)
exp returns [expr]
: ^(OR a=exp b=exp) {expr = ($a.expr == 1 || $b.expr == 1) ? 1 : 0;}
| ^(AND a=exp b=exp) {expr = ($a.expr == 1 && $b.expr == 1) ? 1 : 0;}
| ^(IS a=exp b=exp) {expr = ($a.expr == $b.expr) ? 1 : 0;}
| ^(NOT a=exp) {expr = ($a.expr == 1) ? 0 : 1;}
| TRUE {expr = 1;}
| FALSE {expr = 0;}
;
(为{ ... }
中的凌乱JavaScript代码道歉:我对JavaScript的经验很少!)
现在下载ANTLR 3.3(没有早期版本!)和JavaScript运行时文件:
将antlr-3.3-complete.jar
重命名为antlr-3.3.jar
并解压缩antlr-javascript-runtime-3.1.zip
并将所有文件存储在与Exp.g
和ExpWalker.g
文件相同的文件夹中。
现在生成lexer,parser和tree-walker:
java -cp antlr-3.3.jar org.antlr.Tool Exp.g java -cp antlr-3.3.jar org.antlr.Tool ExpWalker.g
使用以下html文件测试所有内容:
<html>
<head>
<script type="text/javascript" src="antlr3-all-min.js"></script>
<script type="text/javascript" src="ExpLexer.js"></script>
<script type="text/javascript" src="ExpParser.js"></script>
<script type="text/javascript" src="ExpWalker.js"></script>
<script type="text/javascript">
function init() {
var evalButton = document.getElementById("eval");
evalButton.onclick = evalExpression;
}
function evalExpression() {
document.getElementById("answer").innerHTML = "";
var expression = document.getElementById("exp").value;
if(expression) {
var lexer = new ExpLexer(new org.antlr.runtime.ANTLRStringStream(expression));
var tokens = new org.antlr.runtime.CommonTokenStream(lexer);
var parser = new ExpParser(tokens);
var nodes = new org.antlr.runtime.tree.CommonTreeNodeStream(parser.parse().getTree());
nodes.setTokenStream(tokens);
var walker = new ExpWalker(nodes);
var value = walker.walk();
document.getElementById("answer").innerHTML = expression + " = " + value;
}
else {
document.getElementById("exp").value = "enter an expression here first";
}
}
</script>
</head>
<body onload="init()">
<input id="exp" type="text" size="35" />
<button id="eval">evaluate</button>
<div id="answer"></div>
</body>
</html>
看到结果: