をしてる。
これ。
今わかった所までの覚え書き。
● 近況
youtubeへは下記をアップロード。
ゲームのメインループをクラスに切り出してみたという話。
● で、いよいよ次は
スクリプトの解析をする処理。アドベンチャーゲームだから。
シナリオを書いたテキストファイルを読み込んで、ゲームを動かしてみたい。
で現状下記がボツに。
というわけで自分でつくることにした。
● スクリプトファイルを
単語単位に分けるのがflex。
fade 0 画面の輝度を0に load "awesome.jpg" 背景画像をロード fade 0 to 100 in 500 画面の輝度を0から100%まで500ミリ秒で wait ユーザ入力を待つ
こういうのを。
fade 0 load awesome.jpg fade 0 to 100 in 500 wait
こういう風に直してくれるのがflex。
ありがとうflex。
● これやるためのflexコードが
こんな感じ。
%{ #include "myparser.tab.h" %} %% <INITIAL>"fade" { return FADE; } <INITIAL>"load" { return LOAD; } <INITIAL>"to" { return TO; } <INITIAL>"in" { return IN; } <INITIAL>"wait" { return WAIT; } <INITIAL>[0-9]+ { yylval.integer_value = atoi(yytext); return INT_VALUE; } <INITIAL>[ \t] { } <INITIAL>"\"" { yylval.string_literal[0] = '\0'; BEGIN _LITERAL; } <_LITERAL>"\"" { BEGIN INITIAL; return STR_LITERAL; } <_LITERAL>. { strcat(yylval.string_literal, yytext); } %%
flexにお願いするとこれを元に、C言語のコードを生成してくれる。
そのC言語のコードの冒頭あたりに
#include "myparser.tab.h"
が挿入される。
また、
<INITIAL>"fade" { return FADE; }
と書いておくと、
入力されたファイルの中に「fade」という単語が見つかったら、「return FADE;」を実行するようなC言語のコードが生成される感じだ。
このときFADEは記号定数だが、宣言部分を生成してくれるのはbison。
● bisonの方のコードが
これで
%{ #include "stdio.h" extern int yylex(); extern int yyerror(char *); %} %union { int integer_value; char string_literal[2048]; } %token FADE LOAD TO IN WAIT %token <integer_value> INT_VALUE %token <string_literal> STR_LITERAL %% program : /* empty or.. */ | program command ; command : FADE INT_VALUE { printf("fade to %d\n", $2); } | LOAD STR_LITERAL { printf("load the file named: '%s'\n", $2); } | FADE INT_VALUE TO INT_VALUE IN INT_VALUE { printf("fade from %d to %d in %d milli second\n", $2, $4, $6); } | WAIT { printf("ordered to wait.\n"); } ;
これの
%token FADE LOAD TO IN WAIT
ここで指定したやつが”myparser.tab.h”に
#define FADE 258 #define LOAD 259 #define TO 260 #define IN 261 #define WAIT 262 :
みたく展開される。これをさっきflexのほうで
#include "myparser.tab.h"
として読み込んでいる。
だからflexが読み込むファイルの中に
<INITIAL>"fade" { return FADE; }
とあっても、FADEがdefineされているので通る。
● あとは
mylange.c
#include <stdio.h> #include "myparser.tab.h" int yyerror(char *s) { printf("yyerror(): %s", s); return -1; } int yywrap(void) { return 1; } extern int yyparse(void); int main() { yyparse(); return 0; }
これでmain()からyyparse()を呼び出す。
yyparse()が、bisonが生成したコード(構文解析器)の処理呼び出しになっている。
yyparse()の中では、flexが生成したコード(字句解析器)の処理(単語単位で取り出す処理)を使うという寸法。
yyerror()とyywrap()はこんな感じで定義しておくらしい(いい加減)。
● 実行結果
こんな感じ。
$ ./mylang < sample.txt fade to 0 load the file named: 'awesome.jpg' fade from 0 to 100 in 500 milli second ordered to wait. $
なんか元のスクリプトと同じような出力にしてしまった・・。
けど正真正銘、字句解析器→構文解析器を通した結果出力。
● はじめ
特に理解がいかなかったのがflex生成コードと、
bisonが生成したコードの結びつき具合。
● 現在は
flexとbisonが出してくれたCコードを、
ゲームメインのC++から呼び出すときの齟齬が出ないか恐る恐るリンク中。