T A K E O K A B A S I C I n t e r p r i t e r 2014/JUN/13 0. はじめに 1970年代末期から1980年代前半に流行した「TinyBASIC」と同様な機能の処理 系です。 コンパクトな仕様で、組み込みマイコンに内蔵し、マイコン単独でそれなりの プログラム開発ができることを目指しています。 ステートメントやコマンドは、1980年代のメジャーな処理系に、ほぼ合わせて あります。 十六進数の取り扱いを強化しています。 入出力には、通常のシリアル端末を使用します。 本処理系は、通常の端末を使用するにもかかわらず、強力な行編集機能を提供 します。 1. 処理系の特徴など a) 整数のみ扱う 32bit を標準的な整数の大きさとしています。 文字は1文字を整数として扱い、処理を行います。 b) 四則演算のオーバフローを無視し、機械操作が行えるようにしています。 (C言語と同様) b) 配列変数の参照/操作を工夫して、機械語の間接アドレッシングと同様な操 作をわかりやすく実現しています。C 言語風のメモリ操作を可能にしてい ます。 間接メモリ参照の節で詳説。 c)変数名 変数名は先頭の英文字1文字のみ判別(引き続く英数字は無視) 変数名に英小文字,英大文字は別の変数となります。 つまり、a-z, A-Zが変数。 d) if条件式 の条件式の直後に THEN などの予約語は必要ありません。(記述 した場合はエラーになります) e) 省略形の使用が可能 PaloAlto TinyBasicと同様に、 B>> r. (これは、runの省略) など、コマンド、ステートメントの先頭から数文字+'.'という省略形を使用 できます。 f) 十六進数値プリント出力 マイコン開発に便利な16進数でのプリント出力を装備 式の値を、各形式で出力。 hex 式 ?? 式 64bit BASICでは、式の値を16進16桁で出力 32bit BASICでは、式の値を16進8桁で出力 ?$ 式 8bit; 式の値の下8bitを、16進2桁で出力 ?!=式 16bit; 式の値の下16bitを、16進4桁で出力 ?* 式 32bit; 式の値の下32bitを、16進8桁で出力 ?@ 式 64bit; 式の値の下64bitを、16進16桁で出力 g) "*"特殊形式 peek , poke 一般のBASICで、peek , poke で実現される機能を、 "*" を使用した特殊形式で記述します。 IOポート・アクセスに使用できるように、ここでのアクセスは、 CPU自体が持つ、単位アクセスになります。 したがって、アラインメントが合っていない場合の動作は、CPUに依存します。 アクセス時の Endian も、実行するCPUのものがそのまま反映されます。 peek は、式中の配列変数が現れる場所に、 *(式) として書けます。 peekの *{式) ,*[式) ,*$式) は、符号付きとして扱われ、負号が拡張されます。符号拡張が不要など、必要に応じて、0xFFなどと& を取ってください。 例: ? *($1234)+1 0x1234番地から、64bit(32bit版の場合は32bit) で値を読み込み、それに1を加え、プリント。 poke は、代入の "=" の左辺の、配列変数が現れる場所に、 *(式) として書けます。 例: *($1234)=$89 0x1234番地へ、64bit(32bit版の場合は32bit) で値 0x89 を書き込む。 *(式) : 64bitBASICでは64bit単位の、32bit版の場合は32bit単位のアクセス *{式) : 32bit単位のアクセス *[式) : 16bit単位のアクセス *$式) : 8bit単位のアクセス h) print print には、次のものを','で区切って複数書くことができます。 文字列(""で囲まれた), 式, #式 式は計算され、符号付き十進で表示されます。 #式 は、カラム指定です。#式 以降、数値表示が、#式で指定されただけの幅で表示で行われます。 #指定は、そのprint文が終了するとデフォールトに戻ります。 例) B>>print "abc",1+1,"def",2+2,#4,3+4,"ghi",5+6 abc 2def 4 7ghi 11 2. 配列 dim a(式) dim a{式) dim a[式) dim a$式) で、配列を宣言。領域を確保。 配列は、プログラムを編集、または、run すると、クリア、解放されます。 デバッグ時など、配列確保後に、配列をクリアせずに、コマンド入力状態 (プロンプト)から、実行を再開するには、goto を使用します。 (run を使用すると配列は解放されてしまう) 配列名にはA-Z, a-z が使用できます。 配列は一次元のみです。 a(式) で参照/代入 64bit BASICでは、64bit単位のアクセス 32bit BASICでは、32bit単位のアクセス a{式) で参照/代入 32bit単位のアクセス a[式) で参照/代入 16bit単位のアクセス a$式) で参照/代入 8bit単位のアクセス aをベースとし、「式」の値を、型に合わせたオフセットとして加える。 それをアドレスとして、参照/代入を行う。 ※ここでのアクセスは、CPUの単位アクセスになる。 したがって、アラインメントが合っていない場合の動作は、CPUに依存。 3. 行エディタの操作 本処理系では、一行入力の際に常に行エディタが使用できます。 一行入力においては、 ^F : 前進 ^B : 後退 ^A : 行頭へ移動 ^E : 行末へ移動 ^D : 抹消 ^H : 抹消 後退 ^K : 行末まで消去 ^U : 行抹消 という編集ができます。 4. 一時停止、ポーズ プログラム実行中、リスト表示中に ^C : 実行うちきり ^S : 一時停止 です。 5. プログラム編集機能 a) 行の入力、挿入 コマンドラインで、行頭に数字をつけて入力した行は、プログラムの入力と して、テキスト・バッファに記憶される。行頭の数字は行番号となる。 プログラムは行番号に応じてソートされる。 すでに存在していた行は上書きされる。 b) プログラムテキストの表示 コマンドラインで、 B>> list 行番号 と入力すると、行番号以降の行が次々とコンソールに表示される。 行番号の入力を省略すると、先頭から表示される。 (正確には、list 式 となっており、「式」には変数を含む任意の式が書ける。 式を評価した結果を行番号として、リスト表示処理を行う) Tips: listコマンドは、'.'と省略可能。 B>> . と入力すると、list コマンドと同様の結果が得られる。 c) 行編集 コマンドラインで、 B>> edit 行番号 とすると、所望の行が行編集バッファに表示され、それを行エディタで編集 できる。 d) コマンドとステートメント ステートメントは、コマンドラインでも使用できます。 コマンドは、コマンドラインでのみ使用でき、プログラム中には記述できま せん。(SyntaxErrorとなります) -------- 簡易 構文早見表 コマンド ::= list [式] run bye ステートメント ::= end goto 式 input 変数 if 式 [ステートメント...] gosub 式 return do while 式 for 変数=式1 to 式2 [step 式3] next [変数] print ? ?? 式 ?$ 式 crlf spc 式 hex 式 chr 式 rem ' dim 変数名(式) strcpy(配列変数,配列変数) strncpy(配列変数,配列変数,式) memcpy(配列変数,配列変数,式) ::= 式 "str" 定数 ::= 十進数 $十六進数 &h十六進数 '文字定数' 変数 ::= 英文字[英数字...] 英文字[英数字...](式) 英文字[英数字...]{式) 英文字[英数字...][式) 英文字[英数字...]$式) 関数 ::= - ! abs(式) rand(式) getkey(式) wswap(式) qswap(式) *(式) *{式) *[式) *$式) && &^ 二項演算子 ::= 式+式 加算 式-式 減算 式*式 乗算 式/式 除算(符号付き) 式%式 剰余演算子(符号付き) 式|式 OR演算子 式&式 AND演算子 式^式 XOR演算子 式<<式 左シフト 式>>式 右シフト 式=式 等号 式<>式 不等号 式<式 小なり (less than) 式<=式 小なりイコール (less equal) 式>式 大なり (greater than) 式>=式 大なりイコール (greater equal) ---- 文法説明 1) コマンド list [式] コンソールにプログラムリストを表示 式が指定された場合は、式の評価結果を行番号とし、その行番号以降のリスト を表示する。 run プログラムの実行を先頭から開始する。 bye 処理系を終了する。 setprog 式1 [,式2] 式1で示される番地にプログラムが存在するとして、 プログラムの先頭ポインタをセットする。 式2が 非0 の時、先頭ポインタからプログラムの末尾を探して末尾ポインタをセットする。 式2が省略された時、式2が 非0 と同様に、末尾を探して末尾ポインタをセットする。 末尾ポインタの値は、特殊変数"&&"で参照できる。 ※setdimtop も参照のこと 2)ステートメント dim 変数名(式) 配列を宣言し、領域を確保する。 配列変数名は、A-Z, a-z。 setdimtop 式 配列領域の先頭を、式で示される番地とする。 通常、配列領域は、自動的にプログラム末尾("&&"で指される)の 直後に取られる。 RAM(ヒープ)上にプログラムが存在している時は、 setdimtopは必要ない。 setprogで、ROM上のプログラムを指定したときは、 配列をRAM(ヒープ)上に確保しなければならないので、setdimtopが 必要になる。 run した直後に、配列領域は、"&&"で指される直後に設定される。 よって、ROM上のプログラムは、プログラム中の、 dim宣言の前に、setdimtopを行うべきである。 ※setprog も参照のこと memstat 宣言された配列の状態、次に配列が取られるアドレス、 ヒープの先頭("&^")、プログラムの末尾("&&")などを 表示する。 end プログラムの実行を終了し、コマンドラインに戻る。 goto 式 式で示された行へジャンプする。 input 変数 人間に行入力を行わせ、その行を式として評価する。その評価結果を変数へ代 入する。 人間の入力する式には、本処理系の式の要素が使用できる。(変数、関数など も使用可能) if 式 [ステートメント...] 式を評価し、その値が0でなければ、後続するステートメントの列を実行する。 式の値が0ならば、後続のステートメントを行末までスキップする。 gosub 式 式で示された行をサブルーチン・コールする。 return gosubで呼び出されたサブルーチンから戻る。 for 変数=式1 to 式2 [step 式3] 繰り返しの開始。 すべての式(式1〜3)を評価した後、変数に式1を代入する。 その後、対応する nextに出会ったところで、変数に式3の値を加える。式3が0 以上の時、変数の値が式2を越えていれば、繰り返しを終了する。式3が負の時、 変数の値が式2を下回っていれば、繰り返しを終了する。 本処理系のfor-nextはgotoで脱出する事ができない。 繰り返しの途中で脱出したい場合は、繰り返し変数に、終了条件を満たす値を 代入し、対応するnextへジャンプして行う。例を参照 next [変数] 繰り返しの終り。 ここで変数を指定した場合は、対応するforで指定した変数と、この変数が一 致しなければならない。 do while繰り返しの開始。whileと組み合わせて使用する。 while 式 式が0でなければ、対応するdoの直後へジャンプする。 本処理系のdo-whileはgotoで脱出する事ができない。 繰り返しの途中で脱出したい場合は、終了条件を満たすようにし、対応する whileへジャンプして行う。例を参照 print ? プリントアイテムを表示する。 crlf 改行する。 spc 式 スペースを式の値だけ表示する。 hex 式 ?? 式 式の値を十六進表示する。 chr 式 式の値をASCII文字コードとして、一文字表示する。 rem ' コメント。以降、行末までスキップする。 strcpy(配列変数1,配列変数2) 配列変数2の位置を先頭とするバイトから、 0でターミネートされた文字列があるものとして、 配列変数1の位置を先頭バイトとする領域へ、 配列変数1の配列の範囲を越えることはない。 文字列のすべてが対象配列の中に入らない場合、 途中でコピーは打ち切られる。 配列変数2 部には、文字列定数(例:"asd")も書ける。 例: strcpy( a$3), b(1)) b(1)の位置から始まる文字列を、a$3) の場所へコピーする。 aの配列の領域を越えることはない。 b(1)の位置は、 bの先頭 + sizeof(int)*1 である。 a$3)の位置は、 aの先頭 + sizeof(char)*3 である。 strncpy(配列変数1,配列変数2,式) 配列変数2の位置を先頭とするバイトから、 0でターミネートされた文字列があるものとして、 配列変数1の位置を先頭バイトとする領域へ、 式で示されたバイト数だけコピーする。 配列変数1の配列の範囲を越えることはない。 文字列のすべてが対象配列の中に入らない場合、 途中でコピーは打ち切られる。 配列変数2 部には、文字列定数(例:"asd")も書ける。 ※注意: C言語のstrncpy()とは異なり、文字列が式より短いときに、 文字列の後ろを 0 で埋めることはしない。 例: strncpy( a$3), b(1), 10) memcpy(配列変数1,配列変数2,式) 配列変数2の位置を先頭とするバイトから、 配列変数1の位置を先頭バイトとする領域へ、 式で示されたバイト数だけコピーする。 配列変数1の配列の範囲を越えることはない。 バイト列のすべてが対象配列の中に入らない場合、 途中でコピーは打ち切られる。 例: memcpy( a$3), b(1), 10) strncat(配列変数1,配列変数2,式) 配列変数1の位置を先頭バイトとする領域にすでに置かれている文字列に連結して、 配列変数2の位置を先頭とするバイトから、 0でターミネートされた文字列があるものとして、 式で示されたバイト数だけコピーする。 配列変数1の配列の範囲を越えることはない。 文字列のすべてが対象配列の中に入らない場合、 途中でコピーは打ち切られる。その場合でも、文字列の末尾には必ず 0 が付く 配列変数2 部には、文字列定数(例:"asd")も書ける。 例: strncat( a$3), b(1), 10) -- thread 対応 -- ps プロセスの一覧を表示する。 wait 全スレッドの終了を待つ(のか???) messwait 式1,式2 式1の値で示される番号のオブジェクトのメッセージを待つ。 すでに、そのメッセージを待っているプロセスがあった場合は、待たずに抜ける。 0番のオブジェクトは、キーボード入力。 式2は、待ちのタイムアウトの期間(現在からの相対時間)を指定。タイムアウトになると、待ちから抜ける。 sleep 式 式の値で示される時刻だけ、スレッドの実行を停止する。 3) 関数 - 式の値に -1 を掛ける。 ‾ 式の値の各bitを反転する。 ! 式の値が0なら1に、0以外なら0とする。 abs(式) 式の値の絶対値を返す。 rand(式) 乱数。 発生した乱数を式で除算した値を返す。式の値は0であってはならない。 C ライブラリの rand()の呼びだしとなる getkey(式) 一文字入力。 人間にキーボードより、一文字入力させ、入力された文字のASCIIコードを返す。 式はダミーだが、文法エラーがあってはならない。 wswap(式) 式の値の下位2バイトのバイトオーダを入れ替えた値を返す。 $1234 は、$3412が返る。 qswap(式) 式の値の4バイトのバイト・オーダを入れ替えた値を返す。 $12345678 は、$78563412が返る。 && 特殊な変数。(無引数の関数) プログラムテキストの最終番地を返す。 &^ 特殊な変数。(無引数の関数) ヒープエリア(RAM)の先頭番地を返す。 -- thread 対応 -- fork(式) 式を開始行番号として、threadを生成する。 スレッドのプロセス番号を返す。 messnew(式) 式はダミーだが、文法エラーがあってはならない。 メッセージ・オブジェクトを獲得。オブジェクト番号を返す。 0番のオブジェクトは、キーボード入力。 0番のオブジェクトは、システム起動時に自動的に生成されているので、ユーザが獲得する必要がない。 messread(式) 式の値で示される番号のメッセージ・オブジェクトから、読み出す。 messsend(式1,式2) 式1の値で示される番号のオブジェクトへ、式2の値をメッセージとして送る。 そのメッセージ・オブジェクトを待っているプロセスがあれば、プロセスは走行可能になる。 lastwait(式) 式の値で示される番号のオブジェクトの最新の待ちが外された要因を返す。 1 O_RES_RECV メッセージを受信した -2 O_RES_TO タイムアウト -3 O_RES_WAITING 現在も待ちプロセスがある(待ちは外れていない) -1 Error オブジェクトは未使用 vecmul(式v1,式v2,式v3,式n) 式v1を先頭番地とするベクトル(一次元配列)と 式v2を先頭番地とするベクトル(一次元配列)の 各要素を乗算し、 式v3を先頭番地とするベクトルに格納する。 要素数は、式n で指定。 vecadd(式v1,式v2,式v3,式n) 式v1を先頭番地とするベクトル(一次元配列)と 式v2を先頭番地とするベクトル(一次元配列)の 各要素を加算し、 式v3を先頭番地とするベクトルに格納する。 要素数は、式n で指定。 vecsum(式v1,式n) 式v1を先頭番地とするベクトル(一次元配列)の 全要素を加算し、返す。 要素数は、式n で指定。 ompthread 式 omp_set_num_threads(式)を実行し、 OpenMPのthread数を指定する。 4) 二項演算子 式+式 加算 式-式 減算 式*式 乗算 式/式 除算(符号付き) 式%式 剰余演算子(符号付き) 負数の剰余は機械依存。 式|式 OR演算子 式&式 AND演算子 式^式 XOR演算子 式<<式 左シフト 式>>式 右シフト 式=式 等号 式<>式 不等号 式<式 小なり (less than) 式<=式 小なりイコール (less equal) 式>式 大なり (greater than) 式>=式 大なりイコール (greater equal) --- このドキュメントはここまでです todo, bug - idol_proc は普段は、readyQに入れない - あるプロセスが終了すると、別のある一つのプロセスが、他の倍、動く - timeout - sleep --- ToDo --- 2014/JUN/13 ・pop or drop, (Call, For, Do) ・set rand seed ・スタック ネスト チェック 式eval, for,gosub ネスト数 ・DIM全体の限界チェック ---- EOF