トップ » 技術記事 » Flash/Flex で作る俺様言語(kmyacc編)(2) - kmyacc で BASICっぽい言語を作ってみよう

Flash/Flex で作る俺様言語(kmyacc編)(2) - kmyacc で BASICっぽい言語を作ってみよう

タグ: Flash Flex

前回から kmyacc を利用して簡単なプログラミング言語を作成しています。前回は、kmyaccに付属しているサンプルのコンパイルに加え、簡単な計算機を作り、変数機能を追加してみました。今回は、されにこれを拡張して、BASICっぽい言語を作ってみようと思います。

前回のおさらい

では、前回のおさらいをしてみます。前回、kmyacc を利用して、ActionScript で実行できる簡単な電卓を作ってみました。まず、kmyacc は、以下より入手できます。

前回作った簡易電卓に、簡単なインターフェイスをつけて、Flash上で実行結果を確認できるようにしてみます。

まずは、Calc.asy という簡易電卓の文法ファイルを作成します。以下は文法定義部分だけ抜粋したものです。以下の文法の規則は次の意味を持ちます。

  • 1行に1つずつ計算式を書くことができる
  • 変数の代入ができる
  • 「>」から行を始めると計算結果を表示する

とりあえず完成したものを以下のリンクより実行することができます。

簡易電卓
簡易電卓

以下が文法定義ファイルです。

start:  lines;
lines: /* empty */
    | lines line            { yylrec++; }
    ;
line: '>' expr '\n'         { Calc.output( $2 ); }
    | WORD '=' expr '\n'    { calc_vars[$1] = $3; }
    | '\n'                  { trace("(empty line ignored)"); }
    | error '\n'
    ;
expr: expr '+' expr { $$ = $1 + $3; }
    | expr '-' expr { $$ = $1 - $3; }
    | expr '*' expr { $$ = $1 * $3; }
    | expr '/' expr { $$ = $1 / $3; }
    | expr '%' expr { $$ = ($1) % ($3); }
    | '(' expr ')'  { $$ = $2; }
    | NUMBER { $$ = $1; }
    | WORD   { $$ = calc_vars[$1]; }
    ;

そして、これを、kmyacc で変換して、ActionScript のファイルにします。変換のコマンドは、次のように書くのでした。これにより、Calc.as というファイルが生成されます。

kmyacc Calc.asy

ここでは、まだ必要ないのですが、将来的に、どのように読み込まれているのかコンパイル経過の情報を表示させたい場合は、次のように -t オプションをつけてコンパイルします。また、さらに詳しい情報を出力させたい場合は -y オプションをつけます。そうすると、y.output というレポートファイルを作成するようになります。

kmyacc -ty Calc.asy

そして、Flexで簡単なインターフェイスを用意すれば完成です。MXMLのタグを以下のように書きました。(Calc.asy から生成した Calc.as は TextArea を継承させたので、計算結果を表示する独自コンポーネントになりました。)

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:calc="*"
	layout="absolute"
	creationComplete="a_txt.text='a=2\nb=8\n>a*b+4'">
	<mx:Panel title="TestCalc" width="100%" height="100%"

		paddingLeft="8" paddingRight="8" paddingBottom="8">
		<mx:Label text="計算式を記述。" width="100%"/>

		<mx:TextArea id="a_txt" width="100%" height="60%" />
		<mx:Button label="実行" click="calc.Run(a_txt.text)"/>

		<mx:Label text="実行結果"/>
		<calc:Calc id="calc" width="100%" height="40%" />

	</mx:Panel>
</mx:Application>

ここまでのプログラムをZIPファイルにまとめました。以下よりダウンロードできます。・http://aoikujira.com/demo/hakkaku/rc/2008030..

今回作るもの

それでは、ここで今回作るものを考えてみます。今回作りたいのは、BASICインタプリタです。変数が使えるだけでなく、IF や GOTO、FOR 文をサポートして、簡単な分岐や繰り返しができるようにしてみます。

これまでは、パーサジェネレーター(kmyacc)でパースする段階ですべての計算をしていましたが、制御構文をサポートする場合、パース段階で計算を実行してしまうと、正しい値が得られなくなります。もちろん定数同士の計算であれば、この段階で計算をしても問題ないのですが、変数の計算を実行してしまっては困ります。また、パースの段階で、繰り返し処理を行わせることはできません。

では、どうするのかと言うと、パースする段階で構文木を作ります。構文木というのは、プログラムの構造をツリー構造で表すものです。例えば、「A=2*3」というプログラムなら、以下のような形の構文木を作ります。


+ 代入処理
|- A に
|- + 掛ける(*)
   | - 2
   | - 3

