HugeAntlrsは書いた:
antlrWorksは自分自身のツリー文法なしで解析ツリーを表示でき、antlrが文法ファイルから解析ツリーを自動的に生成することを読んだので、私はこの基本的な解析ツリーにアクセスできると思います。おそらく気づいていません。私はこの考えで正しいですか?
いいえ、それは正しくありません。ANTLRは、フラットな1次元のトークンストリームを作成します。
ANTLRWorksは、ソースを解釈するときに、その場で独自の解析ツリーを作成します。このツリーにアクセスすることはできません(Javascriptを使用したり、Javaを使用したりすることはできません)。(サブ)ツリーのルートであると思われるトークンを定義するか、ASTから削除する必要のあるトークンを定義する必要があります。適切なASTを作成する方法を説明する次のQ&Aをチェックしてください:ANTLRを使用して構築されたASTを出力する方法は?
編集
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を生成します。
ファイル: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
次に、レクサー、パーサー、ツリーウォーカーを生成します。
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>
そして結果を見よ: