├── README.md
└── ttbasic
├── basic.cpp
└── ttbasic.ino
/README.md:
--------------------------------------------------------------------------------
1 | TOYOSHIKI Tiny BASIC for Arduino
The code tested in Arduino Uno R3.
Use UART terminal, or temporarily use Arduino IDE serial monitor.
Operation example
> list
10 FOR I=2 TO -2 STEP -1; GOSUB 100; NEXT I
20 STOP
100 REM Subroutine
110 PRINT ABS(I); RETURN
OK
>run
2
1
0
1
2
OK
>
The grammar is the same as
PALO ALTO TinyBASIC by Li-Chen Wang
Except 3 point to show below.
(1)The contracted form of the description is invalid.
(2)Force abort key
PALO ALTO TinyBASIC -> [Ctrl]+[C]
TOYOSHIKI TinyBASIC -> [ESC]
NOTE: Probably, there is no input means in serial monitor.
(3)Other some beyond my expectations.
(C)2012 Tetsuya Suzuki
GNU General Public License
--------------------------------------------------------------------------------
/ttbasic/basic.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | TOYOSHIKI Tiny BASIC for Arduino
3 | (C)2012 Tetsuya Suzuki
4 | GNU General Public License
5 | */
6 |
7 | #include
8 | #include
9 |
10 | // TOYOSHIKI TinyBASIC symbols
11 | // TO-DO Rewrite defined values to fit your machine as needed
12 | #define SIZE_LINE 80 //Command line buffer length + NULL
13 | #define SIZE_IBUF 80 //i-code conversion buffer size
14 | #define SIZE_LIST 256 //List buffer size
15 | #define SIZE_ARRY 32 //Array area size
16 | #define SIZE_GSTK 6 //GOSUB stack size(2/nest)
17 | #define SIZE_LSTK 15 //FOR stack size(5/nest)
18 |
19 | // Depending on device functions
20 | // TO-DO Rewrite these functions to fit your machine
21 | #define STR_EDITION "ARDUINO"
22 |
23 | // Terminal control
24 | #define c_putch(c) Serial.write(c)
25 | #define c_getch( ) Serial.read()
26 | #define c_kbhit( ) Serial.available()
27 |
28 | #define KEY_ENTER 13
29 | void newline(void) {
30 | c_putch(13); //CR
31 | c_putch(10); //LF
32 | }
33 |
34 | // Return random number
35 | short getrnd(short value) {
36 | return random(value) + 1;
37 | }
38 |
39 | // Prototypes (necessity minimum)
40 | short iexp(void);
41 |
42 | // Keyword table
43 | const char *kwtbl[] = {
44 | "GOTO", "GOSUB", "RETURN",
45 | "FOR", "TO", "STEP", "NEXT",
46 | "IF", "REM", "STOP",
47 | "INPUT", "PRINT", "LET",
48 | ",", ";",
49 | "-", "+", "*", "/", "(", ")",
50 | ">=", "#", ">", "=", "<=", "<",
51 | "@", "RND", "ABS", "SIZE",
52 | "LIST", "RUN", "NEW"
53 | };
54 |
55 | // Keyword count
56 | #define SIZE_KWTBL (sizeof(kwtbl) / sizeof(const char*))
57 |
58 | // i-code(Intermediate code) assignment
59 | enum {
60 | I_GOTO, I_GOSUB, I_RETURN,
61 | I_FOR, I_TO, I_STEP, I_NEXT,
62 | I_IF, I_REM, I_STOP,
63 | I_INPUT, I_PRINT, I_LET,
64 | I_COMMA, I_SEMI,
65 | I_MINUS, I_PLUS, I_MUL, I_DIV, I_OPEN, I_CLOSE,
66 | I_GTE, I_SHARP, I_GT, I_EQ, I_LTE, I_LT,
67 | I_ARRAY, I_RND, I_ABS, I_SIZE,
68 | I_LIST, I_RUN, I_NEW,
69 | I_NUM, I_VAR, I_STR,
70 | I_EOL
71 | };
72 |
73 | // List formatting condition
74 | // 後ろに空白を入れない中間コード
75 | const unsigned char i_nsa[] = {
76 | I_RETURN, I_STOP, I_COMMA,
77 | I_MINUS, I_PLUS, I_MUL, I_DIV, I_OPEN, I_CLOSE,
78 | I_GTE, I_SHARP, I_GT, I_EQ, I_LTE, I_LT,
79 | I_ARRAY, I_RND, I_ABS, I_SIZE
80 | };
81 |
82 | // 前が定数か変数のとき前の空白をなくす中間コード
83 | const unsigned char i_nsb[] = {
84 | I_MINUS, I_PLUS, I_MUL, I_DIV, I_OPEN, I_CLOSE,
85 | I_GTE, I_SHARP, I_GT, I_EQ, I_LTE, I_LT,
86 | I_COMMA, I_SEMI, I_EOL
87 | };
88 |
89 | // exception search function
90 | char sstyle(unsigned char code,
91 | const unsigned char *table, unsigned char count) {
92 | while(count--) //中間コードの数だけ繰り返す
93 | if (code == table[count]) //もし該当の中間コードがあったら
94 | return 1; //1を持ち帰る
95 | return 0; //(なければ)0を持ち帰る
96 | }
97 |
98 | // exception search macro
99 | #define nospacea(c) sstyle(c, i_nsa, sizeof(i_nsa))
100 | #define nospaceb(c) sstyle(c, i_nsb, sizeof(i_nsb))
101 |
102 | // Error messages
103 | unsigned char err;// Error message index
104 | const char* errmsg[] = {
105 | "OK",
106 | "Devision by zero",
107 | "Overflow",
108 | "Subscript out of range",
109 | "Icode buffer full",
110 | "List full",
111 | "GOSUB too many nested",
112 | "RETURN stack underflow",
113 | "FOR too many nested",
114 | "NEXT without FOR",
115 | "NEXT without counter",
116 | "NEXT mismatch FOR",
117 | "FOR without variable",
118 | "FOR without TO",
119 | "LET without variable",
120 | "IF without condition",
121 | "Undefined line number",
122 | "\'(\' or \')\' expected",
123 | "\'=\' expected",
124 | "Illegal command",
125 | "Syntax error",
126 | "Internal error",
127 | "Abort by [ESC]"
128 | };
129 |
130 | // Error code assignment
131 | enum {
132 | ERR_OK,
133 | ERR_DIVBY0,
134 | ERR_VOF,
135 | ERR_SOR,
136 | ERR_IBUFOF, ERR_LBUFOF,
137 | ERR_GSTKOF, ERR_GSTKUF,
138 | ERR_LSTKOF, ERR_LSTKUF,
139 | ERR_NEXTWOV, ERR_NEXTUM, ERR_FORWOV, ERR_FORWOTO,
140 | ERR_LETWOV, ERR_IFWOC,
141 | ERR_ULN,
142 | ERR_PAREN, ERR_VWOEQ,
143 | ERR_COM,
144 | ERR_SYNTAX,
145 | ERR_SYS,
146 | ERR_ESC
147 | };
148 |
149 | // RAM mapping
150 | char lbuf[SIZE_LINE]; //Command line buffer
151 | unsigned char ibuf[SIZE_IBUF]; //i-code conversion buffer
152 | short var[26]; //Variable area
153 | short arr[SIZE_ARRY]; //Array area
154 | unsigned char listbuf[SIZE_LIST]; //List area
155 | unsigned char* clp; //Pointer current line
156 | unsigned char* cip; //Pointer current Intermediate code
157 | unsigned char* gstk[SIZE_GSTK]; //GOSUB stack
158 | unsigned char gstki; //GOSUB stack index
159 | unsigned char* lstk[SIZE_LSTK]; //FOR stack
160 | unsigned char lstki; //FOR stack index
161 |
162 | // Standard C libraly (about) same functions
163 | char c_toupper(char c) {
164 | return(c <= 'z' && c >= 'a' ? c - 32 : c);
165 | }
166 | char c_isprint(char c) {
167 | return(c >= 32 && c <= 126);
168 | }
169 | char c_isspace(char c) {
170 | return(c == ' ' || (c <= 13 && c >= 9));
171 | }
172 | char c_isdigit(char c) {
173 | return(c <= '9' && c >= '0');
174 | }
175 | char c_isalpha(char c) {
176 | return ((c <= 'z' && c >= 'a') || (c <= 'Z' && c >= 'A'));
177 | }
178 |
179 | void c_puts(const char *s) {
180 | while (*s) c_putch(*s++); //終端でなければ出力して繰り返す
181 | }
182 |
183 | void c_gets() {
184 | char c; //文字
185 | unsigned char len; //文字数
186 |
187 | len = 0; //文字数をクリア
188 | while ((c = c_getch()) != KEY_ENTER) { //改行でなければ繰り返す
189 | if (c == 9) c = ' '; //[Tab]キーは空白に置き換える
190 | //[BackSpace]キーが押された場合の処理(行頭ではないこと)
191 | if (((c == 8) || (c == 127)) && (len > 0)) {
192 | len--; //文字数を1減らす
193 | c_putch(8); c_putch(' '); c_putch(8); //文字を消す
194 | } else
195 | //表示可能な文字が入力された場合の処理(バッファのサイズを超えないこと)
196 | if (c_isprint(c) && (len < (SIZE_LINE - 1))) {
197 | lbuf[len++] = c; //バッファへ入れて文字数を1増やす
198 | c_putch(c); //表示
199 | }
200 | }
201 | newline(); //改行
202 | lbuf[len] = 0; //終端を置く
203 |
204 | if (len > 0) { //もしバッファが空でなければ
205 | while (c_isspace(lbuf[--len])); //末尾の空白を戻る
206 | lbuf[++len] = 0; //終端を置く
207 | }
208 | }
209 |
210 | // Print numeric specified columns
211 | void putnum(short value, short d) {
212 | unsigned char dig; //桁位置
213 | unsigned char sign; //負号の有無(値を絶対値に変換した印)
214 |
215 | if (value < 0) { //もし値が0未満なら
216 | sign = 1; //負号あり
217 | value = -value; //値を絶対値に変換
218 | } else {
219 | sign = 0; //負号なし
220 | }
221 |
222 | lbuf[6] = 0; //終端を置く
223 | dig = 6; //桁位置の初期値を末尾に設定
224 | do { //次の処理をやってみる
225 | lbuf[--dig] = (value % 10) + '0'; //1の位を文字に変換して保存
226 | value /= 10; //1桁落とす
227 | } while (value > 0); //値が0でなければ繰り返す
228 |
229 | if (sign) //もし負号ありなら
230 | lbuf[--dig] = '-'; //負号を保存
231 |
232 | while (6 - dig < d) { //指定の桁数を下回っていれば繰り返す
233 | c_putch(' '); //桁の不足を空白で埋める
234 | d--; //指定の桁数を1減らす
235 | }
236 | c_puts(&lbuf[dig]); //桁位置からバッファの文字列を表示
237 | }
238 |
239 | // Input numeric and return value
240 | // Called by only INPUT statement
241 | short getnum() {
242 | short value, tmp; //値と計算過程の値
243 | char c; //文字
244 | unsigned char len; //文字数
245 | unsigned char sign; //負号
246 |
247 | len = 0; //文字数をクリア
248 | while ((c = c_getch()) != KEY_ENTER) { //改行でなければ繰り返す
249 | //[BackSpace]キーが押された場合の処理(行頭ではないこと)
250 | if (((c == 8) || (c == 127)) && (len > 0)) {
251 | len--; //文字数を1減らす
252 | c_putch(8); c_putch(' '); c_putch(8); //文字を消す
253 | } else
254 | //行頭の符号および数字が入力された場合の処理(符号込みで6桁を超えないこと)
255 | if ((len == 0 && (c == '+' || c == '-')) ||
256 | (len < 6 && c_isdigit(c))) {
257 | lbuf[len++] = c; //バッファへ入れて文字数を1増やす
258 | c_putch(c); //表示
259 | }
260 | }
261 | newline(); //改行
262 | lbuf[len] = 0; //終端を置く
263 |
264 | switch (lbuf[0]) { //先頭の文字で分岐
265 | case '-': //「-」の場合
266 | sign = 1; //負の値
267 | len = 1; //数字列はlbuf[1]以降
268 | break;
269 | case '+': //「+」の場合
270 | sign = 0; //正の値
271 | len = 1; //数字列はlbuf[1]以降
272 | break;
273 | default: //どれにも該当しない場合
274 | sign = 0; //正の値
275 | len = 0; //数字列はlbuf[0]以降
276 | break;
277 | }
278 |
279 | value = 0; //値をクリア
280 | tmp = 0; //計算過程の値をクリア
281 | while (lbuf[len]) { //終端でなければ繰り返す
282 | tmp = 10 * value + lbuf[len++] - '0'; //数字を値に変換
283 | if (value > tmp) { //もし計算過程の値が前回より小さければ
284 | err = ERR_VOF; //オーバーフローを記録
285 | }
286 | value = tmp; //計算過程の値を記録
287 | }
288 |
289 | if (sign) //もし負の値なら
290 | return -value; //負の値に変換して持ち帰る
291 |
292 | return value; //値を持ち帰る
293 | }
294 |
295 | // Convert token to i-code
296 | // Return byte length or 0
297 | unsigned char toktoi() {
298 | unsigned char i; //ループカウンタ(一部の処理で中間コードに相当)
299 | unsigned char len = 0; //中間コードの並びの長さ
300 | char* pkw = 0; //ひとつのキーワードの内部を指すポインタ
301 | char* ptok; //ひとつの単語の内部を指すポインタ
302 | char* s = lbuf; //文字列バッファの内部を指すポインタ
303 | char c; //文字列の括りに使われている文字(「"」または「'」)
304 | short value; //定数
305 | short tmp; //変換過程の定数
306 |
307 | while (*s) { //文字列1行分の終端まで繰り返す
308 | while (c_isspace(*s)) s++; //空白を読み飛ばす
309 |
310 | //キーワードテーブルで変換を試みる
311 | for (i = 0; i < SIZE_KWTBL; i++) { //全部のキーワードを試す
312 | pkw = (char *)kwtbl[i]; //キーワードの先頭を指す
313 | ptok = s; //単語の先頭を指す
314 |
315 | //キーワードと単語の比較
316 | while ( //次の条件が成立する限り繰り返す
317 | (*pkw != 0) && //キーワードの末尾に達していなくて
318 | (*pkw == c_toupper(*ptok))) { //文字が一致している
319 | pkw++; //キーワードの次の文字へ進む
320 | ptok++; //単語の次の文字へ進む
321 | }
322 |
323 | //キーワードと単語が一致した場合の処理
324 | if (*pkw == 0) { //もしキーワードの末尾に達していたら(変換成功)
325 | if (len >= SIZE_IBUF - 1) { //もし中間コードが長すぎたら
326 | err = ERR_IBUFOF; //エラー番号をセット
327 | return 0; //0を持ち帰る
328 | }
329 |
330 | ibuf[len++] = i; //中間コードを記録
331 | s = ptok; //文字列の処理ずみの部分を詰める
332 | break; //単語→中間コード1個分の変換を完了
333 | } //キーワードと単語が一致した場合の処理の末尾
334 |
335 | } //キーワードテーブルで変換を試みるの末尾
336 |
337 | //コメントへの変換を試みる
338 | if(i == I_REM) { //もし中間コードがI_REMなら
339 | while (c_isspace(*s)) s++; //空白を読み飛ばす
340 | ptok = s; //コメントの先頭を指す
341 |
342 | for (i = 0; *ptok++; i++); //コメントの文字数を得る
343 | if (len >= SIZE_IBUF - 2 - i) { //もし中間コードが長すぎたら
344 | err = ERR_IBUFOF; //エラー番号をセット
345 | return 0; //0を持ち帰る
346 | }
347 |
348 | ibuf[len++] = i; //コメントの文字数を記録
349 | while (i--) { //コメントの文字数だけ繰り返す
350 | ibuf[len++] = *s++; //コメントを記録
351 | }
352 | break; //文字列の処理を打ち切る(終端の処理へ進む)
353 | }
354 |
355 | if (*pkw == 0) //もしすでにキーワードで変換に成功していたら
356 | continue; //繰り返しの先頭へ戻って次の単語を変換する
357 |
358 | ptok = s; //単語の先頭を指す
359 |
360 | //定数への変換を試みる
361 | if (c_isdigit(*ptok)) { //もし文字が数字なら
362 | value = 0; //定数をクリア
363 | tmp = 0; //変換過程の定数をクリア
364 | do { //次の処理をやってみる
365 | tmp = 10 * value + *ptok++ - '0'; //数字を値に変換
366 | if (value > tmp) { //もし前回の値より小さければ
367 | err = ERR_VOF; //エラー番号をセット
368 | return 0; //0を持ち帰る
369 | }
370 | value = tmp; //0を持ち帰る
371 | } while (c_isdigit(*ptok)); //文字が数字である限り繰り返す
372 |
373 | if (len >= SIZE_IBUF - 3) { //もし中間コードが長すぎたら
374 | err = ERR_IBUFOF; //エラー番号をセット
375 | return 0; //0を持ち帰る
376 | }
377 | s = ptok; //文字列の処理ずみの部分を詰める
378 | ibuf[len++] = I_NUM; //中間コードを記録
379 | ibuf[len++] = value & 255; //定数の下位バイトを記録
380 | ibuf[len++] = value >> 8; //定数の上位バイトを記録
381 | }
382 | else
383 |
384 | //文字列への変換を試みる
385 | if (*s == '\"' || *s == '\'') { //もし文字が「"」か「'」なら
386 | c = *s++; //「"」か「'」を記憶して次の文字へ進む
387 | ptok = s; //文字列の先頭を指す
388 | //文字列の文字数を得る
389 | for (i = 0; (*ptok != c) && c_isprint(*ptok); i++)
390 | ptok++;
391 | if (len >= SIZE_IBUF - 1 - i) { //もし中間コードが長すぎたら
392 | err = ERR_IBUFOF; //エラー番号をセット
393 | return 0; //0を持ち帰る
394 | }
395 | ibuf[len++] = I_STR; //中間コードを記録
396 | ibuf[len++] = i; //文字列の文字数を記録
397 | while (i--) { //文字列の文字数だけ繰り返す
398 | ibuf[len++] = *s++; //文字列を記録
399 | }
400 | if (*s == c) s++; //もし文字が「"」か「'」なら次の文字へ進む
401 | }
402 | else
403 |
404 | //変数への変換を試みる
405 | if (c_isalpha(*ptok)) { //もし文字がアルファベットなら
406 | if (len >= SIZE_IBUF - 2) { //もし中間コードが長すぎたら
407 | err = ERR_IBUFOF; //エラー番号をセット
408 | return 0; //0を持ち帰る
409 | }
410 | //もし変数が3個並んだら
411 | if (len >= 4 && ibuf[len - 2] == I_VAR && ibuf[len - 4] == I_VAR) {
412 | err = ERR_SYNTAX; //エラー番号をセット
413 | return 0; //0を持ち帰る
414 | }
415 |
416 | ibuf[len++] = I_VAR; //中間コードを記録
417 | ibuf[len++] = c_toupper(*ptok) - 'A'; //変数番号を記録
418 | s++; //次の文字へ進む
419 | }
420 | else
421 |
422 | //どれにも当てはまらなかった場合
423 | {
424 | err = ERR_SYNTAX; //エラー番号をセット
425 | return 0; //0を持ち帰る
426 | }
427 | } //文字列1行分の終端まで繰り返すの末尾
428 |
429 | ibuf[len++] = I_EOL; //文字列1行分の終端を記録
430 | return len; //中間コードの長さを持ち帰る
431 | }
432 |
433 | // Return free memory size
434 | short getsize() {
435 | unsigned char* lp; //ポインタ
436 |
437 | for (lp = listbuf; *lp; lp += *lp); //ポインタをリストの末尾へ移動
438 | return listbuf + SIZE_LIST - lp - 1; //残りを計算して持ち帰る
439 | }
440 |
441 | // Get line numbere by line pointer
442 | short getlineno(unsigned char *lp) {
443 | if(*lp == 0) //もし末尾だったら
444 | return 32767; //行番号の最大値を持ち帰る
445 | return *(lp + 1) | *(lp + 2) << 8; //行番号を持ち帰る
446 | }
447 |
448 | // Search line by line number
449 | unsigned char* getlp(short lineno) {
450 | unsigned char *lp; //ポインタ
451 |
452 | for (lp = listbuf; *lp; lp += *lp) //先頭から末尾まで繰り返す
453 | if (getlineno(lp) >= lineno) //もし指定の行番号以上なら
454 | break; //繰り返しを打ち切る
455 |
456 | return lp; //ポインタを持ち帰る
457 | }
458 |
459 | // Insert i-code to the list
460 | void inslist() {
461 | unsigned char *insp; //挿入位置
462 | unsigned char *p1, *p2; //移動先と移動元
463 | short len; //移動の長さ
464 |
465 | if (getsize() < *ibuf) { //もし空きが不足していたら
466 | err = ERR_LBUFOF; //エラー番号をセット
467 | return; //処理を打ち切る
468 | }
469 |
470 | insp = getlp(getlineno(ibuf)); //挿入位置を取得
471 |
472 | //同じ行番号の行が存在したらとりあえず削除
473 | if (getlineno(insp) == getlineno(ibuf)) { //もし行番号が一致したら
474 | p1 = insp; //p1を挿入位置に設定
475 | p2 = p1 + *p1; //p2を次の行に設定
476 | while ((len = *p2) != 0) { //次の行の長さが0でなければ繰り返す
477 | while (len--) //次の行の長さだけ繰り返す
478 | *p1++ = *p2++; //前へ詰める
479 | }
480 | *p1 = 0; //リストの末尾に0を置く
481 | }
482 |
483 | //行番号だけが入力された場合はここで終わる
484 | if (*ibuf == 4) //もし長さが4(行番号のみ)なら
485 | return; //終了する
486 |
487 | //挿入のためのスペースを空ける
488 | for (p1 = insp; *p1; p1 += *p1); //p1をリストの末尾へ移動
489 | len = p1 - insp + 1; //移動する幅を計算
490 | p2 = p1 + *ibuf; //p2を末尾より1行の長さだけ後ろに設定
491 | while (len--) //移動する幅だけ繰り返す
492 | *p2-- = *p1--; //後ろへズラす
493 |
494 | //行を転送する
495 | len = *ibuf; //中間コードの長さを設定
496 | p1 = insp; //転送先を設定
497 | p2 = ibuf; //転送元を設定
498 | while (len--) //中間コードの長さだけ繰り返す
499 | *p1++ = *p2++; //転送
500 | }
501 |
502 | //Listing 1 line of i-code
503 | void putlist(unsigned char* ip) {
504 | unsigned char i; //ループカウンタ
505 |
506 | while (*ip != I_EOL) { //行末でなければ繰り返す
507 |
508 | //キーワードの処理
509 | if (*ip < SIZE_KWTBL) { //もしキーワードなら
510 | c_puts(kwtbl[*ip]); //キーワードテーブルの文字列を表示
511 | if (!nospacea(*ip)) //もし例外にあたらなければ
512 | c_putch(' '); //空白を表示
513 |
514 | if (*ip == I_REM) { //もし中間コードがI_REMなら
515 | ip++; //ポインタを文字数へ進める
516 | i = *ip++; //文字数を取得してポインタをコメントへ進める
517 | while (i--) //文字数だけ繰り返す
518 | c_putch(*ip++); //ポインタを進めながら文字を表示
519 | return; //終了する
520 | }
521 |
522 | ip++;//ポインタを次の中間コードへ進める
523 | }
524 | else
525 |
526 | //定数の処理
527 | if (*ip == I_NUM) { //もし定数なら
528 | ip++; //ポインタを値へ進める
529 | putnum(*ip | *(ip + 1) << 8, 0); //値を取得して表示
530 | ip += 2; //ポインタを次の中間コードへ進める
531 | if (!nospaceb(*ip)) //もし例外にあたらなければ
532 | c_putch(' '); //空白を表示
533 | }
534 | else
535 |
536 | //変数の処理
537 | if (*ip == I_VAR) { //もし定数なら
538 | ip++; //ポインタを変数番号へ進める
539 | c_putch(*ip++ + 'A'); //変数名を取得して表示
540 | if (!nospaceb(*ip)) //もし例外にあたらなければ
541 | c_putch(' '); //空白を表示
542 | }
543 | else
544 |
545 | //文字列の処理
546 | if (*ip == I_STR) { //もし文字列なら
547 | char c; //文字列の括りに使われている文字(「"」または「'」)
548 |
549 | //文字列の括りに使われている文字を調べる
550 | c = '\"'; //文字列の括りを仮に「"」とする
551 | ip++; //ポインタを文字数へ進める
552 | for (i = *ip; i; i--) //文字数だけ繰り返す
553 | if (*(ip + i) == '\"') { //もし「"」があれば
554 | c = '\''; //文字列の括りは「'」
555 | break; //繰り返しを打ち切る
556 | }
557 |
558 | //文字列を表示する
559 | c_putch(c); //文字列の括りを表示
560 | i = *ip++; //文字数を取得してポインタを文字列へ進める
561 | while (i--) //文字数だけ繰り返す
562 | c_putch(*ip++); //ポインタを進めながら文字を表示
563 | c_putch(c); //文字列の括りを表示
564 | if (*ip == I_VAR) //もし次の中間コードが変数だったら
565 | c_putch(' '); //空白を表示
566 | }
567 |
568 | else { //どれにも当てはまらなかった場合
569 | err = ERR_SYS; //エラー番号をセット
570 | return; //終了する
571 | }
572 | }
573 | }
574 |
575 | // Get argument in parenthesis
576 | short getparam() {
577 | short value; //値
578 |
579 | if (*cip != I_OPEN) { //もし「(」でなければ
580 | err = ERR_PAREN; //エラー番号をセット
581 | return 0; //終了
582 | }
583 | cip++; //中間コードポインタを次へ進める
584 |
585 | value = iexp(); //式を計算
586 | if (err) //もしエラーが生じたら
587 | return 0; //終了
588 |
589 | if (*cip != I_CLOSE) { //もし「)」でなければ
590 | err = ERR_PAREN; //エラー番号をセット
591 | return 0; //終了
592 | }
593 | cip++; //中間コードポインタを次へ進める
594 |
595 | return value; //値を持ち帰る
596 | }
597 |
598 | // Get value
599 | short ivalue() {
600 | short value; //値
601 |
602 | switch (*cip) { //中間コードで分岐
603 |
604 | //定数の取得
605 | case I_NUM: //定数の場合
606 | cip++; //中間コードポインタを次へ進める
607 | value = *cip | *(cip + 1) << 8; //定数を取得
608 | cip += 2; //中間コードポインタを定数の次へ進める
609 | break; //ここで打ち切る
610 |
611 | //+付きの値の取得
612 | case I_PLUS: //「+」の場合
613 | cip++; //中間コードポインタを次へ進める
614 | value = ivalue(); //値を取得
615 | break; //ここで打ち切る
616 |
617 | //負の値の取得
618 | case I_MINUS: //「-」の場合
619 | cip++; //中間コードポインタを次へ進める
620 | value = 0 - ivalue(); //値を取得して負の値に変換
621 | break; //ここで打ち切る
622 |
623 | //変数の値の取得
624 | case I_VAR: //変数の場合
625 | cip++; //中間コードポインタを次へ進める
626 | value = var[*cip++]; //変数番号から変数の値を取得して次を指し示す
627 | break; //ここで打ち切る
628 |
629 | //括弧の値の取得
630 | case I_OPEN: //「(」の場合
631 | value = getparam(); //括弧の値を取得
632 | break; //ここで打ち切る
633 |
634 | //配列の値の取得
635 | case I_ARRAY: //配列の場合
636 | cip++; //中間コードポインタを次へ進める
637 | value = getparam(); //括弧の値を取得
638 | if (err) //もしエラーが生じたら
639 | break; //ここで打ち切る
640 | if (value >= SIZE_ARRY) { //もし添え字の上限を超えたら
641 | err = ERR_SOR; //エラー番号をセット
642 | break; //ここで打ち切る
643 | }
644 | value = arr[value]; //配列の値を取得
645 | break; //ここで打ち切る
646 |
647 | //関数の値の取得
648 | case I_RND: //関数RNDの場合
649 | cip++; //中間コードポインタを次へ進める
650 | value = getparam(); //括弧の値を取得
651 | if (err) //もしエラーが生じたら
652 | break; //ここで打ち切る
653 | value = getrnd(value); //乱数を取得
654 | break; //ここで打ち切る
655 |
656 | case I_ABS: //関数ABSの場合
657 | cip++; //中間コードポインタを次へ進める
658 | value = getparam(); //括弧の値を取得
659 | if (err) //もしエラーが生じたら
660 | break; //ここで打ち切る
661 | if(value < 0) //もし0未満なら
662 | value *= -1; //正負を反転
663 | break; //ここで打ち切る
664 |
665 | case I_SIZE: //関数SIZEの場合
666 | cip++; //中間コードポインタを次へ進める
667 | //もし後ろに「()」がなかったら
668 | if ((*cip != I_OPEN) || (*(cip + 1) != I_CLOSE)) {
669 | err = ERR_PAREN; //エラー番号をセット
670 | break; //ここで打ち切る
671 | }
672 | cip += 2; //中間コードポインタを「()」の次へ進める
673 | value = getsize(); //プログラム保存領域の空きを取得
674 | break; //ここで打ち切る
675 |
676 | default: //以上のいずれにも該当しなかった場合
677 | err = ERR_SYNTAX; //エラー番号をセット
678 | break; //ここで打ち切る
679 | }
680 | return value; //取得した値を持ち帰る
681 | }
682 |
683 | // multiply or divide calculation
684 | short imul() {
685 | short value, tmp; //値と演算値
686 |
687 | value = ivalue(); //値を取得
688 | if (err) //もしエラーが生じたら
689 | return -1; //終了
690 |
691 | while (1) //無限に繰り返す
692 | switch(*cip){ //中間コードで分岐
693 |
694 | case I_MUL: //掛け算の場合
695 | cip++; //中間コードポインタを次へ進める
696 | tmp = ivalue(); //演算値を取得
697 | value *= tmp; //掛け算を実行
698 | break; //ここで打ち切る
699 |
700 | case I_DIV: //割り算の場合
701 | cip++; //中間コードポインタを次へ進める
702 | tmp = ivalue(); //演算値を取得
703 | if (tmp == 0) { //もし演算値が0なら
704 | err = ERR_DIVBY0; //エラー番号をセット
705 | return -1; //終了
706 | }
707 | value /= tmp; //割り算を実行
708 | break; //ここで打ち切る
709 |
710 | default: //以上のいずれにも該当しなかった場合
711 | return value; //値を持ち帰る
712 | } //中間コードで分岐の末尾
713 | }
714 |
715 | // add or subtract calculation
716 | short iplus() {
717 | short value, tmp; //値と演算値
718 |
719 | value = imul(); //値を取得
720 | if (err) //もしエラーが生じたら
721 | return -1; //終了
722 |
723 | while (1) //無限に繰り返す
724 | switch(*cip){ //中間コードで分岐
725 |
726 | case I_PLUS: //足し算の場合
727 | cip++; //中間コードポインタを次へ進める
728 | tmp = imul(); //演算値を取得
729 | value += tmp; //足し算を実行
730 | break; //ここで打ち切る
731 |
732 | case I_MINUS: //引き算の場合
733 | cip++; //中間コードポインタを次へ進める
734 | tmp = imul(); //演算値を取得
735 | value -= tmp; //引き算を実行
736 | break; //ここで打ち切る
737 |
738 | default: //以上のいずれにも該当しなかった場合
739 | return value; //値を持ち帰る
740 | } //中間コードで分岐の末尾
741 | }
742 |
743 | // The parser
744 | short iexp() {
745 | short value, tmp; //値と演算値
746 |
747 | value = iplus(); //値を取得
748 | if (err) //もしエラーが生じたら
749 | return -1; //終了
750 |
751 | // conditional expression
752 | while (1) //無限に繰り返す
753 | switch(*cip){ //中間コードで分岐
754 |
755 | case I_EQ: //「=」の場合
756 | cip++; //中間コードポインタを次へ進める
757 | tmp = iplus(); //演算値を取得
758 | value = (value == tmp); //真偽を判定
759 | break; //ここで打ち切る
760 | case I_SHARP: //「#」の場合
761 | cip++; //中間コードポインタを次へ進める
762 | tmp = iplus(); //演算値を取得
763 | value = (value != tmp); //真偽を判定
764 | break; //ここで打ち切る
765 | case I_LT: //「<」の場合
766 | cip++; //中間コードポインタを次へ進める
767 | tmp = iplus(); //演算値を取得
768 | value = (value < tmp); //真偽を判定
769 | break; //ここで打ち切る
770 | case I_LTE: //「<=」の場合
771 | cip++; //中間コードポインタを次へ進める
772 | tmp = iplus(); //演算値を取得
773 | value = (value <= tmp); //真偽を判定
774 | break; //ここで打ち切る
775 | case I_GT: //「>」の場合
776 | cip++; //中間コードポインタを次へ進める
777 | tmp = iplus(); //演算値を取得
778 | value = (value > tmp); //真偽を判定
779 | break; //ここで打ち切る
780 | case I_GTE: //「>=」の場合
781 | cip++; //中間コードポインタを次へ進める
782 | tmp = iplus(); //演算値を取得
783 | value = (value >= tmp); //真偽を判定
784 | break; //ここで打ち切る
785 |
786 | default: //以上のいずれにも該当しなかった場合
787 | return value; //値を持ち帰る
788 | } //中間コードで分岐の末尾
789 | }
790 |
791 | // PRINT handler
792 | void iprint() {
793 | short value; //値
794 | short len; //桁数
795 | unsigned char i; //文字数
796 |
797 | len = 0; //桁数を初期化
798 | while (*cip != I_SEMI && *cip != I_EOL) { //文末まで繰り返す
799 | switch (*cip) { //中間コードで分岐
800 |
801 | case I_STR: //文字列の場合
802 | cip++; //中間コードポインタを次へ進める
803 | i = *cip++; //文字数を取得
804 | while (i--) //文字数だけ繰り返す
805 | c_putch(*cip++); //文字を表示
806 | break; //打ち切る
807 |
808 | case I_SHARP: //「#」の場合
809 | cip++; //中間コードポインタを次へ進める
810 | len = iexp(); //桁数を取得
811 | if (err) //もしエラーが生じたら
812 | return; //終了
813 | break; //打ち切る
814 |
815 | default: //以上のいずれにも該当しなかった場合(式とみなす)
816 | value = iexp(); //値を取得
817 | if (err) //もしエラーが生じたら
818 | return; //終了
819 | putnum(value, len); //値を表示
820 | break; //打ち切る
821 | } //中間コードで分岐の末尾
822 |
823 | if (*cip == I_COMMA) { //もしコンマがあったら
824 | cip++; //中間コードポインタを次へ進める
825 | if (*cip == I_SEMI || *cip == I_EOL) //もし文末なら
826 | return; //終了
827 | } else { //コンマがなければ
828 | if (*cip != I_SEMI && *cip != I_EOL) { //もし文末でなければ
829 | err = ERR_SYNTAX; //エラー番号をセット
830 | return; //終了
831 | }
832 | }
833 | } //文末まで繰り返すの末尾
834 |
835 | newline(); //改行
836 | }
837 |
838 | // INPUT handler
839 | void iinput() {
840 | short value; //値
841 | short index; //配列の添え字
842 | unsigned char i; //文字数
843 | unsigned char prompt; //プロンプト表示フラグ
844 |
845 | while (1) { //無限に繰り返す
846 | prompt = 1; //まだプロンプトを表示していない
847 |
848 | //プロンプトが指定された場合の処理
849 | if(*cip == I_STR){ //もし中間コードが文字列なら
850 | cip++; //中間コードポインタを次へ進める
851 | i = *cip++; //文字数を取得
852 | while (i--) //文字数だけ繰り返す
853 | c_putch(*cip++); //文字を表示
854 | prompt = 0; //プロンプトを表示した
855 | }
856 |
857 | //値を入力する処理
858 | switch (*cip) { //中間コードで分岐
859 | case I_VAR: //変数の場合
860 | cip++; //中間コードポインタを次へ進める
861 | if (prompt) { //もしまだプロンプトを表示していなければ
862 | c_putch(*cip + 'A'); //変数名を表示
863 | c_putch(':'); //「:」を表示
864 | }
865 | value = getnum(); //値を入力
866 | if (err) //もしエラーが生じたら
867 | return; //終了
868 | var[*cip++] = value; //変数へ代入
869 | break; //打ち切る
870 |
871 | case I_ARRAY: //配列の場合
872 | cip++; //中間コードポインタを次へ進める
873 | index = getparam(); //配列の添え字を取得
874 | if (err) //もしエラーが生じたら
875 | return; //終了
876 | if (index >= SIZE_ARRY) { //もし添え字が上限を超えたら
877 | err = ERR_SOR; //エラー番号をセット
878 | return; //終了
879 | }
880 | if (prompt) { //もしまだプロンプトを表示していなければ
881 | c_puts("@("); //「@(」を表示
882 | putnum(index, 0); //添え字を表示
883 | c_puts("):"); //「):」を表示
884 | }
885 | value = getnum(); //値を入力
886 | if (err) //もしエラーが生じたら
887 | return; //終了
888 | arr[index] = value; //配列へ代入
889 | break; //打ち切る
890 |
891 | default: //以上のいずれにも該当しなかった場合
892 | err = ERR_SYNTAX; //エラー番号をセット
893 | return; //終了
894 | } //中間コードで分岐の末尾
895 |
896 | //値の入力を連続するかどうか判定する処理
897 | switch (*cip) { //中間コードで分岐
898 | case I_COMMA: //コンマの場合
899 | cip++; //中間コードポインタを次へ進める
900 | break; //打ち切る
901 | case I_SEMI: //「;」の場合
902 | case I_EOL: //行末の場合
903 | return; //終了
904 | default: //以上のいずれにも該当しなかった場合
905 | err = ERR_SYNTAX; //エラー番号をセット
906 | return; //終了
907 | } //中間コードで分岐の末尾
908 | } //無限に繰り返すの末尾
909 | }
910 |
911 | // Variable assignment handler
912 | void ivar() {
913 | short value; //値
914 | short index; //変数番号
915 |
916 | index = *cip++; //変数番号を取得して次へ進む
917 |
918 | if (*cip != I_EQ) { //もし「=」でなければ
919 | err = ERR_VWOEQ; //エラー番号をセット
920 | return; //終了
921 | }
922 | cip++; //中間コードポインタを次へ進める
923 |
924 | //値の取得と代入
925 | value = iexp(); //式の値を取得
926 | if (err) //もしエラーが生じたら
927 | return; //終了
928 | var[index] = value; //変数へ代入
929 | }
930 |
931 | // Array assignment handler
932 | void iarray() {
933 | short value; //値
934 | short index; //配列の添え字
935 |
936 | index = getparam(); //配列の添え字を取得
937 | if (err) //もしエラーが生じたら
938 | return; //終了
939 |
940 | if (index >= SIZE_ARRY) { //もし添え字が上限を超えたら
941 | err = ERR_SOR; //エラー番号をセット
942 | return; //終了
943 | }
944 |
945 | if (*cip != I_EQ) { //もし「=」でなければ
946 | err = ERR_VWOEQ; //エラー番号をセット
947 | return; //終了
948 | }
949 | cip++; //中間コードポインタを次へ進める
950 |
951 | value = iexp(); //式の値を取得
952 | if (err) //もしエラーが生じたら
953 | return; //終了
954 | arr[index] = value; //配列へ代入
955 | }
956 |
957 | // LET handler
958 | void ilet() {
959 | switch (*cip) { //中間コードで分岐
960 |
961 | case I_VAR: //変数の場合
962 | cip++; //中間コードポインタを次へ進める
963 | ivar(); //変数への代入を実行
964 | break; //打ち切る
965 |
966 | case I_ARRAY: //配列の場合
967 | cip++; //中間コードポインタを次へ進める
968 | iarray(); //配列への代入を実行
969 | break; //打ち切る
970 |
971 | default: //以上のいずれにも該当しなかった場合
972 | err = ERR_LETWOV; //エラー番号をセット
973 | break; //打ち切る
974 | }
975 | }
976 |
977 | // Execute a series of i-code
978 | unsigned char* iexe() {
979 | short lineno; //行番号
980 | unsigned char* lp; //未確定の(エラーかもしれない)行ポインタ
981 | short index, vto, vstep; //FOR文の変数番号、終了値、増分
982 | short condition; //IF文の条件値
983 |
984 | while (*cip != I_EOL) { //行末まで繰り返す
985 |
986 | //強制的な中断の判定
987 | if (c_kbhit()) //もし未読文字があったら
988 | if (c_getch() == 27) { //読み込んでもし[ESC]キーだったら
989 | err = ERR_ESC; //エラー番号をセット
990 | break; //打ち切る
991 | }
992 |
993 | //中間コードを実行
994 | switch (*cip) { //中間コードで分岐
995 |
996 | case I_GOTO: //GOTOの場合
997 | cip++; //中間コードポインタを次へ進める
998 | lineno = iexp(); //分岐先の行番号を取得
999 | if (err) //もしエラーが生じたら
1000 | break; //打ち切る
1001 | lp = getlp(lineno); //分岐先のポインタを取得
1002 | if (lineno != getlineno(lp)) { //もし分岐先が存在しなければ
1003 | err = ERR_ULN; //エラー番号をセット
1004 | break; //打ち切る
1005 | }
1006 |
1007 | clp = lp; //行ポインタを分岐先へ更新
1008 | cip = clp + 3; //中間コードポインタを先頭の中間コードに更新
1009 | break; //打ち切る
1010 |
1011 | case I_GOSUB: //GOSUBの場合
1012 | cip++; //中間コードポインタを次へ進める
1013 | lineno = iexp(); //分岐先の行番号を取得
1014 | if (err) //もしエラーが生じたら
1015 | break; //打ち切る
1016 | lp = getlp(lineno); //分岐先のポインタを取得
1017 | if (lineno != getlineno(lp)) { //もし分岐先が存在しなければ
1018 | err = ERR_ULN; //エラー番号をセット
1019 | break; //打ち切る
1020 | }
1021 |
1022 | //ポインタを退避
1023 | if (gstki > SIZE_GSTK - 2) { //もしGOSUBスタックがいっぱいなら
1024 | err = ERR_GSTKOF; //エラー番号をセット
1025 | break; //打ち切る
1026 | }
1027 | gstk[gstki++] = clp; //行ポインタを退避
1028 | gstk[gstki++] = cip; //中間コードポインタを退避
1029 |
1030 | clp = lp; //行ポインタを分岐先へ更新
1031 | cip = clp + 3; //中間コードポインタを先頭の中間コードに更新
1032 | break; //打ち切る
1033 |
1034 | case I_RETURN: //RETURNの場合
1035 | if (gstki < 2) { //もしGOSUBスタックが空なら
1036 | err = ERR_GSTKUF; //エラー番号をセット
1037 | break; //打ち切る
1038 | }
1039 |
1040 | cip = gstk[--gstki]; //行ポインタを復帰
1041 | clp = gstk[--gstki]; //中間コードポインタを復帰
1042 | break; //打ち切る
1043 |
1044 | case I_FOR: //FORの場合
1045 | cip++; //中間コードポインタを次へ進める
1046 |
1047 | //変数名を取得して開始値を代入(例I=1)
1048 | if (*cip++ != I_VAR) { //もし変数がなかったら
1049 | err = ERR_FORWOV; //エラー番号をセット
1050 | break; //打ち切る
1051 | }
1052 | index = *cip; //変数名を取得
1053 | ivar(); //代入文を実行
1054 | if (err) //もしエラーが生じたら
1055 | break; //打ち切る
1056 |
1057 | //終了値を取得(例TO 5)
1058 | if (*cip == I_TO) { //もしTOだったら
1059 | cip++; //中間コードポインタを次へ進める
1060 | vto = iexp(); //終了値を取得
1061 | } else { //TOではなかったら
1062 | err = ERR_FORWOTO; //エラー番号をセット
1063 | break; //打ち切る
1064 | }
1065 |
1066 | //増分を取得(例STEP 1)
1067 | if (*cip == I_STEP) { //もしSTEPだったら
1068 | cip++; //中間コードポインタを次へ進める
1069 | vstep = iexp(); //増分を取得
1070 | } else //STEPではなかったら
1071 | vstep = 1; //増分を1に設定
1072 |
1073 | //もし変数がオーバーフローする見込みなら
1074 | if (((vstep < 0) && (-32767 - vstep > vto)) ||
1075 | ((vstep > 0) && (32767 - vstep < vto))){
1076 | err = ERR_VOF; //エラー番号をセット
1077 | break; //打ち切る
1078 | }
1079 |
1080 | //繰り返し条件を退避
1081 | if (lstki > SIZE_LSTK - 5) { //もしFORスタックがいっぱいなら
1082 | err = ERR_LSTKOF; //エラー番号をセット
1083 | break; //打ち切る
1084 | }
1085 | lstk[lstki++] = clp; //行ポインタを退避
1086 | lstk[lstki++] = cip; //中間コードポインタを退避
1087 | //FORスタックに終了値、増分、変数名を退避
1088 | //Special thanks hardyboy
1089 | lstk[lstki++] = (unsigned char*)(uintptr_t)vto;
1090 | lstk[lstki++] = (unsigned char*)(uintptr_t)vstep;
1091 | lstk[lstki++] = (unsigned char*)(uintptr_t)index;
1092 | break; //打ち切る
1093 |
1094 | case I_NEXT: //NEXTの場合
1095 | cip++; //中間コードポインタを次へ進める
1096 | if (lstki < 5) { //もしFORスタックが空なら
1097 | err = ERR_LSTKUF; //エラー番号をセット
1098 | break; //打ち切る
1099 | }
1100 |
1101 | //変数名を復帰
1102 | index = (short)(uintptr_t)lstk[lstki - 1]; //変数名を復帰
1103 | if (*cip++ != I_VAR) { //もしNEXTの後ろに変数がなかったら
1104 | err = ERR_NEXTWOV; //エラー番号をセット
1105 | break; //打ち切る
1106 | }
1107 | if (*cip++ != index) { //もし復帰した変数名と一致しなかったら
1108 | err = ERR_NEXTUM; //エラー番号をセット
1109 | break; //打ち切る
1110 | }
1111 |
1112 | vstep = (short)(uintptr_t)lstk[lstki - 2]; //増分を復帰
1113 | var[index] += vstep; //変数の値を最新の開始値に更新
1114 | vto = (short)(uintptr_t)lstk[lstki - 3]; //終了値を復帰
1115 |
1116 | //もし変数の値が終了値を超えていたら
1117 | if (((vstep < 0) && (var[index] < vto)) ||
1118 | ((vstep > 0) && (var[index] > vto))) {
1119 | lstki -= 5; //FORスタックを1ネスト分戻す
1120 | break; //打ち切る
1121 | }
1122 |
1123 | //開始値が終了値を超えていなかった場合
1124 | cip = lstk[lstki - 4]; //行ポインタを復帰
1125 | clp = lstk[lstki - 5]; //中間コードポインタを復帰
1126 | break; //打ち切る
1127 |
1128 | case I_IF: //IFの場合
1129 | cip++; //中間コードポインタを次へ進める
1130 | condition = iexp(); //真偽を取得
1131 | if (err) { //もしエラーが生じたら
1132 | err = ERR_IFWOC; //エラー番号をセット
1133 | break; //打ち切る
1134 | }
1135 | if (condition) //もし真なら
1136 | break; //打ち切る(次の文を実行する)
1137 | //偽の場合の処理はREMと同じ
1138 |
1139 | case I_REM: //REMの場合
1140 | while (*cip != I_EOL) //I_EOLに達するまで繰り返す
1141 | cip++; //中間コードポインタを次へ進める
1142 | break; //打ち切る
1143 |
1144 | case I_STOP: //STOPの場合
1145 | while (*clp) //行の終端まで繰り返す
1146 | clp += *clp; //行ポインタを次へ進める
1147 | return clp; //行ポインタを持ち帰る
1148 |
1149 | //一般の文に相当する中間コードの照合と処理
1150 | case I_VAR: //変数の場合(LETを省略した代入文)
1151 | cip++; //中間コードポインタを次へ進める
1152 | ivar(); //代入文を実行
1153 | break; //打ち切る
1154 | case I_ARRAY: //配列の場合(LETを省略した代入文)
1155 | cip++; //中間コードポインタを次へ進める
1156 | iarray(); //代入文を実行
1157 | break; //打ち切る
1158 | case I_LET: //LETの場合
1159 | cip++; //中間コードポインタを次へ進める
1160 | ilet(); //LET文を実行
1161 | break; //打ち切る
1162 | case I_PRINT: //PRINTの場合
1163 | cip++; //中間コードポインタを次へ進める
1164 | iprint(); //PRINT文を実行
1165 | break; //打ち切る
1166 | case I_INPUT: //INPUTの場合
1167 | cip++; //中間コードポインタを次へ進める
1168 | iinput(); //INPUT文を実行
1169 | break; //打ち切る
1170 |
1171 | case I_NEW: //中間コードがNEWの場合
1172 | case I_LIST: //中間コードがLISTの場合
1173 | case I_RUN: //中間コードがRUNの場合
1174 | err = ERR_COM; //エラー番号をセット
1175 | return NULL; //終了
1176 | case I_SEMI: //中間コードが「;」の場合
1177 | cip++; //中間コードポインタを次へ進める
1178 | break; //打ち切る
1179 | default: //以上のいずれにも該当しない場合
1180 | err = ERR_SYNTAX; //エラー番号をセット
1181 | break; //打ち切る
1182 | } //中間コードで分岐の末尾
1183 |
1184 | if (err) //もしエラーが生じたら
1185 | return NULL; //終了
1186 | } //行末まで繰り返すの末尾
1187 | return clp + *clp; //次に実行するべき行のポインタを持ち帰る
1188 | }
1189 |
1190 | // RUN command handler
1191 | void irun() {
1192 | unsigned char* lp; //行ポインタの一時的な記憶場所
1193 |
1194 | gstki = 0; //GOSUBスタックインデクスを0に初期化
1195 | lstki = 0; //FORスタックインデクスを0に初期化
1196 | clp = listbuf; //行ポインタをプログラム保存領域の先頭に設定
1197 |
1198 | while (*clp) { //行ポインタが末尾を指すまで繰り返す
1199 | cip = clp + 3; //中間コードポインタを行番号の後ろに設定
1200 | lp = iexe(); //中間コードを実行して次の行の位置を得る
1201 | if (err) //もしエラーを生じたら
1202 | return; //終了
1203 | clp = lp; //行ポインタを次の行の位置へ移動
1204 | } //行ポインタが末尾を指すまで繰り返すの末尾
1205 | }
1206 |
1207 | // LIST command handler
1208 | void ilist() {
1209 | short lineno; //表示開始行番号
1210 |
1211 | //表示開始行番号の設定
1212 | if (*cip == I_NUM) //もしLIST命令に引数があったら
1213 | lineno = getlineno(cip); //引数を読み取って表示開始行番号とする
1214 | else //引数がなければ
1215 | lineno = 0; //表示開始行番号を0とする
1216 |
1217 | //行ポインタを表示開始行番号へ進める
1218 | for ( //次の手順で繰り返す
1219 | clp = listbuf; //行ポインタを先頭行へ設定
1220 | //末尾ではなくて表示開始行より前なら繰り返す
1221 | *clp && (getlineno(clp) < lineno);
1222 | clp += *clp); //行ポインタを次の行へ進める
1223 |
1224 | //リストを表示する
1225 | while (*clp) { //行ポインタが末尾を指すまで繰り返す
1226 | putnum(getlineno(clp), 0); //行番号を表示
1227 | c_putch(' '); //空白を入れる
1228 | putlist(clp + 3); //行番号より後ろを文字列に変換して表示
1229 | if (err) //もしエラーが生じたら
1230 | break; //繰り返しを打ち切る
1231 | newline(); //改行
1232 | clp += *clp; //行ポインタを次の行へ進める
1233 | }
1234 | }
1235 |
1236 | //NEW command handler
1237 | void inew(void) {
1238 | unsigned char i; //ループカウンタ
1239 |
1240 | //変数と配列の初期化
1241 | for (i = 0; i < 26; i++) //変数の数だけ繰り返す
1242 | var[i] = 0; //変数を0に初期化
1243 | for (i = 0; i < SIZE_ARRY; i++) //配列の数だけ繰り返す
1244 | arr[i] = 0; //配列を0に初期化
1245 |
1246 | //実行制御用の初期化
1247 | gstki = 0; //GOSUBスタックインデクスを0に初期化
1248 | lstki = 0; //FORスタックインデクスを0に初期化
1249 | *listbuf = 0; //プログラム保存領域の先頭に末尾の印を置く
1250 | clp = listbuf; //行ポインタをプログラム保存領域の先頭に設定
1251 | }
1252 |
1253 | //Command precessor
1254 | void icom() {
1255 | cip = ibuf; //中間コードポインタを中間コードバッファの先頭に設定
1256 |
1257 | switch (*cip) { //中間コードポインタが指し示す中間コードによって分岐
1258 |
1259 | case I_NEW: //I_NEWの場合(NEW命令)
1260 | cip++; //中間コードポインタを次へ進める
1261 | if (*cip == I_EOL) //もし行末だったら
1262 | inew(); //NEW命令を実行
1263 | else //行末でなければ
1264 | err = ERR_SYNTAX; //エラー番号をセット
1265 | break; //打ち切る
1266 |
1267 | case I_LIST: //I_LISTの場合(LIST命令)
1268 | cip++; //中間コードポインタを次へ進める
1269 | if (*cip == I_EOL || //もし行末か、あるいは
1270 | *(cip + 3) == I_EOL) //続いて引数があれば
1271 | ilist(); //LIST命令を実行
1272 | else //そうでなければ
1273 | err = ERR_SYNTAX; //エラー番号をセット
1274 | break; //打ち切る
1275 |
1276 | case I_RUN: //I_RUNの場合(RUN命令)
1277 | cip++; //中間コードポインタを次へ進める
1278 | irun(); //RUN命令を実行
1279 | break; //打ち切る
1280 |
1281 | default: //どれにも該当しない場合
1282 | iexe(); //中間コードを実行
1283 | break; //打ち切る
1284 | }
1285 | }
1286 |
1287 | // Print OK or error message
1288 | void error() {
1289 | if (err) { //もし「OK」ではなかったら
1290 |
1291 | //もしプログラムの実行中なら(cipがリストの中にあり、clpが末尾ではない場合)
1292 | if (cip >= listbuf && cip < listbuf + SIZE_LIST && *clp)
1293 | {
1294 | newline(); //改行
1295 | c_puts("LINE:"); //「LINE:」を表示
1296 | putnum(getlineno(clp), 0); //行番号を調べて表示
1297 | c_putch(' '); //空白を表示
1298 | putlist(clp + 3); //リストの該当行を表示
1299 | }
1300 | else //指示の実行中なら
1301 | {
1302 | newline(); //改行
1303 | c_puts("YOU TYPE: "); //「YOU TYPE:」を表示
1304 | c_puts(lbuf); //文字列バッファの内容を表示
1305 | }
1306 | } //もし「OK」ではなかったらの末尾
1307 |
1308 | newline(); //改行
1309 | c_puts(errmsg[err]); //「OK」またはエラーメッセージを表示
1310 | newline(); //改行
1311 | err = 0; //エラー番号をクリア
1312 | }
1313 |
1314 | /*
1315 | TOYOSHIKI Tiny BASIC
1316 | The BASIC entry point
1317 | */
1318 |
1319 | void basic() {
1320 | unsigned char len; //中間コードの長さ
1321 |
1322 | inew(); //実行環境を初期化
1323 |
1324 | //起動メッセージ
1325 | c_puts("TOYOSHIKI TINY BASIC"); //「TOYOSHIKI TINY BASIC」を表示
1326 | newline(); //改行
1327 | c_puts(STR_EDITION); //版を区別する文字列を表示
1328 | c_puts(" EDITION"); //「 EDITION」を表示
1329 | newline(); //改行
1330 | error(); //「OK」またはエラーメッセージを表示してエラー番号をクリア
1331 |
1332 | //端末から1行を入力して実行
1333 | while (1) { //無限ループ
1334 | c_putch('>'); //プロンプトを表示
1335 | c_gets(); //1行を入力
1336 |
1337 | //1行の文字列を中間コードの並びに変換
1338 | len = toktoi(); //文字列を中間コードに変換して長さを取得
1339 | if (err) { //もしエラーが発生したら
1340 | error(); //エラーメッセージを表示してエラー番号をクリア
1341 | continue; //繰り返しの先頭へ戻ってやり直し
1342 | }
1343 |
1344 | //中間コードの並びがプログラムと判断される場合
1345 | if (*ibuf == I_NUM) { //もし中間コードバッファの先頭が行番号なら
1346 | *ibuf = len; //中間コードバッファの先頭を長さに書き換える
1347 | inslist(); //中間コードの1行をリストへ挿入
1348 | if (err) //もしエラーが発生したら
1349 | error(); //エラーメッセージを表示してエラー番号をクリア
1350 | continue; //繰り返しの先頭へ戻ってやり直し
1351 | }
1352 |
1353 | //中間コードの並びが命令と判断される場合
1354 | icom(); //実行する
1355 | error(); //エラーメッセージを表示してエラー番号をクリア
1356 |
1357 | } //無限ループの末尾
1358 | }
1359 |
--------------------------------------------------------------------------------
/ttbasic/ttbasic.ino:
--------------------------------------------------------------------------------
1 | /*
2 | TOYOSHIKI Tiny BASIC for Arduino
3 | (C)2012 Tetsuya Suzuki
4 | */
5 |
6 | void basic(void);
7 |
8 | void setup(void){
9 | // put your setup code here, to run once:
10 | Serial.begin(9600);
11 | randomSeed(analogRead(0));
12 | }
13 |
14 | void loop(void){
15 | // put your main code here, to run repeatedly:
16 | basic();
17 | }
18 |
--------------------------------------------------------------------------------