前回の予告通り、今回は行番号を明示してくれるようにグレードアップです!
bisonに@xという構造体もどきが用意されていて、[始まりの行、終わりの行、始まりの列、終わりの列]の4つのメンバ変数を持ちます。
私達はここに手動で現在の探査位置を格納してゆき、必要なときに取り出します。
実は手動で格納する部分は既に書き込まれていたりします。コメントアウトされてはいますが。
今回、列情報は使いませんが、念のため格納しておきましょう。
そんなわけで各ソースコードは次のようになりました。
flex
► スポイラーを表示
CODE:
%{
#include
#include
#include "basic_basic_bison.h"
#pragma warning(disable:4996)
extern YYLTYPE yylloc;
void next_location(void);
%}
nonzero [1-9]
digit [[:digit:]]
wspace [[:blank:]]
wspaces {wspace}+
alpha [[:alpha:]]
alnum [[:alnum:]]
integer ({nonzero}{digit}*)|0
variable [_[:alpha:]][_[:alnum:]]*
%%
{integer} {
printf("flex info : found integer\n");
next_location();
yylloc.last_column += yyleng;
return num_literal_token;
}
{variable} {
printf("flex info : found variable\n");
next_location();
yylloc.last_column += yyleng;
return variable_token;
}
= {
printf("flex info : found '='\n");
next_location();
yylloc.last_column += 1;
return '=';
}
\+ {
printf("flex info : found '+'\n");
next_location();
yylloc.last_column += 1;
return '+';
}
- {
printf("flex info : found '-'\n");
next_location();
yylloc.last_column += 1;
return '-';
}
\* {
printf("flex info : found '*'\n");
next_location();
yylloc.last_column += 1;
return '*';
}
\/ {
printf("flex info : found '/'\n");
next_location();
yylloc.last_column += 1;
return '/';
}
; {
printf("flex info : found ';'\n");
next_location();
yylloc.last_column += 1;
return ';';
}
\n {
next_location();
++yylloc.last_line;
yylloc.last_column = 0;
}
wspaces {
yylloc.last_column += yyleng;
}
> {
printf("\n\ncompile completed!\n");
return 0;
}
%%
int yywrap(void)
{
return 1;
}
int main(void)
{
/* 構文解析関数 yyparse */
yyin = fopen("testcode.txt", "r");
yyparse();
getchar();
return 0;
}
void next_location(void)
{
yylloc.first_line = yylloc.last_line;
yylloc.first_column = yylloc.last_column + 1;
}
bison
► スポイラーを表示
CODE:
%defines
%{
#include
#include
#include
//#define YYSTYPE double
void yyerror(const char* s);
int yylex(void);
%}
%token num_literal_token
%token variable_token
%%
input : /* empty */ { printf("bison info : found input\n"); }
| input line { printf("bison info : found input\n"); }
;
line : formula ';' { printf("bison info : found line\n"); }
| ';' { printf("bison info : found line\n"); }
| error ';' { printf("bison error (%d) : wrong formula\n", @1.first_line); }
;
formula : variable_token '=' formula { printf("bison info : found formula\n"); }
| num_literal_token '=' formula { printf("bison error (%d) : left-hand side must variable\n", @1.first_line); }
| formula binary_operator formula { printf("bison info : found formula\n"); }
| variable_token { printf("bison info : found formula\n"); }
| num_literal_token { printf("bison info : found formula\n"); }
;
binary_operator : '+' { printf("bison info : found binary_operator\n"); }
| '-' { printf("bison info : found binary_operator\n"); }
| '*' { printf("bison info : found binary_operator\n"); }
| '/' { printf("bison info : found binary_operator\n"); }
;
%%
/* エラー表示関数 */
void yyerror(const char* s)
{
/* Nothing */
}
テスト用コード
さらっとテストしてみた限りでは、どうやらこれで大丈夫そうです。期待通りに動いてくれています。
というわけで、flex,bisonテスト用のコンパイラ(文法チェックマシン)はこれで完成です。
basic_basic(仮)と命名しておきます。
バージョンは0x0です。
下のリンクからダウンロード可能です。
とりあえずflexとbisonの使い方は そこそこ わかりました。
次回からはLemonというパーサ(構文解析器)の使い方を模索してゆきます。
それでは、良いプログラミングライフを!