Ninaチュートリアル

チュートリアルTOP - NEXT: サブオートマトンの使用

Ninaによるプログラミング

catコマンドの実装

Ninaを使用してプログラミングをしてみましょう。 簡単な例として、 ファイルを読み込んでそのまま出力するプログラム(UNIXのcat(1)コマンドのシンプルな版)を 作成してみましょう。
プログラムを以下に示します。

#machine DFABuilder
#option targetLanguage=Java
    +-.-+
 @S@^@@@v@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 @if($c >= 0)  System.out.print((char)$c);@
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
%%
public static void main(String[] args) throws Exception {
	parseAll(System.in);
}

Ninaが他のプログラミング言語と大きく異なる点は、状態があり、 状態ごとにソースコード断片を埋めていき、状態の遷移を記述するところにあります。
状態は"*"または"@"で囲まれた四角で表します。"@"は受理状態、"*"は非受理状態を表します。 受理状態で入力が終了すると、プログラムは正常終了します。 非受理状態で入力が終了すると、プログラムは構文エラーで終了します。
状態にはラベルを記述することができます。 ラベルは状態を表す四角の左上の頂点に次に記述します。 大文字のみのラベルを記述するときはそのまま記述します。 それ以外の文字が含まれる場合は'...'で囲みます。 ラベル名"S"は開始状態を表します。
状態から他の状態への遷移を記述するときは、 状態を表す四角から方向に対応する文字を記述し、 そこから遷移先の状態まで"-"(横方向への移動)、"|"(縦方向への移動)、 "+"(分岐:分岐のみ可能であり合流はできない)で記述します。
遷移のトリガとなる文字はラベルの中に書き込みます。
状態の中にはその状態に遷移したときに実行されるアクションがあります。 状態の中では、特別な変数$cが使用可能です。 $cは遷移のトリガとなったアルファベット(文字)が格納されます。 オートマトンが開始されたときにもアクションは実行されます。 そのとき、$cには負の整数(アルファベットが文字列等のときはNULL)が格納されます。
出力する言語は#option targetLanguageで指定します。ここではJavaを指定しています。 Javaの他にはCSharp(C#),JavaScriptが使用できます。

以上の点に留意して上記のプログラムを見てみましょう。 上記の例ですと、状態は開始状態のみであり、 開始状態からすべての文字("."で表現される)に対して同じ状態に戻る辺があります。
アクションでは、入力が非負の値のときに標準出力に1文字出力しています。 つまり、「ファイルから読み取った文字をそのまま標準出力に出力する」プログラムを表しています。
ソースをコンパイルしてみましょう。 Mac OS X/Linuxを使用しているときは以下のコマンドを.bashrcに入れてエイリアスを指定すると便利です。

alias ninat='java -jar path/to/nina.jar'
$ ninat cat.nina
$ javac Cat.java

コンパイルされたプログラムを実行してみましょう。

$ java Cat
aaaaaa
aaaaaa
(UNIXではCtrl-D, WindowsではCtrl-Z)

タブ文字を変換するcatコマンドの実装

タブ文字を見つけたら"¥t"に変換する機能を前節のプログラムに付けてみましょう。
プログラムを以下に示します。

#machine DFABuilder
#option targetLanguage=Java
    +-./'System.out.print((char)$c);'-+
 @S@^@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@v@@@@@@@
 @                                           @
 @@@v@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@^@@@@@@@
    +-'¥t'/'System.out.print("¥¥t");'-+
%%
public static void main(String[] args) throws Exception {
	parseAll(System.in);
}

最初に示したプログラムと異なり、タブ文字(¥t)のときの遷移が追加されていることと、 アクションが状態の中から辺のとなりに"/"を挟んで記述されていることがわかります。
Ninaでは、アクションを状態の中だけでなく辺にも記述できます。 辺に記述されたアクションは文字が遷移したときに実行されます。 状態の中のアクションと同様に、特殊変数$cで遷移した文字を取得することができます。

コンパイルして実行してみましょう。

$ nina catt.nina
$ javac Catt.java
$ java Catt
a(Tab)a
a¥ta
(Ctrl-D or Ctrl-Z)
$

wcコマンドの実装

UNIXのwc(1)コマンドの簡単なバージョンをNinaで作成してみましょう。
プログラムを以下に示します。

#machine DFABuilder
#option targetLanguage=Java
   +-.-+ +-------.--+
 @S^@@@v@v@@@      @^@@@@@@@@@@@@@@@@@@@@@@@
 @c++;      >-[¥s]->if($c == '¥n')  line++;@
 @@@@@@^@@@@@      @word++;  c++;          @
       |           @v@@@@@@@@@@@@@@@@@@@@@@@
       |            +-[¥s]--+
       |         @@@@@@@@@@@v@@@@@@@@@@@@@
       +-------.-<if($c == '¥n')  line++;@
                 @c++;                   @
                 @v@@@@@@@^@@@@@@@@@@@@@@@
                  +-[¥s]--+
%%
private static int c, word, line;

public static void main(String[] args) throws Exception {
	c = word = line = 0;
	parseAll(System.in);
	System.out.printf("%d¥t%d¥t%d¥t¥n", line, word, c - 1);
}

上記の例では、複数の状態を持っていることがわかります。 状態は、初期状態、単語の境界、空白文字に対応します。
辺にある[...]はかっこ内の文字セットに一致するとき状態遷移することを表します。
文字セット¥sは空白文字(スペース・タブ・改行)に一致します。Ninaでは以下の文字セットが使用可能です。
文字その一文字
文字1-文字2文字1から文字2までの範囲
¥n改行文字
¥r復帰文字
¥tタブ文字
¥s空白文字
¥S空白文字以外
¥w単語構成文字[A-Za-z0-9_]
¥W単語構成文字以外
¥dASCII数字
¥DASCII数字以外

コンパイルして実行してみましょう。

$ nina wc.nina
$ javac Wc.java
$ java Wc < Wc.java
532 1512 11440

チュートリアルTOP - NEXT: サブオートマトンの使用
Yuichiro Moriguchi
yuichiro-moriguchi@nifty.com
SourceForge.JP