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)
{
<< 省略 >>
}
[解答欄] (すべて半角文字で、空白文字もチェックされます。)
@   A   B   C   D
E   F   G   H
     
FOR 変数 = 式1 TO 式2 STEP 式3
※1 ※2 ※3 ※4

 変数(※1)の番号を変数valに、式1(※2)を文字型配列shiki1に、式2(※3)を文字型配列shiki2に、式3(※4)についてはあれば文字型配列shiki3に、それぞれ記憶してからまとめて表示する。

※1  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文を表示している。
reidai4.mb
FOR A = 1 TO 5
  PRINT A;" Kai"
NEXT
FOR N=10 TO 23 STEP 6 PRINT "FOR TEST 1 = ";N NEXT
FOR N=30 TO 20 STEP -5 PRINT "FOR TEST 2 = ";N
NEXT
A = 3
FOR X = A-3 TO 10 STEP 4-2+3 PRINT "FOR TEST 3 = "; X
NEXT X
END


 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 

 

 

inserted by FC2 system