- ベストアンサー
flex+bisonで簡単なパーサの作成方法とは?
- flexとbisonを使用して簡単な設定ファイルパーサを作成する方法について教えてください。
- bisonで$1, $2などの値が正しく出力されない問題について、どこが原因か教えてください。
- 作成したパーサを実行した際に、期待した出力と異なる結果が出力される問題について、対処方法を教えてください。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
最終的にどういうパーサーを作りたいのかわからないのでちと外しているかもしれませんが > レクサがトークンをstrcatせず(終端文字を残したまま)連結したものを > 使うことはできないんでしょうかねえ。。。と無駄なことを考えてしまいま した。 メモリの消費を抑えたいというのであれば、aaaのような名前は 記号表に登録してその結果を返すようにし、= のような記号は yylval.str_value = "=" のように固定の文字列のアドレスを入れちゃえばどうでしょう? 1234のような定数は yylvalに数値定数を保持するメンバーを増やして それに格納するようにするとか。 yaccをつかったインタプリタはソースが結構見つかると思うので 参考にしてみてはどうでしょう?
その他の回答 (1)
- sakusaker7
- ベストアンサー率62% (800/1280)
flexではなくlexを使うと明確にわかるのですが、yytextはトークンごとに 別の領域を確保するということはしません(extern char yytext[]と宣言される)。 assign: noeq_exp EQ exp_l { printf("<assign>%s|%s|%s\n", $1, $2, $3); printf("address: $1=%p, $2=%p, $3=%p\n", $1, $2, $3); } のようにしてアドレスをチェックするとよくわかると思います。 私の環境では address: $1=0x661f88, $2=0x661f8b, $3=0x661f8c のようになりました。 ということで、お手軽に済ませるには %% [=:] yylval.str_value=strdup(yytext); return EQ; [^=:\t\n]+ yylval.str_value=strdup(yytext); return TOKEN; [ \t]+ yylval.str_value=strdup(yytext); return WS; \n yylval.str_value=strdup(yytext); return CR; %% トークンごとに別の領域を確保してそこにコピーしましょう。
お礼
なるほど。パーサの方はトークンとしてそれぞれヌル終端された文字列を期待しているのに、上のようなレクサのコードでは一連のトークンをstrcat済みの単一バッファ上のトークンごと先頭ポインタが渡されているだけってことですか。。。しかし、トークン毎にいちいちメモリ領域を確保するのは無駄なことですねえ。レクサがトークンをstrcatせず(終端文字を残したまま)連結したものを使うことはできないんでしょうかねえ。。。と無駄なことを考えてしまいました。意外とうまくいきそうな気がするんですが、たぶん気のせいでしょう^^。 とても勉強になりました。有難うございました。
お礼
たびたびご回答いただき恐縮です。私が思ったのは、lex.yy.cでマッチしたトークンを次々とバッファに突っ込んでいるループで(ソースを見たところ、一時的に終端文字を入れたあと、ループ冒頭で終端文字を上書きして消してしまっています)終端文字を消さないように残したままにすれば、のちにパーサのアクションコードから'$1'などでトークンを文字列として参照したときに、うまくいくのではないかということです。で、そのようにいじってみましたら、やっぱり二番めのトークンを正しく認識できずエラーになってしまいました。いまはどうして二番め以降がエラーになるのかを知りたいと思っていますが、どうもまだ全体の仕組みすらよく分かっていない状態ですんで、たぶん高い確率で挫折すると思います^^。 要するに、生意気にもflexとbisonの動作を変更しようと思っていたわけですがそんなに簡単じゃないですね当然。ご紹介の方法も含めてユーザとしての工夫を考えるのが第一でした。 どうもありがとうございました。