├── 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 | --------------------------------------------------------------------------------