今月の活動 (ミローネ言語など)
- 前回 (2021-02-28) https://vain0x.github.io/blog/2021-02-28/diary/
ミローネ言語
https://github.com/vain0x/milone-lang
- C言語の標準規格(C11)に準拠していないコードが生成される不具合を修正した
- GCCで
-Wall
をつけてコンパイルしていたので、そういうミスは指摘されるものと勘違いしていたが、-Wpedantic
を有効化しないと指摘されないらしかった - これによりclangやMSVCでもコンパイルできることを確認した (Windowsでも動く!)
- 試しにchibiccでもやってみたところ、テストはすべて通ったが、セルフコンパイルで作ったコンパイラを動かすとクラッシュしてダメだった
- GCCで
- Cコードを分割してファイルに出力するようにした
- いままでは標準出力にCコードを出力していたが、これだと分割コンパイルができず、Cコンパイラの負荷が高かった
- (参考: セルフコンパイルの結果として、無駄な前方宣言や空行を含めて、8万行弱のコードが生成されていた。GCCは
-O0
でも10秒ぐらい要していた) - この機能を実装するには、名前解決や型検査などのすべてのステージをモジュール単位で行う必要があると思っていたが、実はそこまで難しい話ではなかった
- 型や関数がどのファイルで定義されたかを追跡しているので、Cのコードを生成する直前に型や関数を定義箇所のファイルごと分割する、とするだけで十分だった
- リストなどの多相な型の定義がCの各ソースファイルに生成されるので全体のコード量は増えるが、差分コンパイルができるので、コンパイル時間は短くなるはず
- ninjaのビルドスクリプトを見直した
- 複数のCのファイルをコンパイルすることになったので、スクリプトが大幅に複雑化した
- 数日前に書いた ミローネ言語の開発用にビルドツールninjaを使っている感想など を参照
規格違反の例
コンパイラが出力していた規格違反なCコードの例をあげる。
空の初期化リスト
- 配列を空の初期化リストで初期化する文:
char buf[42] = {};
- 複合リテラルを空の初期化リストで作る式:
(struct K){}
C11では、初期化リストは構文的に空にできない。
2つ目以降の要素やフィールドは省略可能なので、すべて省略できてもよさそうなものだけど。 (C++ではOK.)
不完全型の変数宣言
static struct K k; // 不正
struct K { int n; };
変数の型は完全型でなければいけないので、構造体の型定義を先に書き、その後で変数の宣言を書かないといけない。
C言語は型定義の順番に厳しいが、型定義の前方参照を禁じる理由はあまりない気がする。
前方参照を許可するとワンパスコンパイラを書けなくなるが、Cコンパイラをワンパスで書くのは厳しい。
#include
や #define
との相互作用が気になるのと、前方参照を認めるのはいまさらすぎる、というところか。
enumの前方宣言
enum E; // 不正
enum E { A, B };
構造体がポインタ越しに相互再帰的に参照されることがあるので、ミローネ言語のコンパイラはすべての型の前方宣言を出力してから、型の定義を出力している。 structの前方宣言を出すのと同じノリでenumも前方宣言を出していたが、実際のところenumの前方宣言は意味がなく、規格でも許可されていない。
FFI
ミローネ言語からC言語で書かれたライブラリを使って何かアプリを作る実験をしていた。 jsonをパースして特定のフィールドの値を取得するコマンドと、データベースに保存するメモアプリを作った。 FFI (というか他言語との相互運用) が安定していないと意味のあるプログラムを書くのは厳しいので、このあたりを優先的に安定させていく必要がある。
書いた記事
ぼんやりと思っていることを記事に起こした。 記事にするようなことでもない気もするが、なんであれ書いていけば無意識に自己が啓発されて案が生まれるかもしれない。
- プログラミング言語の構文とセミコロン - ベインのブログ
- 関数型プログラミング言語の構文は「すべてが式」ではない - ベインのブログ
- ミローネ言語の開発用にビルドツールninjaを使っている感想など - ベインのブログ
気になった記事など
本物のC (最終更新は2016年)
「本物の」とはつまり、
- 標準規格(仕様)が C 言語をどういうものとして定めているか
- C プログラムが実際に CPU をどう動かすか
という二つの意味合いに於いてです。
Cの解説は玉石混交で、信頼性のある記事は貴重。 日本語で書かれているのも嬉しい。 ちなみに私は C reference を参考にすることが多い。
Semantic Versioningの闇 (投稿日は 2020-11-10)
semverは「バージョン制約」を定めていないため、「バージョン 1.2.3
は制約 =1
を満たすか?」といった命題の解釈が実装によって異なるらしい。
自作言語のパッケージマネージャを作るとき、このあたり考慮したほうがよさそう。