カテゴリー
コンピュータ言語

コンパイラの構成~プログラミング言語を作りたい(再)④~

前回は、コンパイラの主な構成を簡単に説明しました。今回はコンパイラの初めの部分である①字句解析部に焦点を当てていきたいと思います。ようやくプログラミング的なものも出てきます。今回の内容は「コンパイラ入門」(山下義行著 サイエンス社)を参考にしています。

 繰り返しになりますが、①字句解析部とは、入力されたプログラムを文法上の基本単位であるトークン(字句)に分解・分類するシステムです。自作することもできますが、今回は便利な字句解析器自動生成ツールであるlex(flex)を使用していきます。

 lex(flex)は、lex(flex)用のプログラム(.lファイル)の中でトークン(字句)を正規表現で定義することで、それらの字句を識別するC言語プログラムファイル(.cファイル)を生成してくれます。このC言語プログラムをコンパイルしてできた実行ファイルを字句解析部として用いることができます。

lex(flex)用のプログラムの記述は、以下のような部分に分かれています。

 宣言部
 %%
 正則表現部
 %%
 プログラム部

 宣言部は正則表現、プログラム部で使用する変数・関数・マクロなどを宣言する場所です。正則表現部にはトークン(字句)に対応する正則表現とそれが認識された時に実行される動作を記述し、プログラム部には字句解析で使用する補助関数を記述する場所です。

 例えば非常に雑な英文の字句解析器(主語と動詞と名詞らしきものを識別してくれる)を作成するlex(flex)用のプログラム(sample.l)は以下のような記述になります。

%{
enum {SUB=1,VERB, NOUN, COMMA, EX, QU, ERROR};

#include <stdio.h>

int yywrap(void){
	return 1;
}

%}
%%

I|She|He|You|It|They|We 		{return SUB; }
is|am|are|were|was|be|being|been|do|does|did|have|has|had	{ return VERB; }
[a-z]+|[A-Z][a-z]*			{ return NOUN; }
"!"					{ return EX; }
"?"					{ return QU; }
"\n"|" "|"\t"				{ }
.					{ return ERROR; }
%%

int main(void){
	int t;
	while((t=yylex()) != 0){
		printf("number =%d, string = '%s'\n",t,yytext);
	}

}
           
宣言部

 宣言部は最上部の%{と%}で囲まれた部分を言います。今回のプログラムでは以下の部分です。enumによってSUBなどの列挙定数に順序整数値を割り当てていたり、入力列全体を読み終えたときに実行される関数yywrap()の定義をしたりしています。

%{
enum {SUB=1,VERB, NOUN, COMMA, EX, QU, ERROR};

#include <stdio.h>

int yywrap(void){
	return 1;
}

%}
正則表現部

 正則表現部は中段の部分に当たります。一列に一つのトークンに対応する正則表現(左)とそれを認識した時の動作(右の{}の中)を記述するような形になっています。例えば今回の例では、字句解析を実行する関数yylex()がIやSheを認識した時にはSUBを、isやamを認識した時はVERBを返すようになります。

I|She|He|You|It|They|We 		{return SUB; }
is|am|are|were|was|be|being|been|do|does|did|have|has|had	{ return VERB; }
[a-z]+|[A-Z][a-z]*			{ return NOUN; }
"!"					{ return EX; }
"?"					{ return QU; }
"\n"|" "|"\t"				{ }
.					{ return ERROR; }

 また、三行目の[a-z]+|[A-Z][a-z]*は正則表現と呼ばれるもので、ある文字列の特徴を抽象的に表したものです。[a-z]+はaからzの文字が一つ以上並んだ文字列を表し、[A-Z][a-z]*は頭の一文字がAからZでその後にaからzの文字が0個以上続く文字列のことを表しています。このような正則表現を用いることで、特定の条件を満たす文字列を一つのトークンとして認識することが可能になります。

プログラム部

プログラム部は以下の部分となります。

int main(void){
	int t;
	while((t=yylex()) != 0){
		printf("number =%d, string = '%s'\n",t,yytext);
	}

}

今回のプログラムでは、字句解析関数yylexの返り値が0になるまで(入力列の末尾に到達するまで)字句解析を実行し、また、字句を読み取るたびに読み取った字句(yytext)と対応する整数値(SUBやVERB等)を出力してくれます。

 このように作成したプログラムをlex(flex)でC言語プログラムファイルに変換し、コンパイルを実施すると字句解析の実行ファイルを得ることができます。

 今回はざっくりと字句解析器自動生成ツールのlex(flex)の使い方を説明しました。正則表現部でのトークンの指定がプログラミング言語の外見を決めることになるかと思いますので、ここも重要なところですね。

 今回はこんなところでした。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です