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パターンを使う方法もある。