また、足し算を行う関数の呼び出しを行うプログラム「A=Add(3,5+2)」なら以下のようになります。

+ 代入処理
| - Aに
| - + 関数呼び出し(Add)
    | - + 引数
        | - 3
        | + 足し算(+)
          | - 5
          | - 2

もともと、kmyacc などのパーサジェネレータは、こうした構文木を作るためのものです。これらの構文木を保持するために、ActionScript で次のような構造のクラスを定義すると良いでしょう。

package {
  public class YYNode {
    public var node_type:int;
    public var node_value:Object;
    public var next_node:YYNode;
    public var children:Array;//of YYNode
  }
}

そして、たとえば足し算を行わせる構文木を作るなら、文法定義ファイルへ次のように書き込みます。

expr : expr '+' expr
     {
         var n:YYNode = new YYNode();
         n.node_type = CALC_PLUS;
         n.children = [$1, $2];
         $$ = n;
     }
     | NUMBER
     {
         var n:YYNode = new YYNode();
         n.node_type = NUMBER;
         n.node_value = $1;
         $$ = n;
     }
     ;

ここまでできれば、構文木を1つずつたどってプログラムを実行できます。以下のプログラムは、構文木の各ノードを実行して、次のノードへと進んでいきます。こうして、次のノードが null のところ(つまり、最後)まで実行するのです。

その時に、足し算のノードでは、足す数と足される数が、子ノードして登録されているので、再帰的にノードを実行して、結果の値を得るようにします。

public function runNode(node:YYNode):void {
    var cur:YYNode = node;
    while (n != null) {
      switch (n.node_type) {
        case NUMBER:
          pushValue(n.node_value); break;
        case CALC_PLUS:
          runNode(n.children[0]);
          var a:Object = popValue();
          runNode(n.children[1]);
          var b:Object = popValue();
          pushValue(a + b);
          break;
        //...
      }
      n = n.next;
    }
}
TekitoBasicの制作

このようにして、構文木をパースしながら実行するのが、TekitoBasic です。以下のリンクをクリックすることで実行することができます。

TekitoBasicを実行しているところ
TekitoBasicを実行しているところ

これは、懐かしの N88BASIC に似せた文法になっています。簡単な計算を画面に表示するには、以下のように書きます。

10 print 1 + 2
20 print 2 + 3

IF 文を書く場合には、「IF 条件式 THEN 行番号 ELSE 行番号」のように記述します。


10 if 3 > 1 then 20 else 30
20 print "GT"
25 goto 40
30 print "LT"
35 goto 40
40 print "ok."
50 quit

この TekitoBasic の文法規則から、抜粋したものが以下です。

start   :  lines    { }
        ;
lines   : /* empty */
        | lines line
        ;
line    : LABEL programs EOL
        | LABEL ':' programs EOL
        | EOL
        | error EOL
        ;
programs    : program
            | programs ':' program
            ;
program : FUNCTION args
        | FUNCTION
        | if_block
        | goto_block
        | for_block
        | next_block
        | variable '=' expr
        ;

まとめ

今回は、前回作った簡易電卓にUIをつけたプログラムと、構文木を作成し実行する、TekitoBasic を作ってみました。いずれも、簡単な計算をして、画面に結果を表示するくらいしかできません。しかし、オリジナルのプログラミング言語の叩き台として参考にするのには、ちょうど良い大きさかなと思っています。

また、今回、kmyacc を使って言語を作ってみましたが、kmyacc は多言語に対応しており、その言語ごとに、雛型ファイルが用意されています。TekitoBasicを作る時には、可読性を確保するために、この雛型を書き換える必要があったのですが、これが非常に分かりやすく、実装しながら必要に応じて雛型の方も書き換えることができました。興味のある方は、kmyacc のソースコードの方も読んでみると勉強になると思います。

プログラミング言語の作成は、kmyacc などのパーサーを利用することで、それほど難しくなく短期間で制作することができます。今回作った TekitoBasic もほぼ1日の作業で作成することができました。プログラミングの練習も兼ねて、ぜひ、俺様言語の制作にチャレンジしてみてはどうでしょうか。

Series Navigation«kmyacc の ActionScript 版を使ってみよう

執筆者紹介

クジラ飛行机

クジラ飛行机

くじらはんど(http://kujirahand/)にて、日本語プログラミング言語「なでしこ」(IPA未踏ユース採択)、テキスト音楽「サクラ」(OSPオンラインソフト大賞入賞)など多くのオンラインソフトを開発。著書に「Flexプロフェッショナルガイド」「なでしこ公式バイブル」、「一週間でマスターするActionScript3.0」など。

TrackBack URL :