C言語-インタプリタminiBASIC |
3. 字句解析
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.cとgettoeken.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 ); } |
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 |