2012年9月8日土曜日

Natural Tiny Basic (NT-Basic) ~WindowsでもLinuxでもMac OSでも組み込み機器でも楽しめるBASICインタプリタ~

まつもとゆきひろさんから得た刺激

先日のSWEST14でまつもとゆきひろさんの講演を聞いてからというものの、言語処理系にとても興味が湧いてきました。

何から手を付けて良いかわからなかったので、手始めに既存のBASICインタプリタに手を入れるところから始めました。
オーディオプラットフォームであるBlueTank BF592で動作させた時の様子が以下の動画です。

 

NT-Basicのアプリケーションコード

NT-Basicを使用するアプリケーションコードは至ってシンプルです。

ntbasic_ ntbasic;
ntbasic_execute(&ntbasic, your_program);

上記のようにntbasicハンドラとプログラム文字列をntbasic_execute関数に渡してあげるだけです。
先ほどの動画の動作は以下のコードから実現しています。

#include "ntbasic.h"
#include "uart.h"
#include "lcd.h"
#include "bfin_util.h"

int main(void)
{
  ntbasic_t ntbasic;
  char *prog1 =
    "100 FOR I = 1 TO 8\n" \
    "110 C = 65 + I - 1\n" \
    "120 WRITE 1, C\n" \
    "130 NEXT\n" \
    "140 END\n";
  char *prog2 =
    "100 FOR I = 1 TO 8\n" \
    "110 C = 97 + I - 1\n" \
    "120 WRITE 1, C\n" \
    "130 NEXT\n" \
    "140 END\n";

  uart_init();
  lcd_init();

  while (1) {
    /*
     * プログラム1を実行する。
     */
    lcd_goto(0, 0);
    ntbasic_execute(&ntbasic, prog1);
    bfin_util_usleep(1000000);

    /*
     * プログラム1で書いた表示を消去する。
     */
    lcd_clear();
    bfin_util_usleep(1000000);

    /*
     * プログラム2を実行する。
     */
    lcd_goto(0, 1);
    ntbasic_execute(&ntbasic, prog2);
    bfin_util_usleep(1000000);

    /*
     * プログラム2で書いた表示を消去する。
     */
    lcd_clear();
    bfin_util_usleep(1000000);
  }

  return 0;
}

今回のターゲットは組み込み装置でしたが、実際にLinuxやWindowsやMac OSでもビルドできるようにしました。

なので、「パソコン上でインタプリタ側のプログラムを動作確認」して「実機で動作」という流れでインタプリタを楽しむ事ができます。

「いつでもどこでもインタプリタ」がキーワードです。

組み込み装置で使うためのHAL構造

この手のソフトウェアで重要なのは構造です。
I/Oは最下層のHAL(Hardware Abstract Layer)が実行するようにしてあります。



インタプリタ上のプログラムは、ハードウェア抽象化層を介し、実際のデバイスを制御します。
ターゲット依存部は単に小さなハードウェア抽象化層に対する実装を加えるのみで済みます。

int hal_getc(void);
int hal_putc(int c);
int hal_read(const int port, int *data);
int hal_write(const int port, const int data);
int hal_halt(void);

hal_getc(void)とhal_putc(int c)は標準入出力系を担います。
ポート番号を指定してデータをI/Oするのが、hal_read(const int port, int *data)とhal_write(const int port, const int data)です。

先ほどお見せした動画は、このHALの層で「ポート番号1に対する出力はLCD」という実装を追加したわけです。

int hal_write(const int port, const int data)
{
  switch (port) {
    case 0:
      /*
       * Port 0 is UART in this port.
       */
      hal_putc(data);
      return 0;
    case 1:
      /*
       * Port 1 is LCD in this port.
       */
      lcd_putc((char)data);
      return 0;
  }
  return -1;
}

実際に動作させてみると結構楽しいおもちゃです。
「茶室で楽しむKOZOS拡張基板」のように何か一つ企画をやりたいなぁと考えています。

リソース

ソースコードは以下からダウンロードできます。

0 件のコメント:

コメントを投稿