超小型のBasicインタプリタをどこへでも

Natural Tiny Basic (NT-Basic)は、C言語で記述された超小型のBasicインタプリタです。 Windows、Mac OS、Linux、組み込みシステムと、様々な実行環境で動作可能です。 マイコンを使った小規模組み込みシステムでも使用できるように設計されており、プラットフォームに依存しない複数の小規模なモジュールから構成されています。 内部設計は階層化されており拡張や改造も容易な事から、言語設計の学習素材としても活用できます。


Video


特徴


構文

REM

REM命令を用いると、コメントを記述できます。

100 REM Complete example.

DIM

使用したい変数名は、あらかじめDIM命令で宣言してから使用します。

110 DIM X, Y, Z, I, J
120 X=2; Y=4; Z=8; I=0; J=0

PRINT

PRINT命令を使うと変数の中身の値の表示が可能です。 変数Xの値を表示したい場合、以下のように記述します。 hal.cの実装によって標準出力やLCDなど出力先が決まります。 ダブル・クオーテーションを使って文字列の表示も可能です。 もし、改行をしたくない場合には、終わりに;記号を追加して下さい。 また、文字列に続けて変数の中身の値の表示も可能です。 カンマに続けて変数名を記述します。

130 PRINT X, Y, Z
140 PRINT "This is a text string."
150 PRINT "(X, Y, Z)="; X, Y, Z

GOTO

GOTO命令を用いると、指定した行番号へ処理を移動します。

160 GOTO 180
170 PRINT "Control does not reach here."
180 PRINT "Our next control."

IF - THEN

IF - THEN命令を用いると、条件判断を交えながら命令を実行できます。

190 IF X < 5 THEN PRINT "X < 5"
200 IF Y < 5 THEN PRINT "Y < 5"
210 IF Z < 5 THEN PRINT "Z < 5"

FOR - NEXT

FOR- NEXT命令を用いると、繰り返し処理を実行できます。

220 FOR I = 1 TO 10
230 PRINT (X * I), (Y * I), (Z * I)
240 NEXT
250 FOR I = 1 TO 10
260 J = J + (X + Y + Z)
270 PRINT "J = J + (X + Y + Z) = "; J
280 NEXT
290 PRINT "J=";J

INPUT

INPUT命令を用いると、hal.cで定義された標準入力から値を入力できます。

300 PRINT "Enter a number for I:";
310 INPUT I
320 INPUT "Enter a number for J: ", J

GOSUB - RETURN

GOSUB - RETURN命令を用いると、サブルーチンの呼び出しとサブルーチンからの復帰を実行できます。

330 GOSUB 350
340 GOTO 370
350 PRINT "This is a sub routine."
360 RETURN

READ

READは、抽象化されたハードウェアから何らかの読み込み処理を必要とする場合にhal.cに実装を追加する事で機能します。

変数Xで定義されたポート番号から値を読み込み、変数Yに格納します。 ポート番号0から値を読み込み、変数Zに格納します。

370 READ 0, X
380 PRINT "X=", X
390 READ I, J
400 PRINT "J=", J

WRITE

WRITEは、抽象化されたハードウェアへ何らかの書き込み処理を必要とする場合にhal.cに実装を追加する事で機能します。

変数Xで定義されたポート番号へ、変数Yに格納されている値を書き込みます。 ポート番号0へ変数Zに格納されている値を書き込みます。

410 WRITE 0, X
420 WRITE I, J

END

END命令を使うとプログラムの終了を実行できます。

430 END

完全なサンプル・コード

構文解説で断片的に用いたコードを繋ぎ合わせた完全なサンプル・コードを以下に示します。

100 REM Complete example.
110 DIM X, Y, Z, I, J
120 X=2; Y=4; Z=8; I=0; J=0
130 PRINT X, Y, Z
140 PRINT "This is a text string."
150 PRINT "(X, Y, Z)="; X, Y, Z
160 GOTO 180
170 PRINT "Control does not reach here."
180 PRINT "Our next control."
190 IF X < 5 THEN PRINT "X < 5"
200 IF Y < 5 THEN PRINT "Y < 5"
210 IF Z < 5 THEN PRINT "Z < 5"
220 FOR I = 1 TO 10
230   PRINT (X * I), (Y * I), (Z * I)
240 NEXT
250 FOR I = 1 TO 10
260   J = J + (X + Y + Z)
270   PRINT "J = J + (X + Y + Z) = "; J
280 NEXT
290 PRINT "J=";J
300 PRINT "Enter a number for I:";
310 INPUT I
320 INPUT "Enter a number for J: ", J
330 GOSUB 350
340 GOTO 370
350 PRINT "This is a sub routine."
360 RETURN
370 READ 0, X
380 PRINT "X=", X
390 READ I, J
400 PRINT "J=", J
410 WRITE 0, X
420 WRITE I, J
430 END

使い方

Natural Tiny Basic (NT-Basic) は、様々な環境で動作します。 以下に二つの異なる環境で動作させる場合の例について示します。

コンピュータ環境で使用する例

コンピュータ環境であればlibcを使ってプログラムを読み込むようなアプリケーションを簡単に構成できるでしょう。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ntbasic.h"
#include "progedit.h"

