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