ANTLR4で生成したファイルをjrubyから触ってみる

ANTLR4でパーサまでを生成してクラスをjarにして、扱うときはJRubyからアクセスしてみます。
あまり、ANTLR4には詳しく説明しません。まだよくわからいので。

準備

Java JDK7準備

以下のページからJDKを落とします。
http://www.oracle.com/technetwork/java/javase/downloads/index.html

Linuxならば、たとえば jdk-7u25-linux-x64.tar.gz を以下のように配置します。

 % sudo mkdir /opt
 % cd /opt
 % sudo tar xzf ~/Download/jdk-7u25-linux-x64.tar.gz
 % cd
 % vi ~/.bashrc
...
PATH=$PATH:/opt/jdk1.7.0_25/bin
export PATH
...
 % source ~/.bashrc

javaとjavacとjarのコマンドがあることを確認します。(ex. % which javac)

JRubyの準備

http://jruby.org/
ここでは、jruby-1.7.4 が最新です。

antlr4の準備

まずは、antlr4をダウンロードします。
http://www.antlr4.org/download/
antlr-4.1-complete.jar

Hello.g4 記述

まずは、antlr4用のファイルを用意します。
手始めに、次に記載されているものをそのまま使います。
http://www.antlr.org/wiki/display/ANTLR4/Getting+Started+with+ANTLR+v4

  • Hello.g4
// Define a grammar called Hello

grammar Hello;

r : 'hello' ID ;
ID : [a-z]+ ;
WS : [ \t\r\n]+ -> skip ;

コンパイル&jar化

  • Javaコード生成
 % java -jar ./antlr-4.1-complete.jar Hello.g4

Hello.tokens
HelloBaseListener.java
HelloLexer.java
HelloLexer.tokens
HelloListener.java
HelloParser.java

 % javac -cp ./antlr-4.1-complete.jar Hello*.java

HelloBaseListener.class
HelloLexer.class
HelloListener.class
HelloParser$RContext.class
HelloParser.class

  • Jar化
 % mkdir Hello
 % mv *.class Hello
 % jar cf Hello.jar -C Hello .

Hello.jar


ここからRubyになります。

hello.rbでListenerコードを書く

同じディレクトリに、以下のファイルがあることを確認してください。

  • antlr-4.1-complete.jar
  • Hello.jar (作成したjarファイル)
  • hello.rb
$:.unshift File.dirname(__FILE__)
require 'java'
require 'antlr-4.1-complete.jar'
require 'Hello.jar'
java_import "org.antlr.v4.runtime.ANTLRInputStream"
java_import "org.antlr.v4.runtime.CommonTokenStream"


class TestHelloListener
  include Java::Default::HelloListener
  def enterR(ctx)
    puts "enterR"
  end 

  def exitR(ctx)
    puts "exitR"
    puts ctx.ID
  end 

  def enterEveryRule(ctx)
  end 

  def exitEveryRule(ctx)
  end 

  def visitTerminal(node)
  end 

  def visitErrorNode(node)
  end 

end

input = ANTLRInputStream.new("hello aaa")
lexer = Java::Default::HelloLexer.new(input)
tokens = CommonTokenStream.new(lexer)
parser = Java::Default::HelloParser.new(tokens)

parser.addParseListener(TestHelloListener.new)
parser.r

JRubyで実行

 % jruby hello.rb

enterR
exitR
aaa