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

 3. 字句解析

reidai01.mb
INPUT "Teihen=",t
INPUT "Takasa=",h
s = t * h / 2
PRINT "Menseki=";s
END

 1行のプログラムを意味のある単語に分解する必要がある。例えば、reidai01.mbの1行目INPUT "Teihen=",tは、INPUT と "Teihen=" と , と tに分解する。分解された単語(語句)をトークンといい、この処理を字句解析という。
 最初のトークン(INPUT)で何の命令かを判定し、各命令ごとの処理を行う。
 トークンに分解する関数get_tokenは作成済みであるので、ホームディレクトリに用意してから利用する。ファイル名は、gettoken.cgettoeken.hとする。
 さらにコンパイルして、オブジェクトファイルを作成しておく。

cc -c gettoken.c

[get_tokenの使い方]
 関数get_tokenの使い方は、次のとおりである。
 @ 1行分のデータをグローバル変数gt_lineにコピーする。
 A 関数get_tokenを呼び出す。
  グローバル変数tokenに最初のトークンが格納される。
 関数get_tokenの返却値は、グローバル変数tokenの先頭アドレスである。
 関数get_tokenを呼び出すごとに次のトークンを取り出すことができる。取り出すトークンが無くなったときは、ナルが格納される。

 次のプログラムは、キーボードから入力した文字列を字句解析し、トークンごとに( )で囲んで表示する。

[[test02.c]
 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
12:
13:
14:
15:
#include <stdio.h>
#include <string.h>
#include "gettoken.h"       /* 関数get_token用定義 */

void main(void)
{
    char    buff[256];

    printf("文字列 : ");
    gets(buff);

    @          ;          /* 字句解析の準備 */
    while(*get_token() != '\0')     /* トークン取得 */
        printf("(%s)",A       );
}
[解答欄] (すべて半角文字で、空白文字もチェックされます。)
@    A
     
実行結果
D:\Data\src>cc test02.c gettoken.obj    ←コンパイル
lld @link.i
D:\Data\src>test02    ←実行
文字列 : word 123test,text001. my language is "MB".
(word)(123)(test)(,)(text001)(.)(my)(language)(is)("MB)(.)




 関数get_tokenを使用して、読み込んだプログラムをトークンに分解して表示する処理を追加する。
 各行のデータは、ポインタ配列listに格納されているので、これをグローバル変数gt_lineにコピーし、トークンに分解しながら表示する。これを最終行まで繰り返す。

[mbas02.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:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gettoken.h"
void main(int argc, char *argv[])
{
    char    *list[100];     /* プログラムリスト用 */
    char    buff[256];      /* 1行読み込み用 */
    FILE    *fp;            /* ファイルポインタ */
    int     now = 0;        /* 行数カウント */
    int     last;           /* 最終行 */

    if(argc != 2){          /* ファイル名指定なし */
        printf("ファイル名の指定がありません\n");
        exit(1);                /* 強制終了 */
    }
    /* ファイルのオープン */
    if((fp = fopen(argv[1], "r")) == NULL){
        printf("ファイルがオープンできません\n");
        exit(1);
    }
    /* ファイルの読み込み */
    while(fgets(buff, 256, fp) != NULL){        /* 1行読み込み */
        list[now] = (char *)malloc(strlen(buff) + 1);   /* 領域確保 */
        if(list[now] == NULL){
            printf("領域確保に失敗しました\n");
            exit(1);
        }
        strcpy(list[now], buff);    /* 確保した領域にデータコピー */
        ++now;
    }
    last = now;         /* 最終行番を格納 */
    /* ファイルのクローズ */
    fclose(fp);
    /* 読み込んだリスト表示 */
    for(now = 0; now < last; ++now){
        strcpy(gt_line, list[now]);     /* 字句解析の準備 */
        while(*get_token() != '\0')     /* トークンの取得 */
            printf("(%s)", token);
    }
}
実行結果
D:\Data\src>cc mbas02.c gettoken.obj
lld @link.i
D:\Data\src>mbas02 reidai01.mb
(INPUT)("Teihen=)(,)(t)(
)(INPUT)("Takasa=)(,)(h)(
)(s)(=)(t)(*)(h)(/)(2)(
)(PRINT)("Menseki=)(;)(s)(
)(END)(
)

 リストmbas02.cの青色部分が追加・修正した部分である。
 関数get_token()を使うために #include "gettoken.h" を追加し、コンパイル(実行結果)するときにはgettoken.cまたはgettoken.objとともにコンパイルする。

 トークン(単語)単位で表示する部分(36〜40行)では、字句解析の準備として、次のように読み込んだリストのnow行目をgt_lineにコピーする。

strcpy(gt_line, list[now]);

 関数get_token()を繰り返し呼び出し、トークンを取り出して表示する。取り出したトークンはグローバル変数tokenに記憶されている。トークンとして"\0"が取り出されるまで繰り返す。"\0"が取り出されると1行分が終わったことになる。

while(*get_token() != '\0') while(strcmp(get_token(), "\0")) でも良い。
while(*get_token())


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

 

 

inserted by FC2 system