JavaCCを使ってみる

RPG等のゲームでは、描画処理や当たり判定等をJava/C/C++等の言語で実装す る一方、独自実装のスクリプト言語にイベント(例えば主人公が自動的に任意 の場所へ移動する等)を記述することが多いと思います。 Javaでスクリプト言語を実装するのに有用な、コンパイラコンパイラである JavaCCを使用します。

 

1. osx portのjavacc

下記コマンドでJavaCCは入手できますが。

$ sudo port install javacc
$ javacc
Java Compiler Compiler Version 6.0_beta (Parser Generator)
<snip>

どうも実行してみるとVISITOR=trueが上手く動作しませんでした。

  /** Accept the visitor. **/
  public Object jjtAccept(ExprParserVisitor visitor, Object data) {
    return visitor.visitHoge(this, data); #visitor.visitになってほしい
  }

javacc-5.0にバージョンをダウングレードしてみます。

2. ダウンロード

JavaCCのダウンロードページからjavacc-5.0.tar.gzをダウンロードします。 ファイルはjavacc.jarとスクリプトファイルなのでコンパイル作業は不要です。

3. インストール

javaccというスクリプトファイルがカレントディレクトリ配下のlibに javacc.jarが格納されていることを期待するので、javaccとjavacc.jarは同一 ディレクトリ配下に格納します(javaccを書き換えればこの限りではありませ ん)。私はPATHが通っているホームディレクトリ配下のbinに格納しました。

$ tar zxvf javacc-5.0.tar.gz
$ cp -a javacc-5.0/bin/* ~/bin/
$ javacc
Java Compiler Compiler Version 5.0 (Parser Generator)
<snip>

4. Androidで簡易な電卓

CodeZineのサイトでは電卓用のコードが公開されています。 javacc3sample.zipのexpression4を使用して、Androidで電卓を作成します。

javaccのディレクトリを示す変数のjavacc.dirを先ほどインストールしたディ レクトリに変更します(user.homeはホームディレクトリを示す変数です)。

--- build.properties.org        2014-04-09 09:57:48.000000000 +0900
+++ build.properties    2014-04-09 09:56:34.000000000 +0900
@@ -1,4 +1,4 @@
-javacc.dir=C:\java\tool\javacc-4.0
+javacc.dir=${user.home}/bin/lib
 
 src.dir=src
 build.classes.dir=build/classes

以下のようなActivityを作成します。

(上) EditText
  1+2等の式を入力するフィールドです。
(中) Button
  EditTextの文字列を取得し、CodeZineの電卓用コードを通して計算を実行し
  ます。計算結果をTextViewの文字列に設定します。
(下) TextView
  計算結果を出力するフィールドです。

コードは以下の通りです。calc()メソッドのExprParser parser = ...以降で CodeZineの電卓コードに処理を任せます。

public class MainActivity extends ActionBarActivity {
  
  private LinearLayout mLayout;
  private Button mButton;
  private EditText mEditText;
  private TextView mTextView;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    mLayout = new LinearLayout(this);
    mLayout.setOrientation(LinearLayout.VERTICAL);
    
    mEditText = new EditText(this);
    mLayout.addView(mEditText);
    
    mButton = new Button(this);
    mButton.setText("calc");
    mButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        calc();
      }
    });
    mLayout.addView(mButton);
    
    mTextView = new TextView(this);
    mTextView.setText("none");
    mLayout.addView(mTextView);
    
    setContentView(mLayout);
  }
  
  public void calc() {
    String question = mEditText.getText().toString();
    if (question.length() == 0)
      return;
    Log.d("calc", question);
    ExprParser parser = new ExprParser(new StringReader(question));
    Expr visitor = new Expr();
    try {
      ASTStart start = parser.Start();
      String answer = ((Integer) start.jjtAccept(visitor, null)).toString();
      Log.d("calc", answer);
      mTextView.setText(answer);
    } catch (Exception e) {
      e.printStackTrace();
      mTextView.setText("NaN");
    }
  }
<snip>
}

起動すると以下の画面のようになります。CodeZineのコードは括弧、演算子の 優先順位もケアしてくれるため、関数電卓のようになります。