Java/GradleでのANTLRの使い方、その2
さて、次はAntlrで生成されたパーサーを使って、実際にオレオレ言語をパースしてみる。つまり、この言語で記述されたソースコードを読み込み、字句解析、構文解析して構文木を作り出し、構文木を調べて見ることにする。
とは言っても、いきなり「オレオレ言語」といった、たいそうな代物は作れない。今回作成するのは、ただの四則演算である。
3+2*4
これだけだ。これには、以下を参考にさせていただいたのだが、
初心者にとってはあまりにわからない。「ちょっとした」とか「便利」とかいう言葉とはかけ離れている。
ともあれ、この記事を参考に、少々アレンジしてみる。前回のTest.g4は削除し、以下を入れる。
Sample.g4
grammar Sample;
@header {
package myparser;
}
prog: expr;
expr: term (('+'|'-') term)*;
term: factor (('*'|'/') factor)*;
factor: INT
| '(' expr ')'
;
INT : [0-9]+ ;
Gradleで「generateGrammarSource」を実行すると以下になる。
TestMainは以下のようなものだ。
TestMain.java
package antlrTest;
import org.antlr.v4.runtime.*;
import myparser.*;
import myparser.SampleParser.*;
public class TestMain {
public static void main(String[] args) {
// 字句解析を行う
SampleLexer lexer = new SampleLexer(CharStreams.fromString("3+2*4"));
// 字句解析の結果を構文解析する
CommonTokenStream stream = new CommonTokenStream(lexer);
SampleParser sampleParser = new SampleParser(stream);
// 構文木を調べてみる
ProgContext p = sampleParser.prog();
System.out.println("p:" + p.getText());
ExprContext e = p.expr();
System.out.println(" e:" + e.getText());
e.term().forEach(t-> {
System.out.println(" t:" + t.getText());
t.factor().forEach(f-> {
System.out.println(" f:" + f.getText());
});
});
}
}
これを実行すると、以下が出力される。
p:3+2*4
e:3+2*4
t:3
f:3
t:2*4
f:2
f:4
つまり、Sample.g4の中で定義した、オレオレ言語のシンボル、prog, expr, term, factorといったものを扱うクラスが生成されており、構文解析(パース)を行うと、構文木がそれらのオブジェクトで表現される。
上位オブジェクトには、その下位オブジェクトが格納されているので取得する。こうやって次々と下位オブジェクトを取得していけばよい。
※先の記事にもあるように、この方法とは別にVisitorパターンを使う方法もある。