static int load_program(progedit_t *p, const char *filename)
{
  char buf[BUFSIZ];
  int line = 0;
  FILE *fp = fopen(filename, "rb");
  if (fp == NULL) {
    return -1;
  }

  while (fgets(buf, sizeof(buf), fp) != NULL) {
    line++;
    if (progedit_insert(p, buf) != 0) {
      printf("Insert failed.\nline=%d:%s\n", line, buf);
    }
  }

  fclose(fp);
  return line;
}

static int print_program(progedit_t *p)
{
  char buf[BUFSIZ];
  int line = 0;
  while (progedit_fetch(p, line, buf, sizeof(buf)) == 0) {
    line++;
    printf("  %d: [%s]\n", line, buf);
  }
  return line;
}

int main(int argc, char *argv[])
{
  ntbasic_t ntbasic;
  ntbasic_error_t error;
  progedit_t prog;
  int line_files, line_progs;
  char errmsg[BUFSIZ];
  void *extobj = "This is a user external object for the test.";

  /*
   * Check the arguments.
   */
  if (argc != 2) {
    printf("usage: ntbasic \n");
    return 1;
  }

  /*
   * Load program from a file system.
   */
  progedit_init(&prog);
  line_files = load_program(&prog, argv[1]);
  if (line_files < 0) {
    printf("program read failed.\n");
    return 2;
  }

  printf("[Program list]\n");
  line_progs = print_program(&prog);
  printf("\n");
  printf("[Program information]\n");
  printf("  %d lines readed.\n", line_files);
  printf("  %d lines stored.\n", line_progs);
  printf("  %d bytes.\n", (int)strlen(PROGEDIT_PROGRAM(&prog)));
  printf("\n");

  /*
   * Setup and execute.
   */
  error = ntbasic_setup(&ntbasic, PROGEDIT_PROGRAM(&prog), extobj);
  while (error == NoError) {
    error = ntbasic_execute(&ntbasic);
  }

  /*
   * Check the termination code.
   */
  if (error != EndOfTheProgram) {
    ntbasic_get_error_message(&ntbasic, error, errmsg, sizeof(errmsg));
    printf("Error: %s\n", errmsg);
  }

  return (error == EndOfTheProgram) ? 0 : error;
}

組み込みシステム環境で使用する例

#include "ntbasic.h"

int main(void)
{
  ntbasic_t ntbasic;
  ntbasic_error_t error;
  char *program =
    "100 PRINT \"This is a test\"\n" \
    "110 END\n";
  void *extobj = (void *)0;

  error = ntbasic_setup(&ntbasic, program, extobj);
  while (error == NoError) {
    error = ntbasic_execute(&ntbasic);
  }

  while (1) {
  }
}

内部構造

Natural Tiny Basic (NT-Basic) は、システムの中で少なくとも3つの層で全体が構成される想定で作られています。

Natural Tiny Basic (NT-Basic) は、小規模組み込みシステムで動作させる事を前提に設計されています。 また、libcを含む外部ライブラリへの依存は一切なく、最小限の依存関係で成立するように意図されています。 シェル上でソースコードに対して「grep 'include <' *」を実行して頂ければわかりますが、外部ライブラリを参照するinclude文は、main.cとhal.cにしか含まれません。 そして、これらmain.cとhal.cは、単にコンピュータ環境上で動作を確認するために仮に実装されたもので、Natural Tiny Basic (NT-Basic)の本質的なものではありません。 main.cは、一般的なファイルシステムからプログラムを読み込む例として示したもので、小規模組み込みシステムでは別の形を取るかもしれません。 hal.cは、ハードウェア抽象化層です。対象システムに応じて実装を変更可能です。 progeditとtexteditは、サンプルにおけるプログラム格納領域を提供する機能を持ちますが、実際の組み込みでは不要でしょう。

階層別の機能

アプリケーション層

アプリケーション層は、組み込み対象システムに完全に依存する層です。 Natural Tiny Basic (NT-Basic)のデフォルトの実装は、コンピュータ環境で実行する事を前提にlibcを用いたファイル読み込み型のアプリケーションになっています。 組み込み形態に応じてデフォルトの実装を取り除いて所望のアプリケーションを構成して下さい。

モジュール名機能
mainコンピュータ環境で実行可能なサンプル・プログラム
progeditプログラム・エディタ・モジュール
texteditテキスト・エディタ・モジュール

NT-Basic層

NT-Basic層は、Natural Tiny Basic (NT-Basic)を構成する主要なモジュールが含まれる層です。

上位

NT-Basicの上位層は、アプリケーション層との界面を司る部分で、全てのインタフェースの源を提供します。 幾つかのモジュールで構成されていますが、基本的にntbasic.hをインクルードするだけで済むようになっています。

モジュール名機能
ntbasicNT-Basicのインターフェースモジュール

中位

NT-Basicの中位層は、NT-Basicが内部で使用するモジュール群で構成されています。 一部の定義はアプリケーション層でも使用しますが、必要な依存関係はntbasic.hから呼び出されて自動的に解決されます。

