再開です。
しかし、学校から大きな課題が出るたびに一か月も進行を止めていてはこの先が思いやられます。どうすればよいのでしょうね。
そんなわけで久しぶりのコンパイラ制作学習です。
衝動的にflexなるものを使ってみたくなったので使ってみました。もはや学習プロセスもへったくれもありません。やりたい放題です。
まずはflexのインストールですが、
ここからダウンロードしたものは私の環境で動きました。bison,flexは変な所からダウンロードすると動かなかったりするので一応(ダウンロード場所が問題なのではないと思いますが)。
さて、とりあえず[数値リテラル,変数,=,+,-,*,/,;]を識別させたいなと思い、
解説サイトを参考に見よう見まねで書いてみます。
► スポイラーを表示
CODE:
%{
#include
#include
%}
nonzero [1-9]
digit [[:digit:]]
wspace [[:blank:]]
alpha [[:alpha:]]
alnum [[:alnum:]]
integer ({nonzero}{digit}*)|0
variable [_[:alpha:]][_[:alnum:]]*
%%
{integer}
{
printf("found integer\n");
/*
next_location();
yylloc.last_column += yyleng;
yylval = atof(yytext);
//*/
return num_literal_token;
}
{variable}
{
printf("found variable\n");
/*
next_location();
yylloc.last_column += yyleng;
//*/
return variable_token;
}
=
{
printf("found '='\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '=';
}
\+
{
printf("found '+'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '+';
}
-
{
printf("found '-'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '-';
}
\*
{
printf("found '*'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '*';
}
\/
{
printf("found '/'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '/';
}
;
{
printf("found ';'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return ';';
}
>
{
printf("finished\n");
return 0;
}
%%
int main(void)
{
return yylex();
}
しかし、無慈悲にも大量のエラーを叩き付けられます。
warning, rule cannot be matched
warning, rule cannot be matched
warning, rule cannot be matched
warning, rule cannot be matched
warning, rule cannot be matched
このエラー一色です。
血のにじむような検証の結果、{を始める前に改行を入れてはいけないのだということがわかりました。
つまり下記のようにしないといけないわけですね。
► スポイラーを表示
CODE:
%{
#include
#include
%}
nonzero [1-9]
digit [[:digit:]]
wspace [[:blank:]]
alpha [[:alpha:]]
alnum [[:alnum:]]
integer ({nonzero}{digit}*)|0
variable [_[:alpha:]][_[:alnum:]]*
%%
{integer} {
printf("found integer\n");
/*
next_location();
yylloc.last_column += yyleng;
yylval = atof(yytext);
//*/
return num_literal_token;
}
{variable} {
printf("found variable\n");
/*
next_location();
yylloc.last_column += yyleng;
//*/
return variable_token;
}
= {
printf("found '='\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '=';
}
\+ {
printf("found '+'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '+';
}
- {
printf("found '-'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '-';
}
\* {
printf("found '*'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '*';
}
\/ {
printf("found '/'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return '/';
}
; {
printf("found ';'\n");
/*
next_location();
yylloc.last_column += 1;
//*/
return ';';
}
> {
printf("finished\n");
return 0;
}
%%
int main(void)
{
return yylex();
}
生粋のC言語プログラマーですから、{の前に改行を入れるかどうかは好みの問題だと思っていました。
flexのこの衝撃の仕様に気づくのに、今日の活動時間を丸々費やしました。
もう笑うしかないですね。
それにしても、最近しみじみと思います。
「やっぱ実践あるのみだな」
と。
漠然と「~を学習しよう」とか考えながらただただ教科書を読んでいても、ちっとも頭に入ってこない・覚えられない・すぐ忘れてしまうものです。
「へーそうなんだ」
で終わってしまうんですよね。
だから「ここがこうでこうなっててこ~んな作品をつくる!」って決めてその実現のために足りない知識を補うという形で学習してゆくスタイルが最も良いのではないかと思うわけですよ。
と、いうわけで!
まずはどんな作品を作るのかを決定します。
もちろん最終的な作品としては俺言語のコンパイラということになるのですが、とりあえず最初は簡単そうな作品(目標)を設定します。
「(代入、加算、減算、乗算、除算)の式が文法に沿っているか判定する」
です!
変数の使用を想定していますが、事前に宣言したりといったことは必要ありません。
少し面倒そうだということと、文法に沿っているかどうかを判定することだけが目的だからです。
これで、目標を達成するために学習が捗ることでしょう。
現在はflexのコンパイルが通っただけで動作テストはしていませんから、次回は動作テストからですね。
張り切っていきましょう!
それでは、良いプログラミングライフを!