C言語-トランスレータ(mbas to C) |
9. 繰返し制御文 FOR - NEXT
[FOR文]
書式
FOR 変数 = 式1 TO 式2 [STEP 式3]
増分(STEP 式3)は省略可能で、省略したときの増分は1とする。
変換 | FOR 変数 = 式1 TO 式2 → | for(変数=式1;変数<=式2;++変数){ |
FOR 変数 = 式1 TO 式2 STEP 式3 → | for(変数=式1;変数<=式2;変数+=式3){ |
これだけでは、増分が負の時に対応することができない。例えば、次のFOR文
FOR N = 10 TO 2 STEP -2
を上記の変換にしたがってC言語に変換すると
for(N = 10; N <= 2; N += -2){
となる。変数Nの初期値が10であり、N <= 2の条件式が偽になるので一度も繰り返し実行されない。この場合、正しくは次のように変換しなければならない。
for(N = 10; N >= 2; N += -2){
増分が負の時、条件式を>=にしなければならない。しかし、式3が負であるかどうかは式を計算してみなくてはわからない。例えば増分の式3に"3-5"と指定されたような場合である。
ここでは、増分の式3が−(マイナス)記号で始まっているものだけを負の増分と判定することにする。
変換(追加) | FOR 変数 = 式1 TO 式2 STEP -式3 → | for(変数=式1;変数<=式2;変数+=-式3){ |
変換の処理は、関数mbt_forとして作成する。まず、FOR文のパラメータ(変数、=、式1、TO、式2、STEP、式3)をすべて取り出した後にFOR文を構成し直して出力する。
FOR文の次の文からは、インデントを1つ深くするので、インデント用の変数tabを1加算しておく。
[NEXT文]
書式
NEXT
C言語では、FOR文の範囲の終わりを } で表すので、NEXTが現れたらインデントを1つ浅くして } を表示する。
[main11.c] | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 92: 93: |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gettoken.h" /* 関数のプロトタイプ宣言 */ extern void mbt_for(void); extern void mbt_print(void); extern void mbt_input(void); extern void ptab(void); extern char *get_shiki(void); /* getshiki.c */ /* グローバル変数 */ << 省略 >> else if(!strcmp("PRINT", token)) mbt_print(); /* PRINT 命令の処理 */ else if(!strcmp("FOR", token)){ @ ; /* FOR 命令の処理 */ ++tab; /* インデントを1つ深くする */ }else if(!strcmp("NEXT", token)){ --tab; /* インデントを1つ浅くする */ ptab(); printf(A ); /* NEXT 命令の処理 */ }else if(!strcmp("IF", token)) printf("IF 命令です\n"); << 省略 >> printf("}\n"); } |
[mbt_sub2.c] | |
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 80: 81: 82: 111: 112: 113: 121: |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include "gettoken.h" /* 関数のプロトタイプ宣言 */ void mbt_print(void); void mbt_input(void); void ptab(void); extern char *get_shiki(void); /* getshiki.c */ /* グローバル変数 */ extern int tab; void mbt_for(void) { int val; /* 変数番号 */ char shiki1[256], shiki2[256], shiki3[256]; get_token(); if(isalpha(*token) && strlen(token) == 1) /* 変数名 */ val = *token - 'A'; else{ printf("FOR 変数名エラー\n"); exit(1); } if(*get_token() != B ){ /* = */ printf("FOR 文法エラー\n"); exit(1); } strcpy(shiki1, get_shiki()); /* 始値 */ get_token(); if(*token != 'T' || token[1] != 'O'){ /* TO */ printf("FOR 文法エラー\n"); exit(1); } strcpy(C , get_shiki()); /* 終値 */ get_token(); if(*token == '\n') /* 増分 */ shiki3[0] = '\0'; else if(!strcmp("STEP", token)) strcpy(D , get_shiki()); ptab(); if(shiki3[1] == '-') /* 減少 get_shikiで取得した式の先頭は空白が入っている*/ printf("for(hensuu[%d] = %s; hensuu[%d] >= %s; hensuu[%d] += %s){\n", E , F , E , G , E , H ); else if(shiki3[0] == '\0') printf("for(hensuu[%d] = %s; hensuu[%d] <= %s; ++hensuu[%d]){\n", E , F , E , G , E ); else printf("for(hensuu[%d] = %s; hensuu[%d] <= %s; hensuu[%d] += %s){\n", E , F , E , G , E , H ); } void mbt_print(void) { << 省略 >> } void mbt_input(void) { << 省略 >> } void ptab(void) { << 省略 >> } |
FOR | 変数 | = | 式1 | TO | 式2 | STEP | 式3 |
※1 | ※2 | ※3 | ※4 |
変数(※1)の番号を変数valに、式1(※2)を文字型配列shiki1に、式2(※3)を文字型配列shiki2に、式3(※4)についてはあれば文字型配列shiki3に、それぞれ記憶してからまとめて表示する。
19〜24行目で変数名をチェックし、変数の番号(配列hensuuの添字)を計算して変数valに記憶させる。 | |
25〜28行目で=があるかどうかをチェックしている。 | |
※2 | 29行目で式1を文字型配列shiki1に記憶させる。 |
31〜34行目でTOがあるかどうかをチェックしている。 | |
※3 | 35行目で式2を文字型配列shiki2に記憶させる。 |
37,38行目でSTEPが無ければ(行末を表す改行\nであれば)文字型配列shiki3にナル文字(\0)を記憶させる。 | |
※4 | 39,40行目でSTEPがあれば式3を文字型配列shiki3に記憶させる。 |
42〜50行目で変換後のfor文を表示している。まず、42行目で式3が負のとき、45行目で式3がないとき、48行目で式3が正のときのfor文を表示している。 |
FOR A = 1 TO 5 PRINT A;" Kai" NEXT |
makefileの1行目のメインファイルをmain11に、2行目のサブファイルをmbt_sub2に変更してからmakeを実行する。
mbtでreidai4.mbをreidai4.cに変換し、コンパイルすると
reidai4.c 30: Warning: 'buff' not used
という警告が表示される。これは、宣言した配列buffを使っていないというものである。reidai4.mbに入力命令がないためである。エラーではないので実行できる。
D:\Data\src>make lcc -c -o main11.obj main11.c lcc -c -o mbt_sub2.obj mbt_sub2.c lcc -o mbt.exe main11.obj mbt_sub2.obj gettoken.obj getshiki.obj lld @link.i D:\Data\src>mbt reidai4.mb > reidai4.c D:\Data\src>cc reidai4.c reidai4.c 30: Warning: 'buff' not used lld @link.i D:\Data\src>reidai4 1.000000 Kai 2.000000 Kai 3.000000 Kai 4.000000 Kai 5.000000 Kai FOR TEST 1 = 10.000000 FOR TEST 1 = 16.000000 FOR TEST 1 = 22.000000 FOR TEST 2 = 30.000000 FOR TEST 2 = 25.000000 FOR TEST 2 = 20.000000 FOR TEST 3 = 0.000000 FOR TEST 3 = 5.000000 FOR TEST 3 = 10.000000 終了します |
変換後のreidai4.c ↓
関数のプロトタイプ宣言について
ファイルmbt_sub2.cの中に新しく関数mbt_for()を作成したが、関数のプロトタイプ宣言をしていない。宣言をしなくてもエラーは出ない。これは、他の関数からmbt_for()を呼び出していないためである。正確には関数を呼び出すまでに宣言するか、関数本体があればよいのである。
関数mbt_print()とmbt_input()も他の関数から呼び出されていないので、7,8行目の関数のプロトタイプ宣言を削除してもよい。しかし、関数ptab()はmbt_for()、mbt_print()、mbt_input()から呼び出されているので9行目の関数のプロトタイプ宣言を削除することはできない。ただし、112行目から121行目の関数ptab()をmbt_for()より前に移動すれば9行目を削除することができる。
ここでは、7,8行目にある関数mbt_print()とmbt_input()の関数のプロトタイプ宣言だけを削除することにする。
Copyright © 2001 Hiroshi Masuda |