はじめに
本記事は日本語プログラミング言語Mind8のC言語で実装されているランタイムディスパッチャをC#で代替実装し、.NETのライブラリ資産を利用しやすくしたいという思惑の元に遂行されている企画の続きです。前回の記事で検証用コンソールの完走版にコードを追加した結果、文字列実体の「空列」で止まっていることが判明しました。
前提条件
Windows11 Pro 22H2
VSCode(Visual Studo Code) 1.86.1
Microsoft Visual C++ 2008 Express Edition
Mind Version 8.0.08 for Windows
C# 12
dotnet-sdk-8.0.204-win-x64
VSCodeの拡張機能
C/C++ for Visual Studio Code 1.18.5 Microsoft
C/C++ Extension Pack 1.3.0 Microsoft
.NET Install Tool 2.0.2 Microsoft
Base language support for C# 2.18.16 Microsoft
C/C++のデバッガはCで実装されているMind8kernelの動作をデバッグ実行で探るために使用します。こちらの記事の環境となります。
カスタマイズConsoleのビルド
Mind開発者の@killyさんよりご提供いただいた情報に従い、下記のようにカスタマイズConsoleのビルド用のフォルダfilelevel群を作成しています。
ビルド用フォルダ構成
現状は下記のようなフォルダ構成となります。filedummyフォルダは起動検証用Consoleのビルド環境です。fileフォルダは正規のソースファイルが格納されたフォルダです。
filedummyの内容はこちらの記事を、filelevel1,2(旧0)の内容はこちらの記事を参照してください。
C:\developments\vscode\mind8>tree
C:.
├─bin
├─file
│ └─obj
├─filedummy <--完走
│ └─obj
├─filelevel0 <--完走
│ └─obj
├─filelevel1 <--完走
│ └─obj
├─filelevel2 <--未完走
│ └─obj
├─filelevel3 <--完走
│ └─obj
├─filelevel4 <--完走
│ └─obj
├─filelevel5 <--未完走
│ └─obj
├─filelevel6 <--未完走
│ └─obj
├─kernel
│ └─.vscode
├─lib
├─libY
└─sample
filelevel5,6フォルダは本記事のバージョンの格納フォルダです。filelevel2のソースコードの一部を追加しています。
お題のMindソースコード
こちらの記事より「コンソール初期化・基本部」の定義部に独自に簡略化した「私のプログラム名と起動パラメータを設定0」を導入しています。
コンソール初期化・基本部とは (・ → ・)
(しばらくはシステムコールするな)
終了パラメータを クリアし ※CCONST.SRC
エラー文字列初期化し ※CERROR.SRC
空白文字列初期化し ※COUTPUT.SRC
エラー出力を本来の出力に切り替え ※COUTPUT.SRC
私のプログラム名と起動パラメータを設定0し
。
各ライブラリ初期化とは 本定義 (・ → ・)
コンソール初期化・基本部し ※本ソース示すること。
この範囲は今回の記事でも同じです。今回は「私のプログラム名と起動パラメータを設定0」の内容を変更しています。
下記は完走しているlevel4の状態です。
Mind文字列に変換して次のアドレスを得る0とは 処理単語 .N ※1999.07.04訂正
(ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
アドレス1は 変数
バイト位置は 変数 ※←32bitに(1999.07.04)
アドレス1に 入れ
。
私のプログラム名と起動パラメータを設定0とは (・ → ・)
※※※※※※※※※※※※※※※※※※※※※※※※※
※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
※ ・この中で「私のプログラム名」もセットする ※
※※※※※※※※※※※※※※※※※※※※※※※※※
(私のプログラム名を決定)
c_mcodeFullFilenameを Mind文字列に変換して次のアドレスを得て0
。
これに対して前回は
level5
Mind文字列に変換して次のアドレスを得る0とは 処理単語 .N ※1999.07.04訂正
(ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
アドレス1は 変数
バイト位置は 変数 ※←32bitに(1999.07.04)
アドレス1に 入れ
アドレス1を バイトロードし ゼロ?
ならば 空列と 0を 返し
終り
つぎに
空列と 0を 返し
。
Mind文字列に変換0とは 処理単語 .N
(ASCIZアドレス → 文字列)
Mind文字列に変換して次のアドレスを得て0 捨てること。
私のプログラム名と起動パラメータを設定0とは (・ → ・)
※※※※※※※※※※※※※※※※※※※※※※※※※
※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
※ ・この中で「私のプログラム名」もセットする ※
※※※※※※※※※※※※※※※※※※※※※※※※※
(私のプログラム名を決定)
c_mcodeFullFilenameを Mind文字列に変換0して
捨てること
。
level6
Mind文字列に変換して次のアドレスを得る0とは 処理単語 .N ※1999.07.04訂正
(ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
アドレス1は 変数
バイト位置は 変数 ※←32bitに(1999.07.04)
アドレス1に 入れ
空列と 0を 返し
。
Mind文字列に変換0とは 処理単語 .N
(ASCIZアドレス → 文字列)
Mind文字列に変換して次のアドレスを得て0 捨てること。
私のプログラム名と起動パラメータを設定0とは (・ → ・)
※※※※※※※※※※※※※※※※※※※※※※※※※
※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
※ ・この中で「私のプログラム名」もセットする ※
※※※※※※※※※※※※※※※※※※※※※※※※※
(私のプログラム名を決定)
c_mcodeFullFilenameを Mind文字列に変換0して
捨てること
。
としていました。両者は完走しませんでした。そこでlevel6で下記のように「空列と」をとってみるとこれは完走することがわかりました。
level6改
- 空列と 0を 返し
+ 0を 返し
ここまでが前回の結果で、「空列」は下記のように「文字列実体」として宣言されているところまでを確認しておりました。
空列は 文字列実体 長さ 0。
level2の「私のプログラム名と起動パラメータを設定」の完全記述版でも、「文字列実体」が出てきていたような気がして、以前として文字列の扱いは不完全なので、このあたりでこけているっぽいことが判明しました。
そこで前回記事のコメントでMind開発者の@killyさんより、
空列を
と書くのと
「」を
と書くのは効果として同じなのですが、前者がデータ領域上の文字列であることに比べ、後者はMコード領域上の文字列という違いがあります。
とのアドバイスをいただきましたので、空列が問題というよりはデータ領域上のポインティングの問題かどうかを切り分けるため、level5,6のコードを下記のように修正して実行してみます。
level6改2
- 空列と 0を 返し
+ 「」を 返し
level5は上記の複数ヶ所を同様に訂正。
本来のお題のMind8のソースファイル
こちらの記事を参照してください。
お題のMind8の中間コード実行リスト
今回は省略しました。
お題のMind8の中間コードのC#代替ディスパッチャ実行リスト
まずlevel5改の結果です。完走しました。
level5改
SqNo mcode mc(dec) mpoint dtp.point dtp+0 dtp+1 rtp.point rtp+0 rtp+1
1 8019 32793 114 1024 0 0 1024 0 0
2 002F 47 102 1024 0 0 1023 114 0
3 0012 18 8094 1024 0 0 1023 114 0
4 0036 54 8096 1024 0 0 1023 114 0
5 0080 128 8102 1024 0 0 1023 114 0
6 0036 54 8104 1024 0 0 1023 114 0
7 0070 112 8110 1024 0 0 1023 114 0
8 803A 32826 8112 1024 0 0 1023 114 0
9 002F 47 238 1024 0 0 1022 8112 114
10 80E9 33001 8090 1024 0 0 1022 8112 114
11 0036 54 8072 1024 0 0 1021 8090 8112
12 0071 113 8078 1024 0 0 1021 8090 8112
13 8046 32838 8080 1024 0 0 1021 8090 8112
14 8045 32837 326 1024 0 0 1020 8080 8090
15 0012 18 314 1024 0 0 1019 326 8080
16 0036 54 316 1024 0 0 1019 326 8080
17 0074 116 322 1024 0 0 1019 326 8080
18 0020 32 324 1024 0 0 1019 326 8080
19 0020 32 328 1024 0 0 1020 8080 8090
20 80A3 32931 8082 1024 0 0 1021 8090 8112
21 0036 54 3884 1024 0 0 1020 8082 8090
22 0012 18 3890 1024 0 0 1020 8082 8090
23 016E 366 3892 1024 0 0 1020 8082 8090
24 0020 32 3898 1024 0 0 1020 8082 8090
25 808F 32911 8084 1024 0 0 1021 8090 8112
26 0097 151 3626 1024 0 0 1020 8084 8090
27 0065 101 3628 1022 0 2 1020 8084 8090
28 0020 32 3634 1024 0 0 1020 8084 8090
29 80E8 33000 8086 1024 0 0 1021 8090 8112
30 0261 609 8064 1024 0 0 1020 8086 8090
31 80E7 32999 8066 1022 0 2151879280 1020 8086 8090
32 80E6 32998 8058 1022 0 2151879280 1019 8066 8086
33 001A 26 8026 1022 0 2151879280 1018 8058 8066
34 006B 107 8028 1022 0 2151879280 1016 0 0
35 0055 85 8032 1024 0 0 1016 2151879280 0
36 008F 143 8036 1022 0 2151879280 1016 2151879280 0
37 00ED 237 8038 1022 0 2151879280 1016 2151879280 0
38 00A5 165 8050 1024 0 0 1016 2151879280 0
39 0095 149 8054 1022 0 8052 1016 2151879280 0
40 0022 34 8056 1020 0 0 1016 2151879280 0
41 0122 290 8060 1020 0 0 1019 8066 8086
42 0020 32 8062 1022 0 8052 1019 8066 8086
43 0122 290 8068 1022 0 8052 1020 8086 8090
44 0020 32 8070 1024 0 0 1020 8086 8090
45 0020 32 8088 1024 0 0 1021 8090 8112
46 0020 32 8092 1024 0 0 1022 8112 114
47 00A5 165 8114 1024 0 0 1023 114 0
48 803C 32828 8138 1022 20 8116 1023 114 0
49 002F 47 246 1022 20 8116 1022 8138 114
50 001A 26 5802 1022 20 8116 1022 8138 114
51 006E 110 5804 1022 20 8116 1020 8086 8090
52 0015 21 5808 1024 0 0 1020 20 8090
53 00ED 237 5810 1022 0 1 1020 20 8090
54 0022 34 5830 1024 0 0 1020 20 8090
55 00A5 165 8140 1024 0 0 1023 114 0
56 00C1 193 8158 1022 14 8142 1023 114 0
$$COLD_FORTH
57 0020 32 8160 1024 0 0 1023 114 0
58 80F4 33012 116 1024 0 0 1024 0 0
59 00A5 165 8610 1024 0 0 1023 116 0
60 8083 32899 8628 1022 14 8612 1023 116 0
61 0012 18 3510 1022 14 8612 1022 8628 116
62 004E 78 3512 1022 14 8612 1022 8628 116
63 00EC 236 3518 1020 0 0 1022 8628 116
64 0096 150 3524 1022 14 8612 1022 8628 116
65 026D 621 3526 1020 0 1 1022 8628 116
Hello by mind8
66 0020 32 3528 1024 0 0 1022 8628 116
67 0020 32 8630 1024 0 0 1023 116 0
68 801A 32794 118 1024 0 0 1024 0 0
69 002F 47 106 1024 0 0 1023 118 0
70 00A5 165 8188 1024 0 0 1023 118 0
71 00C1 193 8202 1022 10 8190 1023 118 0
実行終り
72 801B 32795 8204 1024 0 0 1023 118 0
73 002F 47 110 1024 0 0 1022 8204 118
74 00A5 165 8162 1024 0 0 1022 8204 118
75 00C1 193 8184 1022 18 8164 1022 8204 118
実行終り時の処理
76 0020 32 8186 1024 0 0 1022 8204 118
77 0012 18 8206 1024 0 0 1023 118 0
78 004E 78 8208 1024 0 0 1023 118 0
79 0014 20 8214 1022 0 0 1023 118 0
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[13396] mind8dispatch.dll' がコード 0 (0x0) で終了しました。
続いてlevel6改2の結果です。こちらも完走しました。
level6改2
SqNo mcode mc(dec) mpoint dtp.point dtp+0 dtp+1 rtp.point rtp+0 rtp+1
1 8019 32793 114 1024 0 0 1024 0 0
2 002F 47 102 1024 0 0 1023 114 0
3 0012 18 8078 1024 0 0 1023 114 0
4 0036 54 8080 1024 0 0 1023 114 0
5 0080 128 8086 1024 0 0 1023 114 0
6 0036 54 8088 1024 0 0 1023 114 0
7 0070 112 8094 1024 0 0 1023 114 0
8 803A 32826 8096 1024 0 0 1023 114 0
9 002F 47 238 1024 0 0 1022 8096 114
10 80E9 33001 8074 1024 0 0 1022 8096 114
11 0012 18 8054 1024 0 0 1021 8074 8096
12 0036 54 8056 1024 0 0 1021 8074 8096
13 0071 113 8062 1024 0 0 1021 8074 8096
14 8046 32838 8064 1024 0 0 1021 8074 8096
15 8045 32837 326 1024 0 0 1020 8064 8074
16 0012 18 314 1024 0 0 1019 326 8064
17 0036 54 316 1024 0 0 1019 326 8064
18 0074 116 322 1024 0 0 1019 326 8064
19 0020 32 324 1024 0 0 1019 326 8064
20 0020 32 328 1024 0 0 1020 8064 8074
21 80A3 32931 8066 1024 0 0 1021 8074 8096
22 0036 54 3884 1024 0 0 1020 8066 8074
23 0012 18 3890 1024 0 0 1020 8066 8074
24 016E 366 3892 1024 0 0 1020 8066 8074
25 0020 32 3898 1024 0 0 1020 8066 8074
26 808F 32911 8068 1024 0 0 1021 8074 8096
27 0097 151 3626 1024 0 0 1020 8068 8074
28 0065 101 3628 1022 0 2 1020 8068 8074
29 0020 32 3634 1024 0 0 1020 8068 8074
30 80E8 33000 8070 1024 0 0 1021 8074 8096
31 0261 609 8046 1024 0 0 1020 8070 8074
32 80E7 32999 8048 1022 0 4224635920 1020 8070 8074
33 80E6 32998 8040 1022 0 4224635920 1019 8048 8070
34 001A 26 8026 1022 0 4224635920 1018 8040 8048
35 006B 107 8028 1022 0 4224635920 1016 0 0
36 00A5 165 8032 1024 0 0 1016 4224635920 0
37 0095 149 8036 1022 0 8034 1016 4224635920 0
38 0022 34 8038 1020 0 0 1016 4224635920 0
39 0122 290 8042 1020 0 0 1019 8048 8070
40 0020 32 8044 1022 0 8034 1019 8048 8070
41 0122 290 8050 1022 0 8034 1020 8070 8074
42 0020 32 8052 1024 0 0 1020 8070 8074
43 0020 32 8072 1024 0 0 1021 8074 8096
44 0020 32 8076 1024 0 0 1022 8096 114
45 00A5 165 8098 1024 0 0 1023 114 0
46 803C 32828 8122 1022 20 8100 1023 114 0
47 002F 47 246 1022 20 8100 1022 8122 114
48 001A 26 5802 1022 20 8100 1022 8122 114
49 006E 110 5804 1022 20 8100 1020 8070 8074
50 0015 21 5808 1024 0 0 1020 20 8074
51 00ED 237 5810 1022 0 1 1020 20 8074
52 0022 34 5830 1024 0 0 1020 20 8074
53 00A5 165 8124 1024 0 0 1023 114 0
54 00C1 193 8142 1022 14 8126 1023 114 0
$$COLD_FORTH
55 0020 32 8144 1024 0 0 1023 114 0
56 80F4 33012 116 1024 0 0 1024 0 0
57 00A5 165 8594 1024 0 0 1023 116 0
58 8083 32899 8612 1022 14 8596 1023 116 0
59 0012 18 3510 1022 14 8596 1022 8612 116
60 004E 78 3512 1022 14 8596 1022 8612 116
61 00EC 236 3518 1020 0 0 1022 8612 116
62 0096 150 3524 1022 14 8596 1022 8612 116
63 026D 621 3526 1020 0 1 1022 8612 116
Hello by mind8
64 0020 32 3528 1024 0 0 1022 8612 116
65 0020 32 8614 1024 0 0 1023 116 0
66 801A 32794 118 1024 0 0 1024 0 0
67 002F 47 106 1024 0 0 1023 118 0
68 00A5 165 8172 1024 0 0 1023 118 0
69 00C1 193 8186 1022 10 8174 1023 118 0
実行終り
70 801B 32795 8188 1024 0 0 1023 118 0
71 002F 47 110 1024 0 0 1022 8188 118
72 00A5 165 8146 1024 0 0 1022 8188 118
73 00C1 193 8168 1022 18 8148 1022 8188 118
実行終り時の処理
74 0020 32 8170 1024 0 0 1022 8188 118
75 0012 18 8190 1024 0 0 1023 118 0
76 004E 78 8192 1024 0 0 1023 118 0
77 0014 20 8198 1022 0 0 1023 118 0
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[13292] mind8dispatch.dll' がコード 0 (0x0) で終了しました。
とりあえず「空列と」を書いた場合の文字列実体の扱いに問題がありそうであることがわかりました。
つづく
この記事を書いている途中では文字列実体のアドレッシングがどのようにまずいのかは未確認ですが、引き続き調査を行って参ります。次回解決編に乞うご期待?
補足
level6(改、改2でないやつ)のC#代替ディスパッチャ実行リストとCディスパッチャ実行リストを、停止する直前あたりで比較してみました。
level6 C#代替ディスパッチャ実行リスト
SqNo mcode mc(dec) mpoint dtp.point dtp+0 dtp+1 rtp.point rtp+0 rtp+1
1 8019 32793 114 1024 0 0 1024 0 0
31 80E7 32999 8050 1022 0 2322422464 1020 8070 8074
32 80E6 32998 8042 1022 0 2322422464 1019 8050 8070
33 001A 26 8026 1022 0 2322422464 1018 8042 8050
34 006B 107 8028 1022 0 2322422464 1016 0 0
35 0052 82 8032 1024 0 0 1016 2322422464 0
36 0A74 2676 8034 1024 0 0 1016 2322422464 0
例外がスローされました: 'System.IndexOutOfRangeException' (mind8dispatch.dll の中)
level6 Cディスパッチャ実行リスト
SqNo mcode mc(dec) mpoint dtp.point dtp+0 dtp+1 rtp.point rtp+0 rtp+1
1 8019 32793 114 1024 1869567068 6058860 1024 0 0
31 80E7 32999 8050 1022 0 4646640 1020 13987390 13987394
32 80E6 32998 8042 1022 0 4646640 1019 13987370 13987390
33 001A 26 8026 1022 0 4646640 1018 13987362 13987370
34 006B 107 8028 1022 0 4646640 1016 0 0
35 0052 82 8032 1024 1869567068 6058860 1016 4646640 0
36 0095 149 8038 1022 0 13991628 1016 4646640 0
mcode 0052の実行結果が異なっていることがわかります。006Bでデータスタックの状態が異なっているように見えるのは初期状態の違い(C#は先頭値、Cは末尾アドレスが初期値)のようでした。
C#代替実装のmcode 0052を確認してみますと、関数定義だけで中身は実装されていませんでした。他のスタックマクロは何とか解釈できたと思って実装してあるのですが、0052だけマージンの解釈に戸惑い保留としていたようです。
/*--------------------- 変数の直接読み出し ----------------------*/
private void ZzReadBvar(){
/* Mコード=0x004C */
// UCHAR *varAddr;
// varAddr = DataBase + FETCH_MCODE_LONG;
// PUSH_L( *varAddr );
// PUSH_F( 0 );
ap.ResetDataIndex(mp.FetchMcodeInt());
dtp.PushUl(ap.GetUb());
dtp.PushUl(0);
}
private void ZzReadWvar(){
/* Mコード=0x004D */
// USHORT *varAddr;
// varAddr = (USHORT *)(DataBase + FETCH_MCODE_LONG);
// PUSH_L( *varAddr );
// PUSH_F( 0 );
ap.ResetDataIndex(mp.FetchMcodeInt());
dtp.PushUl(ap.GetUs());
dtp.PushUl(0);
}
private void ZzReadDvar(){
/* Mコード=0x004E */
// LONG *varAddr;
// varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
// PUSH_L( *varAddr );
// PUSH_F( 0 );
ap.ResetDataIndex(mp.FetchMcodeInt());
dtp.PushUl(ap.GetUl());
dtp.PushUl(0);
}
private void ZzReadLvar(){
/* Mコード=0x004F */
// ULONG *varAddr;
// varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
// PUSH_L( varAddr[0] ); /* push low double */
// PUSH_L( varAddr[1] ); /* push high double */
ap.ResetDataIndex(mp.FetchMcodeInt());
dtp.PushUl(ap.GetUl());
dtp.PushUl(ap.GetUl());
}
private void ZzReadQvar(){
/* Mコード=0x0050 */
// ULONG *varAddr;
// varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
// PUSH_L( varAddr[1] ); /* push high double */
// PUSH_L( varAddr[0] ); /* push low double */
ap.ResetDataIndex(mp.FetchMcodeInt());
uint var=ap.GetUl();
dtp.PushUl(ap.GetUl());
dtp.PushUl(var);
}
private void ZzReadSvar(){
/* Mコード=0x0051 */
// ULONG *varAddr;
// varAddr = (ULONG *)(DataBase + FETCH_MCODE_LONG);
// PUSH_A( varAddr[1] ); /* push address */
// PUSH_C( varAddr[0] ); /* push length */
ap.ResetDataIndex(mp.FetchMcodeInt());
uint length=ap.GetUl();
dtp.PushUl(ap.GetUl());
dtp.PushUl(length);
}
private void ZzReadJvar(){
/* Mコード=0x0052 */
// ULONG *varAddr;
// ULONG length;
// ULONG margin;
// varAddr = (ULONG *)(DataBase + FETCH_MCODE_LONG);
// length = *varAddr++;
// margin = *varAddr++;
// PUSH_A( (UCHAR *)varAddr + margin ); /* push address */
// PUSH_C( length ); /* push length */
}
/*--------------------- 局所変数の直接読み出し ---------------*/
これは(関数枠だけで中身なし)実行時に例外をスローしないのでちょっと危険な状態ですね。保留にしたときもそのように思っていましたが、いま思えばだいぶ長丁場になっているのでこの状態にある関数がどれかとか忘れてしまっていたようです。
関数枠だけあって中身無しの場合は未定義例外などアプリケーション例外をスローしておくとよさそうです。
また、記述済のコードも妥当性は未確認なので、今後書き直される可能性が大きくあります。