* ネスト可能なダブルクォーテーションからはじまる、プリプロセッサ拡張計画 -(by [[K]], 2025.10.06) ** (1) -私はかつてプリプロセッサが嫌いで、C言語にプリプロセッサがあることはC言語の欠点だと思っていました。プリプロセッサを使わないで済むように、C言語は拡張されるべきだとさえ思っていました。 -でも今は違ってC言語がプリプロセッサとそれ以降の処理フェーズに分かれていることは、むしろうまい仕組みだと思っています。・・・この境地に至るまで10年くらいかかった気がします。 -さて私は以前から、数式のカッコはネスト(=入れ子)が簡単にできるのに、文字列はそうなっていないのは不便だと思ってきました。それで、 [" ~ "] という記法まで考えたのですが、実はまだしっくり来ていませんでした。・・・今回 /" ~ "/ という記法を考えました。これはうまいと思うので、当面はこれでやってみます。 -この「ネスト可能なダブルクォーテーション」があると、プリプロセッサをさらに便利に拡張できる気がするので、しばらくはそれをやってみます。 ** (2) -プリプロセッサの #define は互換性のために維持しますが、追加で #.def というのを作ります。 #.def Abc(x, y, z), /"myfunc(x*y, x+y, z-x)"/ --このとき、右側にネスト可能なダブルクォーテーションが使われています。 --この #.def は、「ネスト可能なダブルクォーテーション」のおかげで、どこが #.def の終わりなのかが容易にわかります。だからみっともないバックスラッシュ(もしくは円マーク)を多用せずとも、複数行で書くことができます。 --この #.def は、ネスト可能なダブルクォーテーションのおかげで、どこが #.def の終わりなのかが容易にわかります。だからみっともないバックスラッシュ(もしくは円マーク)を多用せずとも、複数行で書くことができます。 #.def MakeOp2Func(nam, op), /" int nam(int x, int y) { return x op y; } "/ --この「どこが #.def の終わりなのかわかる」を利用して、1行に複数の #.def を書くことも許します。 #.def Const1, /"123"/ #.def Const2, /"456"/ -#if 類も拡張形式を追加して、 #.if や #.else などを用意します。 #.if !defined(Const1), /"#.def Const1, /"123"/ "/ --#.if がどこで終わるのかはすぐにわかるので、 #.endif はありません。 -#.def の中に #.if などを含むことができます。かなり複雑な記述が可能になります。 ** (3) -上記説明を書いているときに、 #.if !defined(Const1), /"#.def Const1, /"123"/ "/ -が読みやすくないと感じたので、以下の記法も許すことにします。 #.if !defined(Const1), [/"#.def Const1, [/"123"/]"/] #.if !defined(Const1), {/"#.def Const1, [/"123"/]"/} #.if !defined(Const1), </"#.def Const1, (/"123"/)"/> -また、ネストするつもりがない時は、 "..."で代用することも許します。 #.if !defined(Const1), [/"#.def Const1, "123" "/] ** (4) -["..."]という記法を思いついた時のメモ: [[a24_idea001]] -なぜ ["..."] がしっくりこないと思ったのか? --C言語では配列の添え字に文字列を書くことはないですが、ほかの言語で辞書型などをサポートすれば、これもないとは言えなくなるので、あまり応用が利かないなと思ったのです。 --Pythonでは list = [1, “hello”, 3.14] みたいな書き方も普通にあり得て、["..."]形式は紛らわしいと思いました。 -[[a24_longdef]] では #longdef という -[[a24_longdef]] では #longdef というプリプロセッサ拡張を考えて実装しましたが、ネスト可能なダブルクォーテーションがあって、 #.def が使えるなら、 #longdef と同等のことはできてしまうので、 #longdef はいらなくなります。 ** (5) -以下はネスト可能なダブルクォーテーションとは無関係ですが、ついでなのでやります。 #.adddef Abc, "+1" // Abcのdef内容に +1 を書き足します。 #.def Abc, "0" #.def IncAbc, /"#.adddef Abc, "+1" "/ printf("%d ", Abc); IncAbc; printf("%d ", Abc); IncAbc; printf("%d ", Abc); → 「0 1 2 」と表示されます。 --この機能は、 [[a21_txt01_5]] の中に出てきた phrCmp() の pid の管理が面倒だと思って考え出したものです。 --ほかにこんな使い方もできます。 p0 = malloc(123); #.adddef FreBuf, "free(p0);" p1 = malloc(456); #.adddef FreBuf, "free(p1);" p2 = malloc(789); #.adddef FreBuf, "free(p2);" ... ... ... FreBuf; #.undef FreBuf; // 新しくmallocを追加しても、記述を分散させずに済む。 --#.adddef は #.add とも書けます。 -最後に説明するのは #.final です。これは #.adddef した最後の値を前方参照するときに使います。なお、この用途で使う場合、 #.adddef していく内容に、#系の記述やマクロは含められません。 #.def Sz "0" int a[#.final(Sz)]; ... a[Sz] = 123; #.add Sz, "+1" ... a[Sz] = 456; #.add Sz, "+1" ... #.undef Sz; ** (6) -些末な機能として、#.!(...) があります。これは...の中をsprintfで評価してその結果を返します。 puts(# #.!("Sz=%d", Sz)); → puts("Sz=2"); になる。 -(以下編集中)