Parasol

- 実行時文法定義のできる構文解析ライブラリ -

Parasol は,固定した文法を持たない構文解析ライブラリです. アプリケーションなどに適切な文法のスクリプト機能を持たせたい場合や,特殊な作業のための独自のインタプリタを作成したい場合などに便利に使えます. 完全にライブラリとして実装されており,コンパイラ以外の外部ツールや特定フォーマットの入力ファイルなどを必要としません. その一方で,演算子や文,組み込み関数・クラスなど,ほとんどの文法要素を独自に定義することができます. さらに,式パーザやトークナイザなどの単体利用も簡単にでき,実行時に入力された式の計算などにも利用することができます.

パーザを構成する言語要素(演算子,文,組み込み関数・クラス,実行エントリなど)をまとめて,言語ユニットを作成することができます. 言語ユニットは,別の言語ユニットをマージしたり,そこに新しい文法要素を追加したりすることができます. Parasol には,C言語で使われるほとんどの演算子や文を定義した言語ユニットも付属しており,それをベースにして独自のスクリプトを作成することもできます.

ただし,今のところ,型の扱いがちょっと弱いです.

作成には充分注意していますが,間違い等が含まれている可能性があります. 動作の保証はできませんので,御了承下さい. ライセンスは "LGPL Version 2.1" または "Modified BSD" とします. どちらか一方を選んで適用してください. LGPL2.1 の詳細については, COPYING-LGPL2.1 ファイル を,"Modified BSD" の詳細については COPYING-ModifiedBSD ファイル を参照してください.これらのファイルはソースコードに付属しています.

Parasol は,分散型汎用オンライン環境の構築を目指す KiNOKO プロジェクトの一部として作成されました. KiNOKO プロジェクトの詳細については, KiNOKO ホームページ を御覧下さい.


動作環境

現在のところ,以下の環境で動作確認をしています. ANSI C++ 準拠の C++ コンパイラなら,たぶん問題なくコンパイルできると思います.
Linux 2.2/2.4/2.6
gcc 2.95 / 3.3 / 4.1
Intel C++ Compiler 5.0.1

AIX 4.3.3
VisualAge C++ Version 5
gcc 2.95

ダウンロードとフィードバック

[注意] Parasol ライブラリ自体は KiNOKO の一部としてメンテナンスされているものの,このページは最近あまりメンテナンスされていません.最新版の Parasol ライブラリは KiNOKO パッケージの kinoko/src/kernel/lib-common/parasol に含まれています.KiNOKO パッケージは,KiNOKO ホームページ よりダウンロードできます. kinoko/src/kernel/lib-commom/parasol 以下だけをコピーすれば,ここで配布されているパッケージと同じものになります.

インストール方法

サンプルプログラム

ディレクトリ samples には,いくつかのサンプルプログラムがあります. samplesディレクトリで makeとすればコンパイルできます.
yaci.cc
YACI は,Parasol に標準で用意されている文法要素のみから作ったインタプリタです.基本的な文法はC言語と同じですが,いくつかの違いがあります.主な違いは以下の通りです.

あと,標準ライブラリ関数もありません (いくつかの「組み込みクラス/関数」はあります).

このディレクトリには,YACI のためのサンプルスクリプトがいくつかあります.これらは,Parasol 標準パーザの言語機能のテストおよびデモンストレーションのためのものです.以下は,それらの簡単な説明です.

hello.yaci は, 新しい言語を使い始めるときに,最初に書く決まりになっているプログラムです.実行すると,世界に挨拶をします.

    
    % ./yaci hello.yaci
    hello, world.

factorial.yaci は, YACI が処理できるスクリプトのサンプルです.ここでは,0 から 9 までの整数の階乗を計算しています.言語機能を示すためのサンプルなので,冗長で一貫性がありませんが,関数の定義・呼び出しや,出力の方法などを示しています.

    
    % ./yaci factorial.yaci
    5! = 120
    6! = 720
    7! = 5040
    :    :

line-number.yaci も, YACI が処理できるスクリプトのサンプルです.引数に指定されたファイルを一行ずつ読み込み,行番号を付加して標準出力へ書き出します.言語機能のサンプルのため,出力部分で一文字ずつ表示していたりなど,冗長で遅いですが,文字列型やポインタの使用方法などを示しています.

    
    % ./yaci line-number.yaci factorial.yaci
    1: // factorial.yaci
    2: // Created by Enomoto Sanshiro on 4 September 1999.
    3: 
    4: int start_index = 5;
    5: int stop_index = 2 * start_index + 1;
    :                 :                    :

dump.yaci は,書式化出力のサンプルです.実行すると標準入力を読んで,それを16進ダンプします.

    % ./yaci dump.yaci < foo
    0000 0000: 3f 8b 08 08 5e 17 ae 39  00 03 66 6f 6f 00 bc 5b 
    0000 0010: 0d 74 14 55 96 7e 81 a4  29 31 6a 80 8c e0 08 63 
     :    :          :                        :

matherror.yaci は,数学関数の使用とエラーハンドリング (try-catch文)のサンプルです.何の役にも立ちません.

array.yaci は,C 型の配列およびポインタのサンプルです.C型配列は構文にC言語と互換性があり,また,比較的高速に動作しますが,ユーザにメモリ管理の責任が生じます.通常は,以下のリスト型を使用した方がいいでしょう.

variant.yaci は,バリアント型および「特殊スコープへの変数生成とアクセスをする演算子(仮称)」$ のサンプルです.バリアント変数は,保持している値に応じて型が変わりますが,ちゃんと型付けされた変数です.型は,typeof() 演算子により知ることができます.$ 演算子は,多くのインタプリタにあるような,明示的な宣言なしで変数を使えるようにする特殊な演算子です.$名前 または ${名前の文字列式} によりこの変数を使用できます.型はバリアントで,スコープは,「$ 演算子により参照される変数のためのグローバルなスコープ(仮称)」になります.簡単に言えば,perl のような感じで使えます.

list.yaci は,Parasol 独自のプリミティブ型であるリスト型のサンプルです.リストとは,バリアント型の可変長配列のようなものですが,プリミティブ型として実装されているため,演算子や文など他の文法要素のサポートがあり,より便利に使えるようになっています.

listmath.yaci は,リスト型変数に対する算術演算のサンプルです.加減乗除や累乗などの算術演算および数学関数は,リスト型の変数に対しては,各要素への演算を行います.また,リスト型変数と非リスト型変数(スカラ変数)の混合演算も,スカラをリストに拡張して演算を行います.これらの振舞いは,特にベクトル計算やデータ解析などに便利です.

solve.cc
式パーザをプログラムに組み込んで使用するサンプルです. 引数に渡された関数 f(x) に対し,f(x)=0 となる xの値(の一つ)を (可能ならば)求めます.計算にはニュートン法を用いていますが, 構文解析のサンプルとして複雑にならないように,数値計算として必 要な細かい処理はしていません.
    % ./solve "x**2 - 2"
    x[1] = 1.5
    x[2] = 1.41667
    x[3] = 1.41422
    x[4] = 1.41421
第2引数に計算の初期値を与えることができます.省略した場合の初期値は 1 です.

チュートリアル

チュートリアル 1: パーザの拡張
Parasol の標準パーザ YACI に,組み込みクラスや組み込み関数,文,演算子などを追加して拡張する方法について説明します.

チュートリアル 2: アプリケーション内オブジェクトへのインターフェース
Parasol を使用して,スクリプトからアプリケーション内部のオブジェクトにアクセスする方法を,マクロ機能付きドローツール MacroDraw の開発を例にとって説明します.

チュートリアル 3: ライブラリの部分利用
Parasol の構成要素であるトークナイザ,式パーザ,文パーザなどの,ライブラリの一部の機能のみをアプリケーションから利用する方法について説明します.

分散型汎用データ収集システム KiNOKO では,Parasol をベースにして SQL データベースアクセスや正規表現,低レベルシステムアクセスなどのインターフェースを追加したスクリプトを使用しています.詳細は,KiNOKO ホームページを参照してください(KiNOKO パッケージに含まれている Parasol ライブラリの方が最新の安定版です.このページの更新は最近ちょっと遅いです).


既知の不具合

更新履歴

11 November 2005
標準スクリプトの catch 文の文法定義の誤りを修正
スクリプトで例外発生時にメモリリークが生じる問題を修正
ライセンス文中の Parasol のバージョン番号がずれていたのを修正
(上記全てA.K.I.さんの指摘および修正によるものです.ありがとうございました)
Version 0.5.1 リリース.
20 Aug 2005
C 型配列宣言をサポート.
組み込みクラスで2項演算子のオーバロードをできるようにした.
組み込みクラスでプロパティアクセスをできるようにした.
文字列インデクスによるリスト要素アクセスをできるようにした.
シェルコマンド実行・置換の関数を追加.
組み込みクラスのメソッド呼出しに引数の参照渡しをできるようにした.
上記に関連して以下のメソッドの引数を変更.オーバーライドしている場合は注意.
プリミティブ型 void と bool を導入
リスト処理を強化
Version 0.5.0 リリース.
27 Mar 2002
後置演算子・特殊演算子をサポート.
C 型配列をサポート
プリミティブ型 variant を追加.
プリミティブ型 list を追加.あわせてリスト演算子もいくつか追加.
foreach 文を追加.
組み込みクラス・組み込み関数の呼び出し形式を変更 (DispatchMessage(string) を InvokeMethod(int) に).
Version 0.4.0 リリース.
4 Mar 2002
TParaObjectPrototype に Destruct() を追加.
オブジェクト型の ParaValue がシンボルテーブルから削除されるとき、保持しているオブジェクトも delete されるようにした.
関数の戻り値に void を指定できるようにした.
トークナイザでコメントやホワイトスペースをトークンとして返せるようにした.
識別子を構成するアルファベットを指定できるようにした.
実行時のエラーメッセージにも行番号を表示するようにした.
Version 0.3.1 リリース.
24 Oct 2001
サンプルの solve.cc で math.h をインクルードするのを忘れていたのを修正.
TOperator, TStatement, TPackage において,StatementParser を渡す場所を Parse() メソッドに統一(以前はコンストラクタで渡しているものもあった).
Package レベルの構文解析器を実装するのに必要な一連のオブジェクトを一つにまとめたクラス TParser を追加.
クラス TObjectFactory のクラス名を TObjectPrototypeTable に変更.
標準ライブラリに書式付き入力のためのクラス Scanner を追加.
演算子の優先順位を相対的に指定するためのクラス OperatorPriority を追加.
標準文法セットの for 文で continue したときに生じる不具合を修正.
C++ の namespace に対応.
Parasol 内部クラスのクラス名を 全て TPara... に変更.
Version 0.3.0 リリース.
13 Sep 2000
大域変数の初期化に組み込み関数を使用すると大変なことになる不具合を修正.
throw 文を追加.
Version 0.2.2 リリース.
4 Sep 2000
スクリプト中で定義された関数中から組み込み関数が見えない不具合を修正.
標準ライブラリに Argument を追加.Math もちょっと充実させた.
式パーザをプログラムに組み込んで使うサンプル solve を追加.
Version 0.2.1 リリース.
31 Aug 2000
組み込み関数をサポート.
(打田さん(村瀬工業)の示唆に基づく実装です.ありがとうございました)
TObjectPrototype::DispatchMessage() の仕様を変更. 戻り値を int とし,メッセージの解釈に失敗した場合 1 を返すようにした.
組み込みクラスのクラス名を変更.TParaXxxObjectに統一.
try-catch 文を追加.だたし,今のところ catch 節は引数をとらない.
除算演算子の不具合(分母の絶対値が1以下のとき divide by zero になる)を修正.
メソッド呼び出し部分のコードを改良.だいぶすっきりとして見通しが良くなった.と思う.
標準ライブラリに書式化出力のためのクラスを追加.
YACI のサンプルをいくつか追加.
Version 0.2.0 リリース.
24 Aug 2000
エスケープシーケンスの置き換えによりおこる漢字(SJIS)の文字化けを修正.
(打田さん(村瀬工業)の修正コードによる修正です.ありがとうございました)
演算子と文をパーザに追加する方法のサンプルを追加.
ライセンスを LGPL2.1 に決定.ライセンスファイルを添付.
Version 0.1.2 リリース.
2 May 2000
コンストラクタに引数を渡せるようにした.
最上位構造 (Package) にユーザ定義エントリを登録できるようにした.
テーブルに登録されたプロトタイプオブジェクトはテーブルのデストラクタで削除するようにした.
関数の宣言構文を変更可能なようにした.
標準ライブラリにコンテナクラス(いまのところvectorのみ)を追加した.
Version 0.1.1 リリース.
15 Jan 2000
Version 0.1.0 リリース.

今後の予定

型の扱いをまともにする.
非クラスの組み込み型を追加できるようにする.
ユーザ定義型を導入する.
標準ライブラリを充実させる.
システムコールインターフェース,数値計算,GUI(tk/Qt/Gtk インターフェース) など.

Edited by: Enomoto Sanshiro