C言語-トランスレータ(mbas to C) |
3. 字句解析
INPUT "Teihen=", T INPUT "Takasa=", H S = T * H / 2 PRINT "Menseki="; S END |
1行のプログラムを意味のある単語に分解する必要がある。例えば、reidai.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()は、上の実行結果のように空白と記号が区切りの文字となる。さらに、単語が数字で始まっているときは数字列として数字以外の文字が現れるまでを一つの単語として取り出す。例えば"123test"は"123"と"test"に分割されて取り出される。逆に、"text001."は"text001"と"."に分割されて取り出される。
関数get_tokenを使用して、読み込んだプログラムをトークンに分解して表示する処理を追加する。
各行のデータは、ポインタ配列listに格納されているので、これをグローバル変数gt_lineにコピーし、トークンに分解しながら表示する。これを最終行まで繰り返す。
[main02.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 main02.c gettoken.obj lld @link.i D:\Data\src>main02 reidai.mb (INPUT)(A)( )(INPUT)("Teihen=)(,)(T)( )(INPUT)("Takasa=)(,)(H)( )(S)(=)(T)(*)(H)(/)(2)( )(PRINT)("Menseki=)(;)(S)( )(END)( ) |
リストmain02.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")) でも良い。
printf("(%s)", token); printf("(%s)", token);
Copyright © 2001 Hiroshi Masuda |