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

 5. 命令を1行で書けるようにする

 これまでは、命令語と計算に使用するデータを、それぞれ1行ずつに書いた。これではプログラムらしくないので、1行に書けるようにする。
 命令文を1行に書いた場合、それぞれ、意味のある単位で語句を取り出さなければならない。これを字句解析という。
 例えば、mc(miniCASL)言語のプログラムを次のように記述する。

add 123.4 211.2

 この場合、空白で区切られた"add", "123.4", "211.2"の3つの語句に分解しなければならない。この処理をする関数get_tokenを利用してプログラムを作成すると簡単である。関数get_token(gettoken.c)は、標準関数ではなく、この課題研究用に作成したものである。使用するには、#include "gettoken.h"が必要である。

#include "gettoken.h";
char *get_token(void);

 グローバル変数char *gt_line;に文字列(MAX=256文字)を格納しておき、関数get_tokenを呼び出すとグローバル変数char *token;に取り出された単語が格納されて戻ってくる。返却値は、取り出した単語の先頭アドレス(tokenの先頭アドレス)である。

 グローバル変数とは、プログラム中のどこでも利用可能な変数と考えればよい。

 例えば、次の計算式がグローバル変数gt_lineに格納されているとする。

2.1 + 3 + 4.33 + 5e2

 最初にget_token()を呼び出すと、変数tokenには、2.1が格納される。次に呼び出すと空白は無視されて+3が格納される。次に +4.33, +5e2 と順に格納され、最後は\0(ナル)が格納される。
 このように、

[mc06.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:

34:
35:

40:
41:

46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "@          "

#define STRMAX 80       /* 文字列配列の大きさ */

void main(int argc, char *argv[])
{
    double  data1, data2, ans;
    FILE    *fp;        /* ファイル操作用 */

    if(argc != 2){      /* パラメータのチェック */
        printf("使い方:MC filename\n");
        exit(1);
    }
    if((fp = fopen(argv[1], "r")) == NULL){     /* ファイルのオープン */
        printf("ファイルがオープンできませんでした。\n");
        exit(1);
    }
    while(fgets(gt_line, STRMAX, fp)){     /* データの読み込み */
        A            ;
        if(!strcmp(token, "add")){    /* 命令判定 */
            A            ;                /* 1語取り出し */
            data1 = atof(B        );    /* 実数値に変換 */
            A            ;
            data2 = atof(B        );
            ans = data1 + data2;
        }else if(!strcmp(token, "sub")){
            <<赤色の部分(24〜27行)と同じ>>
            ans = data1 - data2;
        }else if(!strcmp(token, "mul")){
            <<赤色の部分(24〜27行)と同じ>>
            ans = data1 * data2;
        }else if(!strcmp(token, "div")){
            <<赤色の部分(24〜27行)と同じ>>
            ans = data1 / data2;
        }else if(!strcmp(token, "end")){
            break;
        }else{
            printf("Error : コマンドエラー\n");
            continue;
        }
        printf("%f\n", ans);            /* 結果表示 */
    }
    fclose(fp);         /* ファイルのクローズ */
}
実行結果
D:\Data\src>cc mc06.c gettoken.obj
lld @link.i
D:\Data\src>mc06 reidai02.mc
23.450000
12.340000
123.400000
-2.345000
[解答欄] (すべて半角文字で、空白文字もチェックされます。)
@   A   B
     
reidai02.mc
add 12.34 11.11
sub 23.45 11.11
mul 12.34 10
div 23.45 -10
end

 21行目while文の中で1行読み込みをしている。関数fgets()はファイルfpから読み込むデータがなくなったとき0を返却するのでwhile文の繰り返しを終了する。mc言語のプログラム中にend命令がなくても終了する。
 1行のデータ(文)を単語に分解する関数get_token()を使うためヘッダファイルgettoken.hをインクルードしている。この中で1行のデータを記憶させるグローバル変数gt_lineが宣言されているので、1行読み込みの関数fgets()の中でgt_lineに読み込んでいる。したがって、配列buffは不要になる。


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

 

 

inserted by FC2 system