プログラミング言語Palan開発日記 3年目

2017年7月ごろから衝動的にコンパイラを自作し始めました。2年経っても完成には程遠く、完全に自己満足の世界なのですが、誰かの為になることも書けるかも(?)知れないので日記・覚書をここにつけてみます。 いいね少なくても2年間続けられたのでいまさらですが、いいね貰えたら多少モチベ上がるかも。

Githubリポジトリ: Palanソースコード(C++)

リファレンス: Palanリファレンスv0.2


ヒストリ

プログラミング言語Palan開発日記 1年目

プログラミング言語Palan開発日記 2年目


日記

更新を楽にするため、上の方が最新です。時系列で読みたい人は下から読んでね:bow_tone1:


実装中

C関数呼び出し改良中


7月17日 FILE

sprintfやscanfなどが呼べるようになった。でも全てのC関数が呼べるにはいろいろ足りない。まずは全ての標準Cライブラリが呼べるところを目指して進めたい。把握している課題は以下。


  • 型定義/構造体。FILE/struct tmなどが使えない。

  • 所有権を持たないリファレンスの取り扱い。strtolなど。

  • ポインタの更新(ポインタのポインタ)ができない。strtolなど。sqliteとか使う場合も必要。

  • グローバル変数?stdinなどが使える必要あり。

  • インポート。プロトタイプを毎回書かずに済むように。

  • マクロ/cpu組み込み機能を使えるにはどうするか。

  • palan関数でも引数での出力は使えるようにした方がいい。可変長引数はとりあえずやめとく。

こう書き並べるとまだまだ遠いな。。とりあえずFILEが使えるようにするところから始めよう。


7月15日 トレンド

おかげさまで公開後しばらくQiitaトレンド入りしてたみたいで、この日記にいいねをたくさん頂くことができた。いいねしてくれた方ありがとうございます!ただgithubのデータ見ると、試しに使ってもらえるまでには、まだまだと実感。激励と思い地道に進めよう。

実装の方はsprintf/scanf等が、思ったり少ない修正で動き始めた。エラー処理やテストを追加中。


7月10日 C言語関数の再考

Palanでは独自ライブラリはなるべく持たずに既存のC言語ライブラリを上手く利用できたらなと考えている。ただ、C言語の関数そのままの文法では出力や高速化のためにポインタを使うし、引数が入力か出力もぱっと見では曖昧で初心者には取り扱いが難しい。このC言語の関数呼び出しをPalanの左から右に流れるような文法に融合させたい。色々考えた結果以下のようにしようと思う。

// プロトタイプ

ccall printf(byte[?] &format, ...) -> int32;
ccall strcpy(byte[?] >>dst, &src) -> byte[?];
ccall sscanf(byte[?] &str, &format => ...) -> int32;
ccall sprintf(@, byte[?] &format, ... => byte[?] dst) -> int32;

// 使い方
byte[80] dst;
"Hello World!" -> printf();
printf("Hello %s!", "would");
dst ->> strcpy("Hello") ->> dst; // 所有権を渡して変更されたものを受け取る。
// 将来的にはdst.strcpy("Hello");でもできるように。

int32 a,b = 0,0;
int num_scanned;
"10 20" -> sscanf("%d %d" => a, b) -> num_scanned;
sprintf("a:%d, b:%d", a, b => dst);

=>より右側が出力となる引数となる。出力になる引数を全部右に持っていくので、sprintfのように引数の位置が変わってしまうものも出てくる。その対応づけはプレースホルダ@で補う、というアイデア。

プロトタイプさえ上手く書ければ、左から右に入力出力が自然な形にかけて明確と思う。またポインタも意識しなくていい。

最初は=>以降は()の外に出そうかと思ったが、内部実装と文法が剥離して余計な誤解を生みそうだったのでやめた。->でなくて=>なのは引数に代入を混ぜられると混乱しそうだったから。ホントは|>がいいかなと思ってたけどやめた。

基本、文法の一貫性よりも内部処理の実態(コンピュータの都合)に合わせて誤解を生みにくい記述を優先したい。

プロトタイプの読み込みまでは何とか実装できているが、リードオンリー参照&や可変長引数...、要素数不明?等、色々文法追加してるので関数呼び出しまでちゃんと動くところまで持っていくのはしばらくかかりそう。


7月9日 静的解析

なんとなくcodacyで静的解析かけてみた。そしたら150件もの指摘が、、ってほとんどドキュメントのマークダウンの指摘やんけ。ネストしたリストの*の後のスペース、タブ幅に合わせないといけないらしい。。なんとかマークダウンなおしたら、C++関連は30件ぐらい。静的解析は、あまり本質的でない指摘があるのがいやでやってなかったが、まぁこれぐらならいいかな。お陰でバグも1件見つけた。たまにやる凡ミスによるわかりにくいバグは防げそう。

気をつけないといけないのは、コードを理解せずに指摘通りに直してはいけない。指摘されたところは結構バグが潜んでいるので、理解せずに直してしまうと静的解析でも検出できないさらにわかりにくいバグになってしまう。


7月4日 パイプ演算子

C言語のプロトタイプとかポインタによる出力どうしようと思って、|>みたいな記号使ったらどうなんかなーと検索したらElixer が引っかかったよ。Elixerって初めて知ったよ。

Elixer ではパイプ演算子といって関数の第一引数に入れるらしい、、ってこれ何も知らずにPalanに組み込んだチェーンコールまんまじゃん。さらに調べるとずっと昔の何かの言語にあったものがF#に組み込まれて、JavaScript とか色んな言語に波及中みたい。新発明かと思ってたが、先客いたのね。みんな同じこと考えるもんだなあ。

ただ思ったよりメジャーな演算子ということがわかったので、今回の用途でこの演算子使うのはやめた方がいいかもしれん。


覚書


  • 引数と戻り値が同じ時 戻り値側の型はvarで省略できるようにする。

  • 実現出来るかわからないけどNULLを使わせないというコンセプトも持ってるが、配列のからコピーせずに要素を取り出す等の用途向けにswapを演算子<->等を組み込むのは有用かもしれない。

  • 数値計算などパフォーマンス上げる為にfreeをしないモードを入れてもいいかもしれない。

  • 名前付きブロック。宣言した時点でメモリ確保してしまうので、子のブロックで親のブロックの変数を宣言できる方がいい。ループ内の振る舞いは要検討。

  • 関数呼び出し時のデーブコピーは呼び出し元でやってるが、リードオンリーの際リファレンスを使うどうかを呼び出し元で選べるから呼び出し先でやってもいいかも、と、一瞬思ったが、引数確定後に元の値が変わる恐れがあるのでやっぱり今まで通りでいい。

  • Bool(and/or)は改良の余地ありかも。比較の種類を返すのではなくて上位if文からジャンプラベルもらった方がいいかも。

  • 継承は便利なもことも多いいいが、子の型が確定しているときに子のデータにダイレクトにアクセスしたい時が面倒。共用体のように型変換せずとも気軽にアクセスできる仕組みがあればいいと思う。

  • 引数にコピーを指示している関数にmoveで渡せてもいい。用途はsetterとか

  • インポートするモジュールをいちいち指定するのは面倒。パースの際に未解決識別子を認識して、それに応じたモジュールを自動でインポートできれば嬉しいかも。