コンパイルオプションの真偽を負論理から正論理に変更する

過去のすべての修正をフィックスし,まっさらなところから「再開発スタート版」を開始するという方針を立てて作業を続けている.fixという英語は「修理する」という意味に使われるが,ここでは「修正が完了し,バージョンの分岐が存在しなくなった状態」と定義する.つまり,#if, #else, #endif がソースコード上から消えることを意味する.nodule.h, Bobject.h で定義されていた条件コンパイル式に関してはすべてFIX完了し,「仮修正」,「暫定」の文字列はシステム内から完全に一掃された状態になったが.,分岐を持つ修正がまだかなりの個数残っている.これらはTEMPORARY, INCOMPLETE,および保留※で識別できるようにしてある.※はPENDINGで識別することにした.

TEMPORARYは一時的な修正で元のソースに戻すという前提で挿入されているもの,INCOMPLETEはまだ修正が確定していないとみなされるものという位置付けだ.これらが,その定義通りの状態になっているかどうかを試すには,#defineで定義された識別子の真・偽を切り替えてみればよい.TEMPORARYは一時的なコードなのだから,オンでもオフでも正常に動作しなくてはならない.従って,TEMPORARYプラグマがこの条件を満たしていれば,リリース版では復旧させるという条件下で存続が認められる.INCOMPLETEの場合も,同様に識別子をオン・オフして動作を確認することで正当性をチェックできる.もし,オンで不具合が出ればオフの論理が正しく,オフで停止すればオンの論理で確定できる.いずれでも不具合が発現しないとすれば(実際はほとんどそのようになっていると思う),その修正の意味を読んでメリットのある方を選択することになる.オンとオフの動作が同じなら,場合によってはTEMPORARYに移管するということも考えられる.

一つ問題なのは現状ではこれらのプラグマのほとんどが負論理になっているという点だ.これは#define文を省略して,識別子の意味と反対の論理で記述されているということを意味する.つまり,たとえば「この文は誤り@20201107」が未定義のまま使われている #ifdef この文は誤り@20201107 #else #endif のブロックではアクティブなブロックが誤りで,アクティブでないブロックが正しいという逆の意味になる.

#ifdef この文は誤り@20201107 (#defineしていないので偽)
  アクティブでないブロック(この文は正しい)
#else
  アクテイブなブロック(この文は誤り)
#endif

オン・オフの切り替えテストを行うためにはかなり不都合なので,とりあえず,すべてのプラグマで#define文を宣言して正論理に切り替えておく必要がある.まず,この修正をやっておこう.修正が必要なところは60箇所くらいある.ことのついでにこのような場所では#ifdef ではなく #if defined() を使うようにすることにしよう.こうしておけばより詳細な条件式を論理演算子を使って記述することもできるし,通常の#ifdefとも区別することができるだろう.

現在システム上には#ifdef文が893個存在する.#if文は69個あるが,うちVSが生成する*.rcの4個を除く65個はすべてVBの#If文(大文字のI)だ.いや,まだある.#ifndef が178箇所で使われている.#ifdefと合わせると1071個の条件コンパイル式があるということになる.これを総点検するというのは現実的ではない.ここでは#defineを置いていない条件式は「一掃」の対象になると宣言するに留めておこう.

▲「保留」されている論理を点検しフィックスする必要がある

ともかく,TEMPORARYとINCOMPLETEに含まれる項目を正論理に変えるところから始めよう.

▲終了時PAIRLISTのデストラクタでdetacount 非ゼロが起こり,ダンプが表示される.サンプルはゼルコバの木モジュール構成図 TEST.ZEL,基準ノードは#33 baselist,軸線図法.datacount=2.

▲#ifdef _DEBUG_で実行を抑制しているブロック/関数が135箇所ある.この中にはすでに廃れてしまっているロジックなども含まれると思われるが,一度点検する必要がある.

#ifdef OBSOLETE(廃れた)はNOTHINGと同様,無条件に削除してよい.いや,待てよ.何かおかしなことが起きている.OBSOLETEの中に含まれているGetOSDisplayStringという関数はそれ以外のどこにも含まれていないのに未定義にならない.⇒いや,出てきた.未解決の外部シンボルとなっている.つまり,この関数はOBSOLETEにはできない.あるいは完全に廃止するかのどちらかだ.このコードは確か外部から拾ってきたものでOSのバージョンなどを取得するためのルーチンだ.残しておいてもよいのではないか?⇒if !defined(GetOSDisplayStringを停止@20190109)で使えるようにしておいた.

この関数を廃止した理由はこのコードがWindows 7 あたりまでしかサポートしていないためだ.修正すれば,Windows 10でも使えるようになるかもしれないが,’GetVersionExA’: が非推奨 というエラー(警告)が出てビルドできないので差し替えが必要だ.警告をエラーとして扱うというオプションを緩和すれば使えないことはないが…このようなこともあるのでいきなりOBSOLETEを削除もリスクがある.⇒OBSOLETE 3件を削除した.NOTHINGは6件ある.⇒始末した.

