これで勝つる! PEGベースのコンパイラコンパイラpaccに触れる

PEG-MLにPEGベースのコンパイラコンパイラpacc-0.0のリリースが告知された。

今までyaccやbisonなどを使わなければならなかったパーサも、paccを利用すれば強力なPEGベースのメタ言語を使って記述できる。この記事ではこの登場したばかりのコンパイラコンパイラ、paccに触れてみた。

インストール

コンパイルに必要なboostライブラリを予めインストールしておく。Macならhomebrewからインストールできる。

$ brew install boost

ソースコードをダウンロードしてきて解凍してmake。

$ tar -xvf pacc-0.0.tar.bz2
$ cd pacc-0.0
$ make 

エラーが出ずにpaccを叩ければ成功。なんか0.0のバージョン名なのかronin(浪人?)と書いてある。

./pacc -v 
pacc 0.0 (rōnin)
Written by Tobold Jayne Goodwin <toby@paccrat.org>

Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

実際に使ってみる

ドキュメントのチュートリアル通りにやってみる。

まず文法ファイルparser.paccを作成。入力が"yes"であれば1を、"no"であれば0を返す簡単なパーサ。メタ言語の文法はPEGをいくらか拡張しているので、メタ言語の詳細はドキュメントのGrammerの章ソースコードのpacc-0.0/test/pacc以下に含まれているテストケースを参考にする。

/* parser.pacc */

Start <- "yes" {1} / "no" {0}

paser.paccをparser.cにコンパイル

$ path/to/pacc parser.pacc --output=parser.c

次にmain関数のコードを書く。コマンドラインの引数をそのままパーサに引き渡す。pacc_wrap関数は、生成されたパーサを簡単に呼び出してくれる便利な関数。

/* main.c */
#include <stdio.h>
#include <string.h>

#include "parser.c"

int main(int argc, char **argv) {
    int result;

    if (argc != 2) {
        fprintf(stderr, "one argument please\n");
        return 1;
    }   

    if (pacc_wrap("arg", argv[1], strlen(argv[1]), &result)) {
        printf("parsed with value %d\n", result);
    } else {
        return 1;
    }   

    return 0;
}

コンパイル

$ gcc main.c 

試す。

$ ./a.out 
one argument please

$ ./a.out yes
parsed with value 1

$ ./a.out no
parsed with value 0

$ ./a.out hoge
arg:1:1: expected Start

yesやnoを入力するとそれに応じた結果が返り、それ以外の入力を与えるとパースに失敗していることがわかる。

終わりに

PEGでは、従来必要だった字句解析器と構文解析器の2つをまとめて記述できる。そして実際にそれができてかつC言語のコードを吐くことができるpaccが登場した。つまり、今までre2cやbisonを使って記述していた字句解析器、構文解析器をこれひとつで置き換えられる選択肢が出てきた。

この記事ではpaccのごく基本的な使い方を紹介した。