C言語-インタプリタminiBASIC
前へ 目次へ 次へ 

 11. 条件分岐 IF - ELSEIF - ELSE - ENDIF

@ IF文の条件1が真のときプログラムAを実行し、ENDIF文の次の行に移る。
A IF文の条件1が偽で、ELSEIF文の条件2が真のときプログラムBを実行し、ENDIF文の次の行に移る。
B IF文の条件1、ELSEIF文の条件2が偽のときELSE文以降のプログラムCを実行し、ENDIF文の次の行に移る。

 プログラムでは、フラグ(目印)用の変数(if_flag)を用意し、条件1が真のときif_flagを1にし、次の文を実行していく。そして、ELSEIF文でif_flag=1のときENDIF文 - 1まで飛ばし、if_flag=0のとき条件2を判定し、if_flagを設定する。
 同様にして、フラグ変数if_flagを、条件が真のときは1、偽のときは0、その他(IF-ENDIFの範囲外)では-1として各文を処理する。



 条件式(条件1,条件2等)の計算は、関数logicを使用する。
 条件によってELSEIF,ELSE,ENDIFに飛ばす処理で、プログラムリスト(配列list)と最終行(last)のデータが必要になる。関数の引数として渡す方法もあるが、ここではグローバル変数に変更する。

int mb_if(int 現在行)
{
    if IF-ENDIFブロック内
        二重IF文エラー
    次のトークン(条件)取得
    条件式の結果を得る
    if 結果が1である
        if_flagを1に設定
    else
        if_flagを0に設定
        ELSEIF-1,ELSE-1またはENDIF-1まで
            飛ばし、現在行を設定する
    現在行を返す
}
int mb_elseif(int 現在行)
{
    if IF-ENDIFブロック外
        文法エラー
    if if_flagが1である
        ENDIF-1まで飛ばし、現在行を設定
    else
        次のトークン(条件)取得
        条件式の結果を得る
        if 結果が1である
            if_flagを1に設定
        else
        if_flagを0に設定
        ELSEIF-1,ELSE-1またはENDIF-1まで
            飛ばし、現在行を設定する
    現在行を返す
}
int mb_else(int 現在行)
{
    if IF-ENDIFブロック外
        文法エラー
    if if_flagが1である
        ENDIF-1まで飛ばし、現在行を設定
    else
        if_flagを1に設定
    現在行を返す
}
int mb_endif(int 現在行)
{
    if IF-ENDIFブロック外
        文法エラー
    if_flagを1に設定
    現在行を返す
}
[mb_cmds6.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:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:

175:
176:
177:

185:
186:
187:

209:
210:
211:

236:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gettoken.h"
/* 関数プロトタイプ宣言 外部参照 */
extern double logic(void);      /* eval.c */
/* グローバル変数 */
extern double  hensuu[26];      /* 変数用(A〜Z) */
extern int     for_ln;          /* FOR  の行番 */
extern int     next_ln;         /* NEXT の行番 */
extern int     if_flag;         /* IF フラグ */
extern int     last;            /* 最終行 */
extern char    *list[100];      /* プログラムリスト用 */

int mb_if(int ln)
{
    double      ans;
    int         n;

    if(if_flag != -1){      /* 二重if文の禁止 */
        printf("IF-ENDIFブロックの中にIF文があります\n");
        exit(1);
    }
    get_token();            /* 次のトークン(条件)取得 */
    ans = logic();          /* 条件式の計算 */
    if(ans == 1.0)          /* 条件 真 */
        if_flag = 1;
    else{                   /* 条件 偽 */
        if_flag = 0;
        /* 次のESLEIF, ELSEまたはENDIFまで飛ばす */
        for(n = ln + 1; n < last; ++n){     /* 次の行から最終行まで調べる */
            strcpy(gt_line, list[n]);
            get_token();            /* 先頭のトークン取得 */
            if(!strcmp(token, "ELSEIF") || !strcmp(token, "ELSE") ||
               !strcmp(token, "ENDIF")){
                ln = n - 1;         /* 現在行をELSE等の行番号-1に設定 */
                break;
            }
        }
        if(n == last){          /* 最終行までELSE等がない */
            printf("対応するELSEIF, ELSE, ENDIFがありません\n");
            exit(1);
        }
    }
    return(ln);
}
int mb_elseif(int ln)
{
    double      ans;
    int         n;
    
    if(if_flag == -1){      /* IF-ENDIFブロック外 */
        printf("IF-ENDIFブロックの外にELSEIF文があります\n");
        exit(1);
    }
    if(if_flag == 1){       /* if,elseifが真の時、次のENDIFまで飛ばす */
        for(n = ln + 1; n < last; ++n){     /* 次の行から最終行まで調べる */
            strcpy(gt_line, list[n]);
            get_token();                /* 先頭のトークン取得 */
            if(!strcmp(token, "ENDIF")){
                ln = n - 1;             /* 現在行をENDIFの行番号-1に設定 */
                break;
            }
        }
        if(n == last){          /* 最終行までENDIDがない */
            printf("対応するENDIFがありません\n");
            exit(1);
        }
    }else{                  /* 偽の時、条件を判定 */
        get_token();            /* 次のトークン(条件)取得 */
        ans = logic();          /* 条件式の計算 */
        if(ans == 1.0)          /* 条件 真 */
            if_flag = 1;
        else{                   /* 条件 偽 */
            if_flag = 0;
            /* 次のESLEIF, ELSEまたはENDIFまで飛ばす */
            for(n = ln + 1; n < last; ++n){     /* 次の行から最終行まで調べる */
                strcpy(gt_line, list[n]);
                get_token();            /* 先頭のトークン取得 */
                if(!strcmp(token, "ELSEIF") || !strcmp(token, "ELSE") ||
                   !strcmp(token, "ENDIF")){
                    ln = n - 1;         /* 現在行をELSE等の行番号に設定 */
                    break;
                }
            }
            if(n == last){          /* 最終行までELSE等がない */
                printf("対応するELSEIF, ELSE, ENDIFがありません\n");
                exit(1);
            }
        }
    }
    return(ln);
}
int mb_else(int ln)
{
    int         n;
    
    if(if_flag == -1){      /* IF-ENDIFブロック外 */
        printf("IF-ENDIFブロックの外にELSE文があります\n");
        exit(1);
    }
    if(if_flag == 1){       /* if,elseifが真の時、次のENDIFまで飛ばす */
        for(n = ln + 1; n < last; ++n){     /* 次の行から最終行まで調べる */
            strcpy(gt_line, list[n]);
            get_token();                /* 先頭のトークン取得 */
            if(!strcmp(token, "ENDIF")){
                ln = n - 1;             /* 現在行をENDIFの行番号-1に設定 */
                break;
            }
        }
        if(n == last){          /* 最終行までENDIDがない */
            printf("対応するENDIFがありません\n");
            exit(1);
        }
    }else                   /* 偽の時 */
        if_flag = 1;
    return(ln);
}
int mb_endif(int ln)
{
    if(if_flag == -1){      /* IF-ENDIFブロック外 */
        printf("IF-ENDIFブロックの外にENDIF文があります\n");
        exit(1);
    }
    if_flag = -1;
    return(ln);
}
int mb_for(int ln)
{
<<省 略>>
}
int mb_next(int ln)
{
<<省 略>>
}
void mb_print(void)
{
<<省 略>>
}
void mb_input(void)
{
<<省 略>>
}
[mbas10.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:

67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91: 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "gettoken.h"
/* 関数プロトタイプ宣言 */
extern void mb_print(void);
extern void mb_input(void);
extern int mb_for(int);
extern int mb_next(int);
extern int mb_if(int);
extern int mb_elseif(int);
extern int mb_else(int);
extern int mb_endif(int);
extern double logic(void);  /* eval.c */
/* グローバル変数 */
double  hensuu[26];         /* 変数用(A〜Z) */
int     for_ln = -1;        /* FORとNEXTの行番 */
int     next_ln = -1;
int     if_flag = -1;       /* IF フラグ */
char    *list[100];         /* プログラムリスト用 */
int     last;               /* 最終行 */

void main(int argc, char *argv[])
{
<<省 略>>
        else if(!strcmp("NEXT", token))
            now = mb_next(now);
        else if(!strcmp("IF", token))
            now = mb_if(now);
        else if(!strcmp("ELSEIF", token))
            now = mb_elseif(now);
        else if(!strcmp("ELSE", token))
            now = mb_else(now);
        else if(!strcmp("ENDIF", token))
            now = mb_endif(now);
        else if(!strcmp("REM", token))
            printf("REM 命令です\n");
        else if(isalpha(*token)){       /* 変数(先頭が英字)チェック */
            valnum = *token - 'A';      /* 変数番号記憶 */
            get_token();
            if(*token != '='){
                printf("代入文が正しくありません\n");
                exit(1);
            }
            get_token();
            hensuu[valnum] = logic();   /* 計算式処理 */
        }else
            printf("命令以外です\n");
    }
}

 21,22行目の変数lastと配列listの宣言はmain()から関数外に移動してグローバル変数にしている。したがって、main()内にある変数lastと配列listの宣言は削除する。

reidai8.mb
INPUT "IF A=12.34 ? A=",A
IF A=12.34 THEN
    PRINT "A=12.34"
ELSE
    PRINT "Not A=12.34"
ENDIF
INPUT "DATA A=",A
INPUT "DATA B=",B
IF A=B THEN
    PRINT "A=B"
ELSEIF A<B THEN
    PRINT "A<B"
ELSE
    PRINT "A>B"
ENDIF
END
実行結果
D:\Data\src>make
lcc  -c -o mbas10.obj mbas10.c
lcc -o mbas.exe  mbas10.obj  mb_cmds6.obj gettoken.obj eval2.obj
lld @link.i
D:\Data\src>mbas reidai08.mb
IF A=12.34 ? A=12.34
A=12.34
DATA A=12.34
DATA B=12.35
A<B
終了します
D:\Data\src>mbas reidai08.mb
IF A=12.34 ? A=-12.34
Not A=12.34
DATA A=12.34
DATA B=-12.34
A>B
終了します
D:\Data\src>mbas reidai08.mb
IF A=12.34 ? A=12.340001
Not A=12.34
DATA A=123.45
DATA B=123.45
A=B
終了します


前へ 目次へ 次へ 
Copyright © 2001 Hiroshi Masuda 

 

 

inserted by FC2 system