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

JRuby+LWJGLでGLSLを試してみる

はじめてということで、手始めに動くかどうかだけ試します。
GLSLのfragment側で色を緑にしてみます。

$:.unshift File.dirname(__FILE__)
require 'java'
require 'lwjgl.jar'

import org.lwjgl.opengl.Display
import org.lwjgl.opengl.DisplayMode
GL11 = org.lwjgl.opengl.GL11
GL20 = org.lwjgl.opengl.GL20

Display.setDisplayMode DisplayMode.new(300, 200)
Display.setTitle "sample"
Display.create


v_str = <<VERT
void main(void)
{
  gl_Position = ftransform();
}
VERT

f_str = <<FRAG
void main(void)
{
  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
FRAG

vid = GL20.glCreateShader(GL20::GL_VERTEX_SHADER)
GL20.glShaderSource(vid, v_str)
GL20.glCompileShader(vid)

fid = GL20.glCreateShader(GL20::GL_FRAGMENT_SHADER)
GL20.glShaderSource(fid, f_str)
GL20.glCompileShader(fid)

pid = GL20.glCreateProgram
GL20.glAttachShader(pid, vid)
GL20.glAttachShader(pid, fid)
GL20.glLinkProgram(pid)
linked = GL20.glGetProgram(pid, GL20::GL_LINK_STATUS)
puts "linked err." if linked==GL11::GL_FALSE

GL20.glUseProgram(pid)


GL11.glClearColor 0.1,0.1,0.1,1

while !Display.isCloseRequested 

  GL11.glClear GL11::GL_COLOR_BUFFER_BIT

  #GL11.glColor3d(1,0,0)
  GL11.glBegin GL11::GL_POLYGON
  GL11.glVertex2d(-0.5,-0.5)
  GL11.glVertex2d( 0.5,-0.5)
  GL11.glVertex2d( 0.5, 0.5)
  GL11.glVertex2d(-0.5, 0.5)
  GL11.glEnd

  Display.update
end

とくに難しいことなく動きました。
めでたしめでたし。
とりあえず、ここまで。

JRubyFXでボタンを押してラベルに表示するのを試してみた

jrubyfxのsampleをいろいろあさって、ボタンを押したらラベル表示を更新する簡単な実装を試してみました。

実装イメージはこんな感じ。

  • hello2.rb
require 'jrubyfx'

class Hello < JRubyFX::Application
  def start(stage)
    with(stage, title: "sample", width: 200, height: 100) do
      layout_scene do
        vbox do
          label("hello", id: 'view')
          button("push") do
            set_on_action do
              stage["#view"].text = "pushed!!!"
            end
          end
        end
      end
      show
    end
  end
end

Hello.launch


「ボタンを押した」というアクションはset_on_actionで取得。
動作はそのブロック内に記述します。
ハッシュが使えるので、labelにidを振っておいて、ハッシュでラベルのテキストを更新します。

実行してみる

 % jruby hello2.rb

swingよりもいい感じに書けます。とくにハッシュが使えるところが。
swingの知識がちょっとあればとりあえずなんとなく作れちゃいますね。
だんだん惚れてきました。

JRubyFXでまずは簡単なラベル表示をしてみた

まだ、JavaFXもよく理解していないですが、適当に実装してみます。
とりあえず、ラベルを使って文字列を表示するところから。
stage上に、まずはsceneを作って、その上にlabelとか貼っていけばよさそうです。

イメージはたぶんこんな感じ。

  • hello.rb
require 'jrubyfx'

class Hello < JRubyFX::Application
  def start(stage)
    with(stage) do
      layout_scene(200, 100) do
        label("hello")
      end
      show
    end
  end
end

Hello.launch

実行してみる

 % jruby hello.rb


rubyっぽくブロックで書けるように工夫されているみたい。
慣れるまでがちょい時間かかりそう、
でも簡潔に書けるのは好ましい。

JRubyFX+FXMLのデモを動かしてみた

今日試した限りでは、JRubyFXがrubygemsに登録されているものは動かなくて、直接githubから持ってきて、ようやく動きました。
2003/05/20にjrubyfxのバージョン1.0.0なるものがrubygemsにアップされたようです。
おそらく、FXMLローダあたりのバグが解消されています。

  • JRE7 Update 21 32bit
  • JRuby 1.7.4
  • jrubyfx (1.0.0 java)
  • jrubyfx-fxmlloader (0.2 java)

準備

JRE7インストール先に、jfxrt.jar があることを確認しました。
C:\Program Files (x86)\Java\jre7\lib\jfxrt.jar
にあれば大丈夫だと思います。

次に、

  • jrubyfx (1.0.0 以上)
  • jrubyfx-fxmlloader

をインストール

 % jruby -S gem install jrubyfx jrubyfx-fxmlloader

次に、JRubyFXのサンプルをgithubから落とします。
https://github.com/jruby/jrubyfx
Windowsならzipデータをダウンロードしてローカル環境に展開すればよいです。

デモを試す

 % cd jrubyfx-master
 % jruby sample/fxml/Demo.rb

とりあえず、動いたっぽい。
バグとかあるのかな、よくわからない。

RubyJavaFX、Swingと比べてなんかいろいろできそうな予感。
これからいろいろと試していければと思います。

JRubyFXのHelloWorldを実行してみた。

準備

 # jruby -S gem install jrubyfx

Hello.rb

require 'jrubyfx'

class HelloWorldApp < JRubyFX::Application
    def start(stage)
        stage.title = "Hello World!"
        stage.width = 200
        stage.height = 100
        stage.show()
    end
end

HelloWorldApp.launch

Jruby+LWJGL+RubeusでOpenGLしてみる

$:.unshift File.dirname(__FILE__)
require 'lwjgl.jar'
require 'rubeus'
Rubeus::Swing.irb

import org.lwjgl.opengl.AWTGLCanvas
GL = org.lwjgl.opengl.GL11

class MyCanvas < AWTGLCanvas

  def initialize
  end

  def initGL
    GL.glClearColor 0.0,0.0,0.0,1
    GL.glViewport(0, 0, width, height)
  end

  def paintGL
    GL.glClear(GL::GL_COLOR_BUFFER_BIT)

    GL.glColor3d(1,1,0)
    GL.glBegin GL::GL_POLYGON
    GL.glVertex2d(-0.5,-0.5)
    GL.glVertex2d( 0.5,-0.5)
    GL.glVertex2d( 0.5, 0.5)
    GL.glVertex2d(-0.5, 0.5)
    GL.glEnd

    swapBuffers
    repaint
  end

end


JFrame.new do |f|
  f.layout = BorderLayout.new
  canvas = MyCanvas.new
  f.size = "400x300"
  f.visible = true
end