ネスト可能なダブルクォーテーションからはじまる、プリプロセッサ拡張計画
(1)
- 私はかつてプリプロセッサが嫌いで、C言語にプリプロセッサがあることはC言語の欠点だと思っていました。プリプロセッサを使わないで済むように、C言語は拡張されるべきだとさえ思っていました。
- でも今は違ってC言語がプリプロセッサとそれ以降の処理フェーズに分かれていることは、むしろうまい仕組みだと思っています。・・・この境地に至るまで10年くらいかかった気がします。
- さて私は以前から、数式のカッコはネスト(=入れ子)が簡単にできるのに、文字列はそうなっていないのは不便だと思ってきました。それで、 [" ~ "] という記法まで考えたのですが、実はまだしっくり来ていませんでした。・・・今回 /" ~ "/ という記法を考えました。これはうまいと思うので、当面はこれでやってみます。
- この「ネスト可能なダブルクォーテーション」があると、プリプロセッサをさらに便利に拡張できる気がするので、しばらくはそれをやってみます。
(2)
- プリプロセッサの #define は互換性のために維持しますが、追加で #.def というのを作ります。
#.def Abc(x, y, z), /"myfunc(x*y, x+y, z-x)"/
- このとき、右側にネスト可能なダブルクォーテーションが使われています。
- この #.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)
- なぜ ["..."] がしっくりこないと思ったのか?
- C言語では配列の添え字に文字列を書くことはないですが、ほかの言語で辞書型などをサポートすれば、これもないとは言えなくなるので、あまり応用が利かないなと思ったのです。
- Pythonでは list = [1, “hello”, 3.14] みたいな書き方も普通にあり得て、["..."]形式は紛らわしいと思いました。
(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を追加しても、記述を分散させずに済む。
- 最後に説明するのは #.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"); になる。