acl4の開発ログ #03

  • (by K, 2026.01.01)

ここまでのもくじ

2026.01.01(木) #0

  • ずっと悩んでいました。機能的にやりたいことを実現するのは全然難しくないのです。
  • でもそれをかっこよく書くことができませんでした。どうやってもドンくさいのです。
  • しかし今日になって、やっといい感じに書く方法を見つけました。
func(a, b, .c) → func(a, b, ADot1(c))
int func(int a, double b, .char *c) → int func(int a, double b, ADot1(char *c))
→ つまりドット1つから書き始めると、それはカッコ閉じか、次のコンマまでADot1(...) で囲われた形に置換されます。

..int d, e; → ADot2(int d, e;)
→ ドット2つから書き始めると、セミコロンまでを ADot2(...) で囲われた形に置換されます。

func.(a, b, c) → func(ADotArg1, a, b, c)
→ 関数呼び出しの際にドットを入れておくと、ADotArg1という引数を勝手に追加します。

func(,a,,c) → func(a, c)
→ 関数呼び出しなどで、不要なコンマはすべて自動で削除されます。
  • たったこれだけをやってくれる簡易プリプロセッサがあれば、私がやりたくてたまらないことは実現できそうなのです。

2026.01.01(木) #1

  • どんなことがしたいのか?
    • [1] 目立たない方法でいくつかの引数を追加で渡したい。具体的に何を渡すかは後で考える。→ func.(...)
    • [2] デバッグモードの時だけ追加の引数を渡したい。→ func(a, b, .c)
    • [3] デバッグモードの時だけ変数を宣言したい。そのたびに #if ~ #endif を使うのはかっこわるい。→..int d, e;

2026.01.07(水) #0

  • やりたいことを簡潔にまとめてみます。こんな感じのことをC言語でやりたいのです(ライブラリ整備とプリプロセッサ拡張で)。
    void func()
    {
        Enter;
        MyClass1 *a = new_MyClass1.();
        MyClass2 *b = new_MyClass2.(1, 2, 3.4);
        aやbを使って色々する.
        Leave;
    }
    // ポイント:
    // newしたけどdeleteしなくていい. Leave すると関数内でnewしたものはすべてdeleteされるから.
    // Leaveのタイミングで消えてほしくないときは、 newx_...を使う.
    // [Q] newしたポインタを誤ってreturnとかで返してしまったら?
    // [A] デバッグレベルが2以上なら、エラーで止まってくれるので何の心配もない. エラー個所も簡単にわかる.
    // [Q] Leaveをやり忘れてreturnしたらどうなるの?
    // [A] デバッグレベルが2以上なら、エラーで止まってくれるので何の心配もない. エラー個所も簡単にわかる.

2026.01.08(木) #0

  • 昨日くらいから、ライブラリ関数やライブラリマクロを「A」で始めるというルールがダメなんじゃないかと思い始めています。
  • Aは目立ちすぎるんです。邪魔なんです。
  • しかしだからといって、何のプリフィクスもなく書いてもよいというルールにすると、ユーザ関数の関数名や変数名にぶつかるリスクがあります。そこが悩ましいです。
  • 私の一番のショックだった出来事は、macのXcodeでmaxとかminという変数名を使おうとしたらエラーが出たことです(もしかしたらXcodeではなかったかもしれません)。たぶんmaxやminというライブラリ関数か何かがあって、それと衝突したんだと思います。
  • そのときに、ライブラリ関数とユーザ関数がぶつからないためのルールは必要だと思いました。そうでないと安心してコードを書けないですし、将来ライブラリをバージョンアップしても大丈夫だという安心は得られません。
  • うーん、普通にアンダスコアから始めるというルールにしたらいいのかなあ。それだとコンパイラやシステム提供の関数群と衝突する可能性はありますが、ユーザ関数とはぶつからないですみます。

2026.01.08(木) #1

  • 悪くなさそうなアイデアに到達しました。
  • まず、acl4に関係するライブラリ関数やマクロはすべてacl4_をつけた形で定義します。
    acl4_Enter, acl4_Leave, acl4_Class, ...
  • その上でライブラリ側に以下のような記述を含ませます。
    #if (!defined(acl4_Version))
        #define acl4_Version  1
    #endif
    #if (acl4_Version >= 1)
        #define Enter  acl4_Enter
        #define Leave  acl4_Leave
        ...
    #endif
    #if (acl4_Version >= 2)
        ...
    #endif
    #if (acl4_Version >= 3)
        ...
    #endif
  • こうすれば、ライブラリ関数やマクロをどこまで acl4_ のプリフィクスなしで使うのか決められます。acl4のバージョンが上がって新しい関数などが増えてもユーザ関数とぶつかる心配がありません。ちなみに acl4_Version を 0 にしておけば、すべて acl4_ をつけて使うこともできるわけです。
  • 「そういえば、<windows.h>にも_WIN32_WINNTっていうのがあったよなー、そっかー、みんな似たようなことを考えるんだなー」と思ったのですが、これはだいぶ意味が違っていて、アプリが想定するよりも古い<windows.h>が与えられたときに、確実にコンパイルエラーにするためのものらしいです。

