GCCのハックなんて暇な時しかしてなくて、間が空いたりすると大事なこと忘れたりとかするから、 メモしておこうと思う。何かの役に立つかもしれないし。
こんなとこ見てる暇があったら、ここを見たほうがいいと思った。
GCCの中間言語にはふたつある。、フロントエンドが プログラムをパースした結果を入れておくTREE(と呼ぶのが正しいのかどうかは知らないけど)と、 それよりも機械よりの中間言語であるRTL(Register Transfer Language)だ。
パースした結果を入れておくTREEは実はGCCで用意されたものでなくてもいい。 パースしたあとのプログラムを表現できて、かつ、そのあとでRTLに変換できるようであればなんでもいいのである。 実際、GCC内に含まれるtreelangではTREEだけじゃなくて、prodとかいう構造も自前で定義して 使ってたりするし、NLでは、標準で用意されている物ではちょっと効率悪く感じたので、 namespaceとか、自前で用意してたりする。
けど、RTLは違う。RTLはGCCの内部で機械語に変換されるから、GCCで決められた通りに 出力しないといけない。
まあ、RTLとTREEっていうのはそんな感じだ。
で、RTLの出力っていうことなんだけど、実際にはRTLの木構造を直接いじるようなことはしない。 "emit_hogehoge"っていう関数があって、まあ、それを使ってRTLを生成するようになっている。
以下が実際にCフロントエンドの中でwhile文を出力しているプログラムである。(c-decl.c)
/* Generate the RTL for T, which is a WHILE_STMT. */ void genrtl_while_stmt (tree t) { tree cond = WHILE_COND (t); emit_line_note (input_location); expand_start_loop (1); genrtl_do_pushlevel (); if (cond && !integer_nonzerop (cond)) { cond = expand_cond (cond); emit_line_note (input_location); expand_exit_loop_top_cond (0, cond); genrtl_do_pushlevel (); } expand_stmt (WHILE_BODY (t)); expand_end_loop (); }
実際にはこれ、Cフロントエンドの中のexpand_hogehogeと、GCCコア部分のexpand_hogehogeと、 Cフロントエンドのgenrtl_hogehogeと、GCCコア部分のgenrtl_hogehogeが混じってってわからないように なってるんだけど、とりあえず、RTL生成の方法を調べる時は、c-decl.c内のgenrtl_hogehogeを追っていけば わかるという感じだ、多分。と、いうか、実は僕もよくわかってないんだけど。
まあ、とにかく、Cフロントエンドの中から式を出力する部分を探すのはそんなに難しいことではない。 GCCのソース構造、TREEの構造さえわかっていれば、それほど苦ではないはずだ(断言はできないけど)。
で、いまいちわからないのが変数を表現するRTLを出力する方法だ。 IDENTIFIER_NODEが、変数の表現なのかと思っていたんだけど、 どうもそうではないらしい。 実は、変数というのは、VAR_DECLで表現されているのである。 まったくもって、騙された感じだ。VAR_DECLなんて、変数宣言の文の 中間表現だと思っちゃうよねぇ…
つまり、
3 + hogehoge
っていう式はTREE的に表現すると、
build_nt( PLUS_EXPR, build_int_2(0,3), build_decl(VAR_DECL, get_identifier("hogehoge"), integer_type_node) );
こんな感じで表現することになるのである。 (普通は変数"hogehoge"は シンボルテーブルに入ってるものを引いてきて、それを使うようにするので、 build_declはしないだろうけど)
まあ、そういうわけで、VAR_DECLは宣言じゃなくて、変数そのものなのである。 FUNC_DECLもそう、TYPE_DECLもそうなのである。で、引数がPARM_DECL。
で、変数のRTLのつくりかた。
まず、グローバル変数。 アセンブリに色々吐き出すにはrest_of_decl_compilationを使う。 RTLに変換するのは…まだ調べていない。
int foo; int bar;
ていうふうにグローバル変数を書いたとして、こいつらを
foo: size 4 bar: size 4
こういうアセンブリに変換するのが rest_of_decl_compilation の役目なのである(多分)。 ちなみに、TYPE_DECLに対しても rest_of_decl_compilation してるのは、デバッグ情報を 埋めるためだと思う。
で、グローバル変数はまあいいとして、ローカル変数だ。これがいまだによくわからない。
Cフロントエンドの中でローカル変数の宣言の中間表現を作っているのがこのへん(c-semantics.c)
void add_decl_stmt (tree decl) { tree decl_stmt; /* We need the type to last until instantiation time. */ decl_stmt = build_stmt (DECL_STMT, decl); add_stmt (decl_stmt); }
DECL_STMTがそれっぽい。で、DECL_STMTをRTLに変換してる部分が、
void genrtl_decl_stmt (tree t) { tree decl; emit_line_note (input_location); decl = DECL_STMT_DECL (t); /* If this is a declaration for an automatic local variable, initialize it. Note that we might also see a declaration for a namespace-scope object (declared with `extern'). We don't have to handle the initialization of those objects here; they can only be declarations, rather than definitions. */ if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) { /* Let the back-end know about this variable. */ if (!anon_aggr_type_p (TREE_TYPE (decl))) emit_local_var (decl); else expand_anon_union_decl (decl, NULL_TREE, DECL_ANON_UNION_ELEMS (decl)); } else if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) make_rtl_for_local_static (decl); else if (TREE_CODE (decl) == LABEL_DECL && C_DECLARED_LABEL_FLAG (decl)) declare_nonlocal_label (decl); else if (lang_expand_decl_stmt) (*lang_expand_decl_stmt) (t); }
こういうの。よくわからんけど、emit_local_varがそれっぽいだろうか。ていうか、anon_aggr_type_pって何だろう。 まあ、とにかく、こういうふうにすれば、VAR_DECLはローカル変数だとして使えるようになるんだろうか。 このへん未確認。
void emit_local_var (tree decl) { /* Create RTL for this variable. */ if (!DECL_RTL_SET_P (decl)) { if (DECL_C_HARD_REGISTER (decl)) /* The user specified an assembler name for this variable. Set that up now. */ rest_of_decl_compilation (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), /*top_level=*/0, /*at_end=*/0); else expand_decl (decl); } if (DECL_INITIAL (decl)) { /* Actually do the initialization. */ if (stmts_are_full_exprs_p ()) expand_start_target_temps (); expand_decl_init (decl); if (stmts_are_full_exprs_p ()) expand_end_target_temps (); } }
emit_local_var(c-semantics.c)の中身。 対象となるローカル変数のVAR_DECLをexpand_declすればローカル変数使えるようになるみたい。 んで、初期値が必要なら、expand_decl_initする。stmts_are_full_exprs_pはわからん。
で、あんま関係無いんだけど、1200行にも及ぶ超巨大関数"grokdeclarator"は C的にexternだとかの修飾子と関数だとか引数だとか、そういうのを何とかしてるだけで、 RTLと直接結びつく部分は特に無い(多分)。ていうか、1200行ってなんだ。 GCCはなんか、まあ、処理としてはそれなりに綺麗になってるんだけど、 小賢しい最適化したりとか、警告の処理が多すぎたりとか、そういうところのせいで 微妙に読みにくいんだよなぁ…仕方無い…のか。 まあ、その程度のコードも読めない奴がGCCに触れるなっていうことだろうか。
GGC(gcc gc)っていうのはGCC内部で使われているガーベジコレクタのことで、 発音すると、GDC(Dコンパイラ)と間違いそうになる。まあ、あんまり関係無いけど。
CでGCっていうと保守的GCしか無理だと思っていた僕の考えを見事に打ち砕く、 CにおけるGCの新しい方向性というか、そういうのを見せつけられた感じがするんだけど、 少々複雑で使うのが大変だ。
まあ、とにかく、複雑さとか、使い方とかはどうでもいいとして、 驚くべきは、GTYタグとgengtypeプログラムが協力して、 GC用のCコードを生成しちゃったりとか、gengtypeプログラム自身がCのプログラムを(簡単にだけど) パースしちゃったりしてる点だ。素敵すぎ。
struct asdf_hashtab_impl GTY(()) { int length; tree GTY((length ("%h.length"))) entries[1]; }; struct asdf_hashtab GTY(()) { struct asdf_hashtab_impl *impl; int num_ent; int threshold; };
こういうプログラムを書いておくと、gengtypeがGTYタグをなんとかして、
void gt_ggc_mx_asdf_hashtab_impl (void *x_p) { struct asdf_hashtab_impl * const x = (struct asdf_hashtab_impl *)x_p; if (ggc_test_and_set_mark (x)) { { size_t i0; for (i0 = 0; i0 < (size_t)(((*x)).length); i0++) { gt_ggc_m_9tree_node ((*x).entries[i0]); } } } } void gt_ggc_mx_asdf_hashtab (void *x_p) { struct asdf_hashtab * const x = (struct asdf_hashtab *)x_p; if (ggc_test_and_set_mark (x)) { gt_ggc_m_17asdf_hashtab_impl ((*x).impl); } }
こういうふうに、マークを行うプログラムを自動生成してくれるのである。
--
GGCはとりあえず、gccint.info の中にドキュメントがあるから助かる。けど、
struct tree_exp GTY(()) { struct tree_common common; int complexity; tree GTY ((special ("tree_exp"), desc ("TREE_CODE ((tree) &%0)"))) operands[1]; };
これの、specialってなんじゃい、って調べたら、
`special' The `special' option is used for those bizarre cases that are just too hard to deal with otherwise. Don't use it for new code. /* * 訳(多分): * * 'special' は他ではどーしよーもないイカれた場合にだけ使うんよ。 * 新しい部分では使ったらあかんのよ。 */
いや、説明になってないよ。
TREE_BLOCKは本物のコンテキスト。ローカル変数の情報とか、その中のサブブロックの情報とか持ってる。 COMPOUND_EXPRはただの文の集まり。ただ、TREE_BLOCKは文の集まりは保持できないので、 そのへんうまくやって。
tree_rest_of_compilationで関数を出す
他色々
あー、別にやる気が無いわけではなくて、いつも心の隅にあるんだけど、 優先順位があまりに低くて("眠る"よりも低い)、何も進んでないわけです。
もうコンパイラとかはどうでもいいんだけど、頭の中には結構な量のGCCに関するノウハウがあるわけで、 これをそのまま放置しとくのも勿体無いかなぁ…とか思ったりもするし、 僕が調べたことっていうのは、それなりに価値があるもんだと思うし、なんとかしたいのである。
っていうわけで、今後の方針。
とりあえず、今まで書いてきたものは捨て、だ。何か気に入らないって、名前が気に入らない。 asdfっていうのは発音しにくいし、思ったよりも使われてるし、失敗の感が強い。 そういうわけで、捨てだ。捨て。いらない。 途中経過までだったらここに置いときます。 グローバル変数に代入とグローバル変数の演算Int型だけだったら動いたような気がする。
で、これから、どうするか、あんまり考えてないんだけど、 コンパイラ専用インタプリタ言語っていう構想があったりするのである。 コンパイラのための仕様と、GCCのRTL生成のためのインターフェースを持ったインタプリタ。
詳細については日記形式で書いていくことにする。一度にまとめて書くと途中で嫌になるからだ。
まず、なんでこんなところに書いてるかっていう背景。 単純な話、大きいことを表立って書いて、実装できなかったらなんかショボいからだ。
今は、思い付いた瞬間だから、それなりにモチベーションもある。 けど、経験的に、これが続くのは、長くて一週間、短いときは3日くらい。 まあ、今のところ構想から2日目で、大丈夫だから、3日ってことはないだろうけど。
とにかく、最近は色々継続して行える自信が無い。どうしようか。あー。わからん。
誰も見てないと思って適当に書いてます。見てしまった人は暖かい目で見守ってあげてください。 とりあえず、googleでgcc,RTL,フロントエンドで検索すると引っかかるんだけど、 そういうので調べて飛んでくるぐらいだろうか。 そういうのに非常に興味があるけど、GCCなんもわからねーよ。っていうのであれば、メールで聞いていただければ、 答えられる範囲で答えていくので、まあ、そんな感じで。
とりあえず、例外処理システムだ。これを考慮してからパーサ書かないと、 パースエラーが捕まえられない。
あー、もういい、メモ代わり。
昨日と今日ちょっとやったところで、コンパイルが通って終了するまでのプログラムを ここに。
GCCフロントエンドはコンパイル通るようにするまでが最初の山。 langhook、GGC、treeを理解していないとコンパイルもままならないっていうのが辛い。
昨日の続き。例外処理。どうするか。ここらへん、きちんとすると、例外だけじゃなくて、全体が遅くなる… もはや効率は捨てるべきだ。 例外処理やろうと思うと、評価器の動作決めないといけない。評価器決めるには構文木の構造決めないといけない。 構文木の構造はパーサーによるし、パーサーは例外処理決めてからじゃないと…
まあいいか。評価器で参考になるのはRuby。あとのインタプリタはごりごり仮想スタックマシンっぽくなってるので パーサー〜中間コード〜VMを並列して読まないとソース←→動作対応が見えてこない。無理。 けど、Rubyは保守GCなので、そこらへんが参考にならない。EmacsとRubyを合わせたぐらいがちょうどいいだろうか。
というわけで、このへんは適当にしてさっさと飛ばしたいんだけどせっかくフルスクラッチしてんだから、 やっぱ綺麗にしたいと思うわけですよ。そして途中で嫌になって没。にはならないように注意しよう。
おおおおお、'('の対応が取れてないばっかりにGGCからくるコンパイルエラーに30分くらい悩まされた…死のう…
--
TODOリストとしても使う。
しばらく、コンパイルできない状態が続くかもしれない。けど、ここを適当に流してしまうと二の舞(三とか四かもしれない)だ。
とにかく、全部がオブジェクト(namespace)として動作するようにしないと…例外はtree_int_cst, tree_exp。 (ilog_string, tree_identifier, tree_decl, tree_type, tree_blockが特殊)
えーと、なんだ。メモ。hashtabが中でハッシュ関数呼んどる。ネームスペースは中でハッシュ関数使ってる。 ハッシュ関数はオブジェクトに依存したいわけだ。ここらへん。相互依存。死にそう。とりあえず、落ち付いて設計すれば、 間違いはないはず。間違えても、取り返しはつくはず。ILOG_SLOTの実装が先。
流れとしては、ILOG_SLOT→ネームスペース→ハッシュテーブル。といったところか。
あーなんか(略)
ーハッシュテーブル内でobj.hashを使うつもりだったらハッシュテーブルの前に関数呼び出しの仕組み作らないかんのか。 関数呼び出ししようと思ったら、評価器がいるのかー。んあー、相互依存しまくり。何が悪かったんだ…
とりあえず、ネームスペースまわりはそれなりに終わった。 というか、NLで使ってたものをほとんどsed s/nl/ilog/gしただけなんだけど。 こういうのを手作業でやるって効率悪いかなぁ…それなりにファイル構成とか、良くなったし、 機能が重複してるやつ省いたりして、結構改良してるので、リファクタリングと呼べないことも無いんだけど。
--
この文章は将来ドキュメント代わりになる予定(嫌なドキュメントだな…)なので、そういうのも書いていかないと。
まず、動機だ。最初に書いたとおり、 「コンパイラはどうでもいいんだけど、せっかくGCCに関するノウハウを時間かけて覚えたので、なんか残したい」 というものだ。
それから、構想のベースとしては、ASDFに実装予定だった機能、「NLで書かれたCパーサ」っていうものだ。
簡単に言うと、Cのヘッダを直接読んでリンクできるようにする。というものだ。D言語をも越えるCとの密接度。
でも、その機能は片鱗も実装されることなく終わってしまったんだけど、 「GCCフロントエンドを操作できるインタプリタでパーサを書く」っていうアイデアは 僕の中で残った。で、ILOG言語はその部分をメインに押し出した、っていうわけだ。
えーと、文章が適当だ。雰囲気で読み取ってください。 そこらへんが技術的背景。実際の動機はもっとネガティブなんだけど、そこらへんは次回へ続く。
あと、ILOGっていうのはI LOve Gccの略なんじゃないかと思う。多分。 ILOGで検索すると、結構出てくるんだけど、正しい名前はILOG Scriptだから大丈夫なのだ。多分。
あー、あかん。次何潰すか思い付かん。パーサかなぁ…明日はNLからパーサの移植。getter、setterを付けること。
今日はEmacs Lispみたいな関数呼び出しを実現した。Emacsのソースを手でコピペするというムダな作業。
まあいいか。これでネイティブ関数書くのがNLよりもいくらか楽になったはずだ。 こういうのを書くのは楽しいな…ムダばっかりなんだけど。
だいぶGCCのソースも読めるようになってきた。フロントエンドまわりは大体大丈夫なはず。 わからなくても、どこらへん読めばいいのかぐらいはわかる。
--
で、動機だ。動機は技術的なものと、精神的なものとあるだろう。 精神的になにかやりたいと思っても、技術的につまらんかったらやる気しないし、 技術的に面白そうでも、心動かされないことだってある。
技術的な面は昨日のはなし。精神的な動機について。
と、いっても、それは、僕が天才ではなかった、という、糞どうでもいい動機だ。
天才プログラマにとって、それ以外の人間っていうのは猫の手でしかない。 できるプログラマっていうのは短い時間で、美しい設計を行い、しかも実装も短時間で行う。 できるプログラマが全ての作業を行うっていうのが、一番コストパフォーマンスがいいのだ。 それ以外の人間が混じるっていうのは、効率を下げる以外の何物でもない。
ようするに、天才ではないプログラマ、つまり、僕は必要ないっていうことだ。 このことは、なんていうか、どうしようもない。 凡人は天才にはなれないし、凡人が必要とされることもありえない。
でも、それでも、天才の仲間入りがしてみたかった。 ほんの、気分だけでもいい。一瞬でもいいから、天才達を振り向かせてみたかった。 しかし、僕には武器が「GCCだったらだいたいわかる」の、ひとつしかなかった。選択肢はなかった。 だから、やる気なんか無くなってても、GCCを使って何かを書きあげる必要があったのだ。
と、いうわけで、人間の糞汚い部分が動機の根底とかで、 「ハックが楽しいから」なんていう素晴しい理由なんかこれっぽっちもないわけで、 僕って小さい人間だと思った。社会の害悪でしかないと思った。
--
と、まあ、ネガティブな話はこのへんにして、そろそろ まともなドキュメントを書きはじめたほうがいいと思ったので、 明日はILOGScriptの概要について書く。
--
今で2000行くらい。半分くらいがNLからのコピー。残りが手でコピペしたもの。 思ったよりもやる気は続いている。あと1週間くらいは続いてくれればいいんだけど。
TODO: to_string、パーサ、ilog_error
うっへっへっ。おとといは飲んで帰って書けなかった。昨日はやる気なくして寝た。 もう駄目だよ。やっぱ続かねーよ。とーさん、かーさん。やっぱ僕は所詮社会のゴミっていうことか。
っつーわけで、今日は寝ないように、夜の9時くらいにコーヒー飲むという暴挙に出てみた。 結構効果あるようだ。
--
ilog_errorを実装しようと思って、変数コンテキストまわりを見直してたんだけど、 もうグダグダだよ。nl_push_envとnl_set_envっていうのがあって、 nl_push_envがスタックにプッシュしてるのはいいとして、nl_set_envもスタックにプッシュしてるの。 名前おかしーだろ。ボケが。
っていうわけで、なんかそこらへんを直してたら、力尽きた。一応終わったけど。 で、errorとexceptionは意味的に分けないといけないと思ったんだけど、 どうしようか。もうなんかいいや。errorもexceptionも一緒、同じ。いや、 ファイル構成的に同じだけで、外部インターフェースはちゃんとなってるはず。多分。
sprintfで勝手に文字列長さ分アロケートしてくれるやつが欲しいと思って、libibertyにあるだろうと思って 探してみたら、ビンゴ。vasprintf。libibertyは見てたら結構暇潰しできる。
んで、ガーって書いてて、相変わらず、Makefile書くのとか、GGCまわりとかはめんどいなぁ…って思う。 このへん、GCCコアメンバー達はどう思ってんだろうか。ML見たらあるような気はするんだけど、 めんどいから無視。
まあ、とりあえず、例外はできた。次はto_string、ilog_hash、パーサ。 つか、パーサはいつになったら始まるんだ。
--
とりあえず、おいしそうなキーワードを並べてみた。ilog
お、そんなに休んでたのか。まあ、とりあえず闇歴史でしかなかったSDL-XIMパッチの分のリベンジできたからいいとするか。
--
今日のlangsmith(おとといだけど)
まつもとさん曰く「誰かができかけのプロジェクトをもってきて〜」
と、いうのは、僕に対するプレッシャーなのだろうか。
いや、そんなわけないんだけど、このメール見たのが、何故か夢の中にmatz氏が出てきた直後だったので、 そのときは、このメッセージが異様に意味があるように思えたのだ。だからどうした。
有名人が夢に出てくるなんて滅多に無いし、そもそもそれがmatz氏であるというのはありえないと思うのだけど、 まあ、とにかく、そういうタイミングだったので、ちょっと面白かった。多分僕以外は何が面白いのかはわからんだろうけど。
--
あー、やる気出ないよ〜。もうダメだよ〜。と、思ってたんだけど、今やってたら、楽しくなってきた。 まだまだ希望は捨てたもんじゃないかもしれない。 hash関数とそれの実装を楽にするためのnamespaceへのインターフェースまわり。 syntax-treeの構想をちょっとまとめる。パーサを書きはじめる。
だいぶ基本部分ができて、動かしてみたくなってきたので、パーサ、評価器を書きはじめる。 そろそろ何かが動くだろうか。
NLに比べたら大分構造が綺麗になったと思う。 実際変更した部分はちょっとなんだけど、ちょっとでも効果は大きいのかもしれない。 リファクタリングとか勉強する価値あるかもしれないと思った。
また空いてしまったよ…って、そんな話よりも、g++のパーサが気になって読んでたんだけど、 cp_parser_binary_expressionが、どうやっても左結合にしかならないの。で、右結合のはずのシフト演算子もcp_parser_binary_expression使ってんの。 「おぇーこりゃどうやって右結合してんのや!?」と、思って調べてたんだけど、全然わからなくて、投げだしそうになったんだけど、 その回答は「シフト演算子は左結合」っていうごくごく普通の答えだったので、投げだした。死にたくなった。
やっぱ希望が消えてきた。どうも…いかんなぁ…一日限界稼働時間みたいなのがあるようだ。多分2時間ちょい。 今日はパーサをちょろっとやっただけ。二日休んだあとにこれはペース落ちすぎだ。
ちょい追加なんとなく、妄想してるときは、 なかなか面白そうなんだけど、これを自分で実装するって思うと無理だと思えてくるから不思議。不思議でもなんでもないけど。 HTMLで書くのは非常に好きなんだけど、やっぱ、前後に依存する処理(章番号とか)がやりたいので、eRubyで遊んでみた。TOCが出る。
とりあえず、基本的な文法はほぼ決定した。そこまで実装して、簡単なサンプルコンパイラ書いて、そこで一個区切りでいいだろう。
また空いた。もう慣れた。
構文要素をオブジェクトにしてやったら、何が何かわからなくなってきた。がりがり遅くなっていくよー。多分。 それでもg++より遅くはならないと思うけど。わからん。まあ、そのへんはあとで。
史上初、作者さえも理解できない言語。
todo: for_stmtもifとかwhileみたいにする。文章書く。あ、大丈夫か。なんでもない。
もう少しで寝そうになってたのを耐えて続きをやる。あと、あー。
とりあえず、構文要素さえもオブジェクトとかゆーわけわからんことをやったおかげで、 それなりに綺麗にパーサと評価器の区別が小さくなってしまった。
よーするに、パーサ書いてるつもりが、評価器も一緒に書いてしまっていたのだ。 あー、この方法は速度かなり犠牲にするけど、インタプリタ書く側からしてみたら良いかもしれない。っていうメモ。
で、もうちょっと安定させたら動きそう。まだ肝心な機能は全然足りないけど、明日くらいにはバージョン10^-19くらいは 出来るかもしれない。いや、明日サボらなかったらだけど。 とりあえず、なんだ。やっぱ最初にそれっぽく動くのを見たときっていうのは、プログラム書いてよかったって思うときだよなぁ… っていう月並みな感想。
todo: 動作確認。関数呼び出し、メソッド呼び出し、メンバアクセス、代入、計算。ほげほげ。
遊びすぎた。メソッド呼び出し一個で12回ネストしとる。死のう。
#1 0x08051ec7 in call_funcobj (this_=0x40447b2c, args=0x4040e6f4) at ilog/ilog-objects.c:44 #2 0x0804ce97 in ilog_funcall (this_=0x40447b2c, func=0x40415300, arglist=0x40447b54) at ilog/ilog-eval.c:70 #3 0x08051cbd in funcall_expr_eval (this_=0x40447adc) at ilog/syntax-tree.c:289 #4 0x0804d071 in ilog_funcall (this_=0x40447adc, func=0x40415258, arglist=0x4040e6f4) at ilog/ilog-eval.c:97 #5 0x0805051f in ilog_funcall_va (receiver=0x40447adc, func=0x40415258) at ilog/native.c:81 #6 0x0804eb2e in ilog_eval (obj=0x40447adc) at ilog/ilog-eval.c:236 #7 0x0804ecbd in stmt_list_eval (list=0x40447aa0) at ilog/ilog-eval.c:280 #8 0x0805123d in ilog_parse_file (debug=0) at ilog/parse.c:578 #9 0x082e713d in compile_file () at /usr/local/src/gcc-3.4.1/gcc/toplev.c:1822 #10 0x082ec2f7 in do_compile () at /usr/local/src/gcc-3.4.1/gcc/toplev.c:4650 #11 0x082ec390 in toplev_main (argc=2, argv=0xbffff7a4) at /usr/local/src/gcc-3.4.1/gcc/toplev.c:4690 #12 0x08052036 in main (argc=2, argv=0xbffff7a4) at main.c:35
いいのかなぁ…
まあいいか。とりあえず、かなりまともに見えてきた。次はメンバアクセス。これができたら、 GCCへのインターフェース作って、って考えたら、もう少しのような気がしてきた。 と、見せかけて、returnという基本的な物が足りない。return面倒なんだよなぁ…。
バックアップの意味も含めて、ここまでの分
お、もうすぐだと思ってたら、tree_rest_of_compilation(関数作るときに最初に呼ぶべきもの) 作るためにlanghookをなんとかする機構とか、tree_decl、tree_type、tree_identifierをnamespaceに見せかける 機構とかが必要らしいことがわかってきた予感。先はもうちょい長い。 「明日にはバージョン10^-19」宣言から四日。どこまで遅れるのか!?9月中にはできるかなー。
インタプリタの基本部分は大分できたと思う。あとは未実装の演算子とかみたいな細かい部分をほじほじすれば。
適当にlanghooks潰した。returnがねぇよ。
todo: declとかtypeとかをやる。
いよおおおぉぉぉおおおおっぉぉぉおおおおおぉぉおおおおおおおおっし。できた。グローバル変数の宣言だけだけど。
一ヶ月くらいかかってるけど、1/4ぐらいは今日書いたと思っていいです。