OCXで使われているint TEMPORARYの意味・用途が不明.「プレビュー→ノーマル一時切り替え中」となっているが,値はゼロのまま変化していない.⇒廃止でよいと思う.TEMPORARYはすべて整理した.INCOMPLETEに移ろう.INCOMPLETE@20190128はdecidePrimaryNodeを隠蔽しているが#elseは空で,改訂版のdecidePrimaryNodeは無条件で動いている.これはすでに確定しているものと判断する.INCOMPLETE@20190129には複数の用途がある.

  1. decidePrimaryNodeで(primarynode->getmarglink() != getOyalink())のとき停止しない
  2. SetMinorTribeで「基準ノードを参照する系列の優先ノード切り替えは禁止」を無視する

多分どちらも反例があると思われるので検証が必要だ.INCOMPLETE@20190202はもっといろいろな場合を含んでいる.

  1. EstablishMajorTribeChainで「系列順位が逆転している場合」を無視
  2. MakeUpTreeで先祖ノードが単身先祖配偶者のとき,EstablishMajorTribeChain(先行系列との接続関係を確立する)を実行しない
  3. TRIBEBOX::MakeUpTreeのループでSetPrimeNode(系列優先仮ノードと優先実ノードを設定)を実行する
  4. MakeUpTreeで「系列優先ノードが隠蔽されている」とき停止しない
  5. SetupPrimaryNodeで始系列の場合も「系列優先実ノードが家内婚配偶者で隠蔽されている場合」の探索を実施する
  6. SetupPrimaryNodeで始系列でない場合には優先実ノードが隠蔽されている場合を認める

これはおそらく完全に確定した修正のように思われる.INCOMPLETE@20190204を見てみよう.

  1. TRIBELIST::MakeUpTreeでEstablishMajorTribeChain(先行系列との接続関係を確立する)を実行する代わりにSetupPrimaryNode(系列優先仮ノードと優先実ノードを設定)している
  2. setMajortribeでsetrealnode(系列優先実ノード参照をリセット)しない
  3. GetMajorTribeChainでIsSolidNameBox検査とsetrealnodeを実行している
  4. TRIBEBOX::GetRealnodeで系列優先実ノードが見つからないとき,優先仮ノードのNameBoxから取り出している処理を廃止

これも確定しているように思われるが,項目4が正当であるためには,前段で系列優先仮ノードから必ず優先実ノードを決定できることが示されなくてはならない.INCOMPLETE@20190130は2箇所だけだ.

  1. ReduceMultiCardで人名枠をIsVisibleCardではなくIsValidNameBoxで判定している
  2. ReduceMultiCardで仮ノード消去の対象カードから配偶者を除外している

項目2は配偶者が消去されるのはBTWの場合だけということを主張している.これは正しいのではないか?最後のINCOMPLETE@20190131は6箇所だ.

  1. TRIBELIST::MakeUpTreeで系列優先仮ノードが隠蔽されているとき,優先仮ノードを探索してTRIBELIST::MakeUpTree(系列優先仮ノードと優先実ノードを設定)するブロックを廃止している.ただし,#elseブロックは空なのでこれは確定と考えるしかない.SetupPrimaryNodeには「隠蔽された系列優先ノードの補正」という処理が入っているので,おそらくここでは不用になったものと思われる.
  2. CARDLINK::getProxyで系列優先仮ノードを無条件で可視化している.いや,違う.これは一般の人名ノードの場合だ.結婚リンクを与えて,その結婚リンクに繋がる仮ノードを返すという関数だ.ここで可視化する必要があるのかどうか?という点に関しては疑問がある.
  3. TRIBEBOX::SetPrimeNodeでSetupPrimaryBoxの代わりにsetPrimenodeを呼び出している.SetupPrimaryBoxという関数はすでに廃止されているので,これは確定だ.
  4. TRIBEBOX::GetRealnodeで系列優先実ノードが有効なカードでなかった場合の処理が挿入されている.#elseにはこれを代替するようなコードは含まれていないので,これで確定とするしかない.
  5. Bobject::getvisibleで(hidden() && visible && PHASE >= INITIALIZED)のとき停止するのを抑制している.hiddenかつvisibleという状態はあり得ないとしているのか?無視してよいと見ているのか,意図が不明なので暫定的に検査を復活させておく.

項目2で隠蔽ノードまで無差別に可視化しているところを見ると,この修正ではカードが隠蔽状態にあることと可視であることは無関係と考えているように思われる.実際,隠蔽状態にあるノードが表示されないというのは事実だがそれは可視状態であるか否かということとは無関係だ.従って,項目2も確定と見てよいのではないだろうか?そうすれば,INCOMPLETE@20190131のプラグマは完全に消える.まあ,一応残して様子を見ることにしよう.まず,TEMPORARYのカテゴリに属するオプションを全部止めて動作を確認しておこう.これらは止めた状態がノーマルな状態のはずだから,当然動かなくてはならない.

GetOSDisplayStringで「’GetVersionExA’: が非推奨として宣言されました。」が出る.「GetOSDisplayStringの使用停止@20190109」がTEMPORARYに入っている.⇒これはPENDING というカテゴリを作って移しておこう.

上の1件を除く4件のTEMPORARYオプションを止めて走らせたところ,Bobject::getvisibleで停止した.これは上記INCOMPLETE@20190131の項目5で「意図が不明なので暫定的に検査を復活させておく」とした論理に該当する.これは現行論理で確定でよいと思われるが,気になるのでどんなノードが引っかかっているのかを見ておこう.printnamaeでダンプしようとしたが,この関数からgetvisibleを呼び出しているのでスタックオーバーフローが発生してしまう.printshortなら大丈夫だろう…⇒#279 kakeizu(0)だ.PHASEは12でMAKEUPTREE.系図木を構築しているところだ.Yリストへの繋ぎ込みはこのフェーズで実行されるので,このフェーズでは無視としてみよう.⇒これで一応描画できた.

完全木テストを通してみよう.全体図が通れば親族図は大体通るので全体図テストでもよかったのかもしれないが,サンプルが小さいのでそんなには掛からないだろう…この版は多分完全被参照リスト管理が動いているのでかなり遅い…それでも1分以内に終わった.添付サンプルも問題ないようだ.次にINCOMPLETEのカテゴリのオプションをすべて止めて動作を見ることにしよう.いや,この辺りで一度バックアップを取っておいた方がよいかもしれない…次はINCOMPLETEオプションをすべて止めて動作を見ることにする.

TRIBEBOX::GetAlternativePrimeNodeで停止した.サンプルは渋沢一族8.ZEL.基準ノードは#211 大川平兵衛の息子.このエラーはMakeUpTree→EstablishMajorTribeChainの中で起きているものだ.forループの中で (T2 == this) のとき,(oyalink)で停止する.これにおそらく一番近いのはINCOMPLETE@20190202なのでこのオプションを復活させて走らせてみよう.⇒+INCOMPLETE@20190131で動作

TRIBEBOX::GetRealnodeにかなりひどいバグがあった.これはオプションとはまったく無関係の独立のバグだ.realodeが空のときにrealnode->getrelationを呼び出そうとしている.考えられないミスだ.ここには「実ノードが単親婚保持ノードの配偶者の場合:配偶者の配偶者を実ノードとする」という説明が付いている.こんな初歩的なバグが残っているとは…⇒このバグが発現しなかったということはこのフローを踏まなかったということなので廃棄しておこう.⇒解決

INCOMPLETE@20190131を追加してこの図面は出力できた.渋沢の全体図テストをやってみよう.いや,それどころではない.下のパネルを出した状態でハングしてしまった.

image

再現しなくなった…⇒表示が出るまでに時間が掛かっているのではないか?通常はOKボタンで直ちにパネルを閉じるが,何かのタイミングで閉じるのが遅くなったための現象ではないか?渋沢で描画までに8.5秒掛かっている.PAIRLISTのダンプを出しているためかもしれない…

INCOMPLETE@20190131単独では同じエラーが発現する.INCOMPLETE@20190131と@20190202がセットとなる必要があるので,この2つは確定ということにしておこう.@20190131の修正は例の隠蔽ノード可視に関わるものなので,この論理が動作に不可欠であることが分かる.@20190202は未決が7個もあるので一発で確定でよいのかどうか不安もあるが,一連の修正として一括確定とする.

INCOMPLETE@20190129の修正は2箇所で,一つはASSERT_NEVER(primarynode->getmarglink() != getOyalink())の停止,もう一つは「優先仮ノードが変化しない場合,系列に多重カードが存在する場合は切り替えを許可する」という緩和策を廃止して一律に基準ノード参照系列をリセットするものだが,いずれもオリジナルを復活させておくことにする.(オリジナルの場合,条件が成立するときは停止するようになっている)

INCOMPLETE@20190130は確定でよいと思われる.また,この確定により,IsVisibleCardは使用されないことが確定する.INCOMPLETE@20190204の修正の主眼はEstablishMajorTribeChainの廃止ではないかと思う.その代わりに導入されたのが,SetupPrimaryNodeだろう.EstablishMajorTribeChainの呼び出しを行わないというのはすでに@20190202で導入されていてそれを徹底したのがINCOMPLETE@20190204ということになるのではないか?どの道,その方向に進んでいるのだから徹底した方がよい.

これでINCOMPLETEはすべてフィックスされた.これらのオプションは2019年1月28日から2月4日までの比較的短い期間に集中している.つまり,一貫した一つのテーマの下に進められたものと思われる.

作業開始時点で893個あった#ifdefは873個になった.わずか20個しか減っていないが,後の残りは原則すべて現状でFIXでよいのではないかと思う.日本語で定義されている分だけでも確定してしまいたいのだが,どのくらい時間が掛かるだろうか?⇒意外にそれほどの時間は掛からないものかもしれないが…プラグマが一つのファイルに限定される場合にはヘッダファイルを使わずにCPPだけで始末ができるだろう.そのやり方ならあまり時間は掛からないと思う.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA