注:この原稿は、「電総研ニュース'98年3月号」に載ったものです。

拡張可能プリプロセッサキット EPP の開発

情報アーキテクチャ部 分散システムラボ 一杉裕志
アブストラクト: EPP is a pre-processor for programming languages which can be extended by adding plug-ins. Plug-ins can introduce new language features, possibly associated with new syntax. The users can incorporate multiple plug-ins into EPP simultaneously that fit the characteristics of their projects. Although the current target of EPP is only Java, the architecture of EPP is applicable to other programming languages.

1. 研究の背景

コンピュータを動かすためのプログラムは、プログラミング言語と呼ばれる 特殊な言語を用いて書かれている。 オペレーティングシステム、ビジネスソフト、CG、ゲームなど、 世界にあるほとんどすべての コンピュータソフトウエアは、 プログラマーによって、いわば手作業で書かれた物である。

このソフトウエアの生産性にもっとも影響するのが プログラミング言語であり、 コンピュータが誕生した直後から 計算機科学における重要な研究分野となっている。 最初のプログラミング言語 FORTRAN に始まり、 構造化プログラミング、オブジェクト指向などの大きな成果のおかげで プログラムの生産性が向上するとともに、従来では考えられなかった 複雑なソフトウエアが作られるようになった。 しかし、プログラミング言語の進歩の速度は、必ずしも速いものではなかった。

一方で、パーソナルコンピュータのハードウエアは、最近10年程度の間に 飛躍的な機能向上を果たしている。 これは IBM が標準的アーキテクチャを公開したことに始まる。 パーソナルコンピュータを構成する個々の部品を接続する規格が公開されたことで、 部品を製造する企業が多数現れ、自由競争の原理により、 部品の高機能化・多様化が促進された。

今回開発した EPP は、言語処理系の実装方法としてよく用いられるプリプロ セッサを部品化することで、パーソナルコンピュータに起きた進歩速度の向上を、 プログラミング言語の世界にも起こすことを目的としたシステムである。 もしこのシステムのような部品化された言語処理系が世界に普及すれば、 大学や企業は新しい言語機能部品を容易に提供でき、 プログラマはその中から自分の目的に最適なものを選んで使えるようになる。 その結果自由競争の原理により、プログラミング言語の 飛躍的な高機能化・多様化が起こることを期待している。

2. EPP の概要

プログラムのソースコードを読み込み、それに対して何らかの処理を施した後、 変更されたソースコードを出力するようなプログラムを、プリプロセッサと呼ぶ。 EPP は Java 言語のソースコードを処理するプリプロセッサである。 EPP それ自体は、 入力プログラムの意味を変えずに出力する 「何もしない」プリプロセッサである。 しかし、ユーザは EPP に入力するソースコードの先頭で、 EPP に追加する拡張部品(プラグイン)を指定することにより、 プリプロセッサとしての動作を変更・拡張することができる。 これにより Java 言語に新しい言語機能を追加することができる。

図2は、 EPP を用いた Java プログラムの例である。 ソースファイルの先頭に #epp で始まる行を書くことで、 取り込むプラグインを指定する。 この例では "enum" という名前のプラグインを取り込むことで、 もともとの Java 言語にない enum 構文が使えるようになる。 この入力プログラムは EPP によって、図3のようなプログラムに変換される。 出力プログラムは、普通の Java コンパイラでコンパイルされ、実行可能になる。

プラグインどうしの衝突さえ起きなければ、 プラグインを複数同時に指定することもできる。 プラグインの簡単な例として、連続値定数定義、省略可能引数、マクロ定義など Java にない機能を追加するものが現在いくつか用意されている。 この中から、プログラマは自分の目的にあったプラグインを複数選択して 組み合わせて使うことができる。

現在爆発的に普及しつつある Java 言語は優れたプログラミング言語であるが、 言語機能や構文を拡張する機構を全く持たない。 EPP はこの欠点を補い、様々な新しい言語機能や、 使いやすいライブラリを提供することを可能にする。

なお、 EPP のアーキテクチャは Java 言語には依存しておらず、 他のプログラミング言語やハードウエア記述言語などにも容易に応用できる。

3. 技術的特長

EPP は従来のシステムにない、以下の技術的特長を持つ。

3.1 部品化を支援する継承機構: System Mixin