2026.01.08(木) #2

  • [Q] newがどうだとか言っているけど、それって要するにC++の真似をしたいってこと?それなら素直にC++を使えばいいんじゃないの?
  • [A] いや別にnewじゃなくてmallocとオブジェクト初期化の関数呼び出しでもよかったのですが、それをnewって書いたほうが伝わりやすいですよね?
  •  これからいろいろ他の言語の真似をしていくと思います。C++だけじゃないんです。いろんなところからつまみ食いをするイメージなのです。だから「じゃあC++でいいじゃん」にはならないと思うのです。

2026.01.11(日) #0

  • <string.h>って、str系の関数とmem系の関数があると思います。strcmp・memcmpとか、strcpy・memcpyとか、strchr・memchrとか、対(つい)になっていると思うのですが、strstrに対応するmemmemがあればいいのにって思いました。
  • と思ったらなんとすでにあった!ただしGNU拡張で。

2026.01.12(月) #0

  • 10年以上前から使っていたトークン切り出し関数があります。なんとなく、これを見直そうと考えました。
  • この切り出し関数は、文字を、
    • アルファベット(純粋なアルファベットだけではなく、アンダースコアのようなアルファベット的なふるまいができる文字を含む)
    • 数字
    • 一文字記号(;や,やかっこ類など)
    • それ以外の記号
    • 空白類
  • の5つに分類して、
    • アルファベットで始まるトークンの2文字目以降はアルファベットか数字だけで構成される
    • 数字で始まるトークンの2文字目以降はアルファベットか数字だけで構成される
    • 一文字記号は1文字で切り出す
    • それ以外の記号は、それ以外の記号が続く限りつなげて切り出す
  • という簡単なアルゴリズムで切り出していました。こんな単純なものでもほとんどうまくいくのです。
    • (ここには書いてないですが、文字リテラルや文字列リテラルの切り出し、コメントの処理、実数定数の切り出しの処理もあります。)
  • でもこのアルゴリズムだと「=+」とか「**」とかがたまに出てきてしまいます。これは「i=+3;」とか「x=**p;」みたいな文脈なので、それぞれ1文字ずつに切り分けるべきなのです。
  • しょうがないので、今までは、「=」で始まって「==」ではないなら切り分ける、みたいな追加ルールを数行で記述してしのいでいました。
  • ところが今回、こんな例外処理みたいなことをしなくてもうまくいく方法を思いつきました。
    ( ) [ ] { } ; , == = ++ += + ...
  • みたいに、記号類をスペース区切って並べた文字列を一つ作っておいて、これに対して一致するものを前から探せばいいわけです。
  • 一文字の=よりも二文字の==を前においておけばこれで問題ないわけです。
  • もっと早く思いつきたかったよー(笑)。

2026.01.12(月) #1

  • プログラムを実行中に一時停止して、それを全く別のアーキテクチャのCPU上で再開できる機能を考えたことがあります。エンディアンやビット数が違っていても問題ないです。
  • これはかつてエミュレータOSであるOSASKを考えていたころに「タスクセーブ」として考えていたものです。
  • これをそろそろ実装したら面白いかもしれないと今朝思ったものの、結局、そんな一時停止して別のアーキテクチャで再開したいほど実行時間の長いプログラムがたくさんあるかというと思いつかなくて、いまいち需要がないなーと思いました。・・・ということで、まだこれをやるべき時期じゃなさそうです。

2026.01.21(水) #0

  • C言語を工夫して使っていくか、C++をベースにするかで悩み中です。C++はメンバ関数があるのが非常にうらやましいです。
  • あるものは使えばいいっていうのは全くその通りなのですが、メンバ関数以外はそんなにうらやましくないしなあ・・・。
  • まあたぶん、まずはC言語で行けるところまで行く、にすると思います。私の性格からして。

2026.01.22(木) #0

  • さてではacl4ではなんていうクラス名にすればいいんだろう。 acl4_VecChr かなあ。長いなあ。 acl4_VCh くらいにしてしまいたいのだけど、そうするとたぶん初見では vector<char> の代用品のつもりっぽいなーってわかってもらえない。じゃあしょうがないか・・・。

2026.01.24(土) #0

  • a4_0001a4_0002を書きました。
  • 次はVecChrを作ろうと思います。
  • 5ページくらいになったら、目次ページを作ろうとも思っています。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2026-01-24 (土) 18:51:12 (142d)