モジュール名機能
coreNT-Basicのコア・モジュール
statementNT-Basicの文法評価処理モジュール
expressionNT-Basicの数式評価処理モジュール
variableNT-Basicの変数管理処理モジュール

下位

NT-Basicの下位層は、NT-Basicがモジュール内部で使用するライブラリが含まれる層です。 組み込みで特に重要なのはhal.cで、この実装によってPRINT構文やINPUT構文がどこから入力を得るのかが決まります。

モジュール名機能
tinyrand乱数発生モジュール
ntlibc独自libcモジュール
halハードウェア層抽象化モジュール

ハードウェア層

Natural Tiny Basic (NT-Basic)の組み込みに際して、上記のアプリケーション層、NT-Basic層が階層毎に適切に分離されている設計において、特にハードウェア層に求められる事はありません。 ハードウェアとの界面はNT-Basicの下位層に含まれるhal.cによって分離定義されます。


よくある質問

ポーティングする場合、どこから始めれば良いですか?

hal.cの実装から始めて下さい。
組み込みシステムの場合には、progeditモジュール、texteditモジュールは不要かもしれません。

独自の命令を追加する事は可能ですか?

はい。
小規模なモジュールに分割設計されたNatural Tiny Basic (NT-Basic)では、既存の命令を参考にして独自の命令を簡単に追加できます。
追加したい独自の命令に一番近い既存構文を参考に命令を追加して下さい。

命令の基本定義はcore.hに存在し、statement.cで実際の構文制御を行ないます。
ntbasic.cに追加した命令に至る処理を追加して下さい。

独自のハードウェアを制御するような事は可能ですか?

はい。
READ命令、WRITE命令を使って可能です。
制御の詳細はhal.cに隠蔽されており、この実装詳細を変更して下さい。

100 PRINT "This program demonstrates HAL I/O."
110 DIM I, O, V
120 INPUT "INPUT  PORT=", I
130 INPUT "OUTPUT PORT=", O
140 READ I, V
150 PRINT "Input"
160 PRINT "Port"; I; "Value"; V
170 WRITE O, V
180 PRINT "Output"
190 PRINT "Port"; O; "Value"; V
200 END

変数は内部でどのように扱われますか?

変数は対象処理系におけるintで処理されます。
変数名は最大8文字で32個まで定義できます。
扱いたい変数の個数を増やしたり、許容する変数名の最大文字数を増やしたい場合には、variable.hにある定義を変更して下さい。

FORやGOSUBはネストできますか?

はい。
以下のサンプルもご覧下さい。

FORのネスト例

100 PRINT "This program demostrates nested FOR loops."
110 FOR X = 1 TO 5
120   FOR Y = 1 TO 10
130     PRINT X; Y; X*Y
140   NEXT
150 NEXT

GOSUBのネスト例

100 PRINT "This program demonstrates nested GOSUBs."
110 INPUT "enter a number: ", I
120 GOSUB 140
130 END
140 FOR T = 1 TO I
150   X = X + I
160   GOSUB 190
170 NEXT
180 RETURN
190 PRINT X;
200 RETURN

ダウンロード

リリース日バージョンリンクリリースノート
2014/11/30 Version 0.3.0 Version 0.3.0
  • NT-Basicの初期化時にextobjに渡したポインタをhal.c内部で受け取れるようにした。
2012/11/04 Version 0.2.0 Version 0.2.0
  • 負の値に対するバグを修正した。
  • 正符号を示す文字に対するバグを修正した。
  • サンプルコードを更新した。
  • ntlibcからハードウェア抽象化層を削除した。
  • extern "C"宣言をヘッダに追加した。
  • Mac OS X上でコンパイルエラーになる不具合を修正した。
2012/09/23 Version 0.1.1 Version 0.1.1
  • 文字列操作モジュールを更新した。
  • progeditモジュールを追加した。
  • texteditモジュールを追加した。
  • 文字列バッファ用の定義を追加した。
  • 行数カウンタのバグを修正した。
  • 変数名の長さに対する定義を追加した。
  • プロジェクトファイルを更新した。
2012/09/22 Version 0.1.0 Version 0.1.0
  • processモジュールをexpressionモジュールに名称変更した。
  • APIの仕様を一部変更した。
  • 未使用のPROGRAM_SIZE定義を削除した。
  • プロジェクトファイルを変更した。
  • WRITE命令のバグを修正した。
  • print_integerの実装を変更した。
  • 返値の仕様を変更した。
  • エラー処理の設計を変更した。
  • 変数モジュールを追加し、変数定義の柔軟性を向上させた。
  • 16ビットプロセッサ向けに初期化コードを変更した。
2012/09/08 Version 0.0.1 Version 0.0.1
  • 初版。

ライセンス

The license is MIT.
Please see also http://opensource.org/licenses/mit-license.php.
/**
 * ===============================================================
 * Natural Tiny Basic (NT-Basic) - A tiny BASIC interpreter
 * ===============================================================
 * Copyright (c) 2012-2014 Shinichiro Nakamura
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * ===============================================================
 */

Author

Shinichiro Nakamura (CuBeatSystems)
@shintamainjp
CuBeatSystems