オブジェクト指向言語はプログラムの部品化を支援すると 言われている。 しかし、言語処理系のように内部が複雑に依存し合うソフトウエアは、 従来からあるオブジェクト指向言語では、 十分な部品化は不可能であった。 筆者はその原因として、従来のクラスの概念が「部品(モジュール)の定義」と 「データ構造の定義」という、2つの役割を無理矢理統一している点にあると 考え、その2つの機構を完全に分離した言語機構を設計した。 System Mixin は、差分プログラミングのスタイルで部品を定義するための 機構である。 この機構により、言語処理系も 数行から数十行の細かい部品に分解して記述することができる。

図1は、 System Mixin を用いたプログラムの部品と、部品を組み合わせた結果を 摸式的に表わしたものである。 一枚一枚の絵は、最終的なできあがりの絵のうち、 ある側面から見た部分(この場合は色)だけを切り出したものである。 これらをすべて重ねると、一枚の完成した絵になる。 System Mixin を用いたプログラミングでは、個々の部品は、 なんらかの機能に密接に関連する部分だけを 切り出したものになる。 部品を複数重ねることで、完成した1つのプログラムになる。

EPP に複数のプラグインを同時に取り込めるのは、この System Mixin の 機構のおかげである。 この機能により、プリプロセッサのあらゆる拡張機能を、 オリジナルのプログラムに対する「追加部品」の形で記述することができる。

3.2 拡張可能な再帰下降パーザ

文法が拡張可能なプログラミング言語システムは従来から数多く存在するが、 いずれも文法の拡張範囲は制限されたものであった。 (例えば、演算子の追加に限る、など。)

EPP は、部品の追加によって広い範囲の文法拡張が行なえるような 設計になっている。 構文解析器は、 yacc などのパーザジェネレータを使わず、 再帰下降のスタイルで直接プログラムされている。 この構文解析器には、新しい構文や演算子を追加するための簡単な「しかけ」が 数多く仕組まれており、プラグインはそれを用いることで文法を拡張できる。

3.3 言語の文法に依存しないデータ構造

プリプロセッサが内部で扱うデータ構造のうち、 トークンと抽象構文木の2つが重要な役割を果たす。 通常はこの2つのデータ構造の定義は処理対象の言語の文法に強く依存するため、 文法が拡張されると、それにともなって変更が必要となる。 そして、データ構造の変更は、それを処理するプログラムの他の部分にも 広範囲に影響を与えてしまう。

EPP ではこの問題を避けるため、トークンと抽象構文木に、 処理対象の言語に依存しないような非常に汎用性の高い構造を持たせた。 このことも、複数の言語拡張プラグインを同時に適用できる理由の1つに なっている。

4. 実用化

EPP は、単なる技術的アイデアを試す実験システムにとどまらず、 実用的なツールとして広く使われることを目指している。 そのために、障害となり得る様々な問題を解決した。

5.まとめ

現在、 EPP の最初のバージョンが動き始めたばかりである。 EPP を使った応用例としては、約5000行のプログラムである EPP 自身と、 いくつかの小さなサンプルプログラムのみである。 今後、世界に向けて広くソフトウエアを公開し、 多くのユーザからのフィードバックを得ることでより使いやすいシステムに していくつもりである。
研究課題名:[特別研究]分散共同研究支援システムの研究
図1:(準備中)
説明: EPP の実現に必要な System Mixin の機能を摸式的に表わしたもの。 各色の絵を重ね合わせると1枚の完成した絵になるように、 複数のプログラム部品を組み合わせると1つの完成したプログラムになる。
#epp "enum"

public class EnumTest {
  enum {RED, GREEN, BLUE}
  enum {
    MALE,
    FEMALE,
  }
  public static void main(String argv[]){
    System.out.println(EnumTest.RED);
  }
}

図2: EPP を使ったプログラム例

/* Generated by EPP 1.0beta3 (by lisp-epp1.0beta3) */

public class EnumTest {
  public static final int RED = 0;
  public static final int GREEN = 1;
  public static final int BLUE = 2;
  public static final int MALE = 0;
  public static final int FEMALE = 1;
  
  public static void main(String argv[]){
    System.out.println(EnumTest.RED);
  }
}

図3: 変換結果

To EPP Home Page.