C言語-インタプリタminiBASIC |
5. END, INPUT, PRINT の処理
各命令の動作にあった処理をプログラミングしていく。その時、各命令の文法(書式、使い方)も決めていく。
[END命令]
END命令の動作は、プログラムを終了させることである。具体的には、 % mbas reidai.mbのように実行したプログラムを終了し、OSのコマンド待ちにすることである。C言語では、関数exitなどで終了することになる。
書式
END
実際にEND命令でプログラムが終了したことがわかるように「終了します」とメッセージを表示して終了するようにする。
40: if(!strcmp("END", token)){ printf("終了します\n"); exit(1); }
[INPUT命令]
INPUT命令の書式をプログラミングが簡単になるように次の形式に決める(後で機能を追加する)。
書式
INPUT 変数
動作は、「?」を表示してキー入力待ちになる。入力された数値は、変数に格納される。変数は、英字1文字(A-Z)である。
プログラムは、関数として作成する。関数名は、mbasのINPUTなのでmb_inputとする。引数も返却値もない。
変数は、プログラムのどこからでも参照できるように実数(double)型のグローバル(大域)変数(配列)とする。A〜Zの26個分宣言する。例えば、配列名をhensuuとするとdouble
hensuu[26];となる。変数Aの値はhensuu[0]に、変数Zの値はhensuu[25]に格納されるようにする。
A(0x41)〜Z(0x5a)のように文字コードは連続しているので、変数名の文字コードから0x41を引き算すれば、配列の添え字が求まる。
41: else if(!strcmp("INPUT", token)) mb_input(); … … … … … void mb_input(void) { 次のトークン(変数)を取得 変数として正しくない{ エラーメッセージ表示 終了 } プロンプト(?)表示 キー入力(文字列として, gets()) 入力データを実数に変換して変数に格納 }
ここまでをプログラムすると次のようになる。
[mbas04.mb] | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gettoken.h" /* 関数プロトタイプ宣言 */ @ ; /* グローバル変数 */ A ; /* 変数用(A〜Z) */ void main(int argc, char *argv[]) { char *list[100]; /* プログラムリスト用 */ char buff[256]; /* 1行読み込み用 */ FILE *fp; /* ファイルポインタ */ int now = 0; /* 行数カウント */ int last; /* 最終行 */ <<省 略>> /* 命令の処理 */ for(now = 0; now < last; ++now){ strcpy(gt_line, list[now]); /* 字句解析の準備 */ get_token(); /* トークンの取得 */ if(!strcmp("END", token)){ /* 命令の判定 */ printf("終了します\n"); exit(1); } else if(!strcmp("INPUT", token)) mb_input(); else if(!strcmp("PRINT", token)) printf("PRINT 命令です\n"); <<省 略>> else printf("命令以外です\n"); } } void mb_input(void) { char buff[256]; /* キー入力用 */ if(!isalpha(*get_token())){ /* 変数名取得・チェック */ printf("変数名は英字のみです\n"); exit(1); } B ; /* プロンプト表示 */ C ; /* キー入力 */ hensuu[*token - 'A'] = atof(buff); /* 入力データを変数へ */ } |
INPUT命令の処理の説明ではトークン(変数名)取得と変数名のチェックを2行で書いている。上のプログラムでは、それを1行で書いている。これを2行で書くと次のようになり変数(char val;)が一つ必要になる。
val = *get_token();
if(!isalpha(val)){
関数get_token()は取り出したトークン(文字列)の先頭アドレスを返却する。したがって、get_token()はアドレスを表すことになり、この関数の直前に*(ポインタ演算子)を付けることでアドレスのデータ、すなわちトークンの先頭の1文字を表すことになる。結果として変数valにはトークンの先頭の1文字が記憶されるので、変数valはchar型となる。
[PRINT命令]
PRINT命令の書式をプログラミングが簡単になるように次の形式に決める(後で機能を追加する)。
書式
PRINT 変数
動作は、変数の値を画面に表示することである。
プログラムは、関数として作成する。関数名は、mbasのPRINTなのでmb_printとする。引数も返却値もない。
変数は、INPUT命令のときにグローバル変数(配列)として宣言してあるので再度宣言する必要はない。
52: else if(!strcmp("PRINT", token)) mb_print(); … … … … … void mb_print(void) { 次のトークン(変数)を取得 変数として正しくない{ エラーメッセージ表示 終了 } 変数の値を表示 }
ここまでをプログラムすると次のようになる。
[mbas05.c] | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 91: |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gettoken.h" /* 関数プロトタイプ宣言 */ @ ; void mb_input(void); /* グローバル変数 */ double hensuu[26]; /* 変数用(A〜Z) */ void main(int argc, char *argv[]) { <<省 略>> /* 命令の処理 */ for(now = 0; now < last; ++now){ strcpy(gt_line, list[now]); /* 字句解析の準備 */ get_token(); /* トークンの取得 */ if(!strcmp("END", token)){ /* 命令の判定 */ printf("終了します\n"); exit(1); } else if(!strcmp("INPUT", token)) mb_input(); else if(!strcmp("PRINT", token)) mb_print(); else if(!strcmp("FOR", token)) printf("FOR 命令です\n"); <<省 略>> else printf("命令以外です\n"); } } void mb_print(void) { if(A ){ /* 変数名取得・チェック */ printf("変数名は英字のみです\n"); exit(1); } printf("%f\n", hensuu[B ]); /* 変数値の表示 */ } void mb_input(void) { <<省 略>> } |
D:\Data\src>cc mbas05.c gettoken.obj lld @link.i D:\Data\src>mbas05 reidai02.mb ? 12.3456 ? 23.45678 23.456780 12.345600 終了します |
コンパイルした後、次のようなmbasのプログラムを用意して、実行する。
INPUT A INPUT Z PRINT Z PRINT A END |
Copyright © 2001 Hiroshi Masuda |