Hug*_*lrs 3 antlr antlrworks parse-tree antlr3
我无法搞清楚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);
Run Code Online (Sandbox Code Playgroud)
由于antlrWorks可以显示解析树而不需要我自己的任何树语法,并且因为我已经读过antlr自动从语法文件生成一个解析树,我假设我可以使用一些运行时函数来访问这个基本的解析树.可能没有意识到.我这个想法是否正确?
HugeAntlrs写道:
由于antlrWorks可以显示解析树而不需要我自己的任何树语法,并且因为我已经读过antlr自动从语法文件生成一个解析树,我假设我可以使用一些运行时函数来访问这个基本的解析树.可能没有意识到.我这个想法是否正确?
不,那是不对的.ANTLR创建一个平坦的1维标记流.
在解释某些源时,ANTLRWorks会动态创建自己的解析树.您无法访问此树(不使用Javascript或使用Java).您必须定义您认为应该是(子)树的根的标记和/或定义需要从AST中删除的标记.查看以下问答,解释如何创建正确的AST:如何输出使用ANTLR构建的AST?
由于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;} ;
Run Code Online (Sandbox Code Playgroud)
上面的语法产生一个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;}
;
Run Code Online (Sandbox Code Playgroud)
(对于凌乱的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文件.
现在生成词法分析器,解析器和树行者:
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>
Run Code Online (Sandbox Code Playgroud)
看到结果:
