HugeAntlrs 写道:
由于 antlrWorks 可以在没有我自己的任何树语法的情况下显示解析树,并且由于我已经阅读了 antlr 自动从语法文件生成解析树,所以我假设我可以使用一些运行时函数访问这个基本的解析树。大概不知道。我的这种想法正确吗?
不,这是不正确的。ANTLR 创建一个平面的一维令牌流。
ANTLRWorks 在解释某些源时动态创建自己的解析树。您无权访问此树(不能使用 Javascript 甚至 Java)。您必须定义您认为应该是(子)树根的标记和/或定义需要从 AST 中删除的标记。查看以下解释如何创建正确 AST 的问答:如何输出使用 ANTLR 构建的 AST?
编辑
由于在 SO 上还没有合适的 JavaScript 演示,这里有一个快速演示。
以下语法使用以下运算符解析布尔表达式:
其中not
优先级最高。
当然还有true
and false
,并且可以使用括号对表达式进行分组。
文件:Exp.g
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-walker:
文件:ExpWalker.g
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
现在生成词法分析器、解析器和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>
看看结果:
