構造体とかがちゃんと動くようになった。Slackに投げたら「はやいねー」という感想をもらった。そら開発時間14時間越えてますからね今日。昼に実装が煩雑になりそうでやめたdeclaratorの実装が、実はそんなに煩雑でもないかもねという話になった。明日ヒマがあれば実装してみよう。いや今日の開発の途中でerrorが__FILE__と__LINE__を吐くのは無意味ではないかと思い始めた。errorでbreakpointを設定すれば全部辿れるのだ。columnが無いのはつらいのでさっさと実装しよう。適当なトークンから引っ張ればいいはずだ。いやそう単純でもないな。朝からパーザを書き直す。AのBNFに従って構文解析するように書き直した。これに5時間くらい溶けた。これのおかげで「ポインタの配列」が扱えるようになったり、カンマ区切りで変数宣言ができるようになった。構造体のポインタを返す関数に矢印をはやせるようになった。N-queenをさっと書こうと思ったら、まずN-queenが書けなくて死んだ。やっとこさ書いたらこんどは動かない。論理否定演算子!を実装していなかったり、if文のcondにlvalue2rvalueをかましていなかったりした。デクリメントが無いのは-=でどうにかした。日記を書きながらwhileとforにもかましていないことを思い出したのでかました。日記がここで400行。テストはさっきtest300を越えた。8月8日Ruiさんの指摘をもとに、テストをマクロで書くことで、期待されている値と実際の計算との距離を近くした。これの移行をする時にエスケープシーケンスの処理がまずっていたので訂正。isprint()にかけてfalseのやつだけを見ていたんだけど、これだとダブルクオーテーションをエスケープできないという問題があった。...)とかが書ける。AST_EXPR_LISTというASTを追加して、これで格納するようにした。for文の節1に宣言を書けるようにした。0;...)とかが書ける。*だったんだけどさすがにそれだと扱いにくかった。AST_DECL_LISTを追加してこれで格納するようにした。*に変換できるように拡張すれば、コード生成で消し飛ばすことが出来る。CodeEnvをグローバル変数に移行。codesをswapすることでいろいろやっていたので、そのときはCodeEnvを別のものにするという処理が必要だったのだけど、いやよく考えたら当時から要らなかったかも知れない。一つのCodeEnvインスタンスがあれば十分なのでグローバル変数にした。ついでにcodesなんて英語にないよ問題を解決。今日は一日aqccをやる予定。typedefを実装したいが、そのためには不完全型の実装を、あれ、Cに前方宣言とかあったっけ?という気分になったのでとりあえず実験。結論としてCに前方宣言はない。宣言していない型でも、とにかくポインタにしておけば使える。テスト書いたら動くのだもの。そんな実装した覚えがないのに。種明かしとしては、ポインタ型の場合はanalyze_type()の本チャンルーチンがそもそも起動しない。->なりなんなりでポインタが外れたときにだけルーチンに入るが、そのときには構造体はすでに定義されているという寸法。typedefを実装。Ruiさんがtypedefは簡単だっていうから気軽に実装を始めたら3時間半くらいかかった。そのおかげでクリティカルなバグをいくつかつぶすことができた。いままでanalyze_type()は構造体だけを相手にしていたが、それだとtypedefで「構造体の配列」みたいなのを持ち込まれた時に対応できなかった。それで全ての型について適当な処理をするようにし、再帰的に処理するようにした。AST_EXPR_LISTのパーズで手抜きをしたために、すべての式はEXPR_LISTみたいなことになっていたが、これだとlvalue/rvalueまわりでバグった。具体的にはEXPR_LISTはかならず全ての式にlvalue2rvalue()を施すため、(*b).aみたいな式が動かなくなっていた。-1でエラーになるのではなくコードが生成されない(!)ためだった。gen_movにassertを入れて、全てをEXPR_LISTにするのではないようにした。考えたらこれが本質的な問題じゃないな......。途中でとてもつらくなったし、自分がどんなコードを書いたか憶えていない。これを書きながら確認したらやっぱりバグっていた。次のようなコードが通らない。直さないといけないがどうなおしたらいいかなぁ。*b).a;}そうか、AST_EXPR_LISTの最後のexprだけlvalue2rvalueを書けなければいいのか。本当に?昼ご飯を食べながら考えよう。lvalue2rvalueをかましているのがそもそも間違いな気がしてきた。EXPR_LISTがlvalueとして認識されるべきかどうかを決めないといけない。何かがおかしいと思ったら、EXPR_LISTがlvalueかどうかは一番最後のEXPRが決めるっていうことだ。いうふうにis_lvalueを書き直したら動いた。ご飯を食べてから前置後置デクリメントを実装。実装してなかったのだ。a)++が通ってしまうが、これは規格的にはダメ。EXPR_LISTに対してis_lvalueで対応しているのがまずいので、これを.演算子のほうにうつす。a.bのaは規格的にはrvalueなのだろう多分。実装上はlvalueの方が便利だけど。デクリメントとfor文始めの宣言を実装したのでこの前書いたNQueenがもう少し簡潔に書けるようになった。そのままexamples/nqueenに突っ込んでcommitした。ここでなんとなく日記を見返した。前から気になっていた部分をいくつか修正。utility.cに入っていても、一つのファイルからしか使っていないやつは移した。このファイルわけというのは面倒で、どこに何を置けばいいかよく分からん。error()の__FILE__を消し飛ばした。error()からbacktraceすれば全部見える。error()のファイル名と行番号だけは吐くようにした。構造体メンバのアラインメントを求めるアルゴリズムを変更。指摘が厳しいけどめっちゃ詳しいサイトを読んでもよく分からなかったので、GCCに実際に突っ込んで見ながらアルゴリズムを特定した。構造体のネスト三段階に配列を組み合わせたものに対して正しいsizeofが帰ってくるので、多分合っているだろう。実装し、unionを実装した、らしい。今日は朝からスタバWifiで開発をした。変えるとstring_builder.cがコンパイルできることがわかったので、いろいろ変えなくてもコンパイルできるように頑張った。全ての関数定義に.globalをつけるようにした。あと浮動小数点がないのでroundup()を改造。Ruiさんがハッカーのたのしみから持ってきたコードがすごかった。分からんままコピペしたら動いたのでウォーっていう気分。結局よくわからんままだ。あとsize_tを使っていたところをintに変えたり、constを読み飛ばしたりした。structやunionと同じ扱いにした。関数引数に...を書けるようにした。今の所関数引数のチェックは虚無なので何をしても問題ないが、現状のコードを読むためには読み飛ばしでもいいから実装が必要だ。あともう少しでaqcc.hが読めそう。してセルフコンパイル(できるところを)するようにする。これから個人ミーティング。昨日Twitterに上げた「C++完全に理解した」名刺が生涯で一番のヒットをしていた。