ANTLR(1)

compilercompilerを勉強中。bison, JavaCCくらいしか使ったことがないので、流行りのANTLRを。

めもめも。

導入

開発環境の起動

  • > java -jar antlrworks-1.y.z.jar
    • とりあえず1.1.3で確認
    • 拡張子の設定してあればダブルクリックでも。

初期設定

  • File > Preferences
    • General Tab > Output path: Same as grammar

出力先を選べる。面倒なので構文ファイルと同じところへ。

サンプル

  • File > New
  • 次のコードを追加
// Chapter 1, p11
grammar T;

@header {
package introduction;
}

@lexer::header {
package introduction;
}

// Parser
r	: 'call' ID ';' EOF
             { System.out.println("invoke " + $ID.text); }
	;

// Lexer
ID	: ('a'..'z')+
	;
WS	: (' '|'\n'|'\r')+
          { $channel = HIDDEN; }
	;
  • 先頭に grammar ;。今回は言語Tを作る
  • @headerで生成されるParserの先頭にコードを追加。
  • @lexer::headerで生成されるLexerの先頭にコードを追加。
  • 記法はyacc-likeにBNF+属性なイメージ
    • : { } | { } | ... | { } ;
  • ルール名を大文字で始めるとLexerルール扱い。この単位でトークンを作る
    • 文字チャネルをトークンチャネルに変換して、パーサはそれを利用する形式みたい。
    • アクション内で $channel = HIDDEN; と書くと、このトークンはスキップされるトークンとして扱われる。ルールWSはスペースや改行文字をトークンチャンネルから消す処理(空白スキップ)
  • ルール名を小文字で始めるとParserルール扱い。トークン先読みができる。
    • アクション内で $.text と書くと、トークン文字列を使える。
  • EOFは暗黙のLexerルールで、たぶんファイル終端。
  • File > Save As
    • ~/antlr/introduction/T.g (任意)

Parser/Lexerの生成

  • Generate > Generate Code
    • ~/antlr/introduction/build/T.tokens
      • トークン一覧
    • ~/antlr/introduction/build/T__.g
      • lexer文法
    • ~/antlr/introduction/build/TLexer.java
      • lexer
    • ~/antlr/introduction/build/TParser.java
      • parser

利用したプログラム

  • introduction/T.java
public class TTest {
  public static void main(String[] args)
        throws IOException, RecognitionException {

    ANTLRInputStream in =
        new ANTLRInputStream(System.in, "UTF-8");
    TLexer lexer = new TLexer(in);
    CommonTokenStream tokens =
        new CommonTokenStream(lexer);
    TParser parser = new TParser(tokens);
    parser.r();
  }
}
  • ANTLR本体に含まれるantlr-runtime-3.0.x.jarをパスに追加しておく
  • 文字ストリームは java.io.Reader ではなく org.antlr.runtime.CharStream を使う
    • org.antlr.runtime.ANTLRInputStream は CharStream の子孫
    • CharStream は look-ahead や rewind などの機能を持ってる
  • TLexer extends org.antlr.runtime.Lexer
    • lexerはトークンマネージャではなく、単にトークンソースとして扱われる。org.antlr.runtime.Lexer implements org.antlr.runtime.TokenSource
  • TParser extends org.antlr.Parser
    • トークンストリームは org.antlr.runtime.CommonTokenStream をかぶせた TLexer を渡す。
    • char-stream -> (token source) -> tokens -> (token stream) -> (parser) な感じ
    • TParser#ルール名 で開始 (parser.r())。

実行

  • EOFをEclipseで送る方法がわからん…
> echo call hoge; \
| java -cp bin;lib\antlr-runtime-3.0.1.jar introduction.TTest
invoke hoge