Mind8のランタイムディスパッチャC実装の代替実装をC#で行う（OutputDevice）

# はじめに
[こちらの記事](https://qiita.com/mylifewithviolin/items/5a68eb63e07379cc7997)にてMind開発者の@killyさんより情報共有いただいたMind8の検証用Consoleをベースに一部正規のConsoleのコードを取り込んだ中間コードhellolevel1.mcoをリビルドしましたが、その記事のコメントでkillyさんより別の構成のソースのご提案もいただき、そのバージョンをhellolevel0.mcoとしました。[こちらの記事](https://qiita.com/mylifewithviolin/items/78e465ce22157a7a1a2f)ではこの２つのバージョンの中間コードをC#で代替実装したディスパッチャで処理させてみましたが、それぞれ完走にはいたっておりません。そこでhellolevel1.mcoより若干ステップ数の多いhelloleve0.mcoをhellolevel2.mcoとして退避し、hellolevel1.mcoより若干ステップ数のより少ないhellolevel2.mcoを生成してC#で代替実装したディスパッチャで処理させてみます。

# 前提条件
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の動作をデバッグ実行で探るために使用します。[こちらの記事](https://qiita.com/mylifewithviolin/items/2804356ae2f39b055b8c)の環境となります。

# カスタマイズConsoleのビルド
killyさんよりご提供いただいた情報に従い、下記のようにカスタマイズConsoleのビルド用のフォルダfilelevel群を作成します。

## ビルド用フォルダ構成
今回は下記のようなフォルダ構成となります。filedummyフォルダは起動検証用Consoleのビルド環境です。fileフォルダは正規のソースファイルが格納されたフォルダです。filelevel2フォルダは従来のfilelevel0フォルダです。
filedummyの内容は[こちらの記事](https://qiita.com/mylifewithviolin/items/40772e39e4b44cd27a22)を、filelevel1,2(旧0)の内容は[こちらの記事](https://qiita.com/mylifewithviolin/items/5a68eb63e07379cc7997)を参照してください。
```
C:\developments\vscode\mind8>tree
C:.
├─bin
├─file
│  └─obj
├─filedummy
│  └─obj
├─filelevel0
│  └─obj
├─filelevel1
│  └─obj
├─filelevel2
│  └─obj
├─kernel
│  └─.vscode
├─lib
├─libY
└─sample
```

# お題のMindソースコード

カスタマイズConsoleのconslevel0.srcを起動検証用Consoleのconsdumy.srcに対して正規版ConsoleのConsole.srcから必要部分だけもってきて、下記のように編集します。

```mind:consleve0.src
スプーリングアドレスは　　変数。
入力文字補正アドレスは　　変数。
※検索機能初期化アドレスは　変数。
※検索機能終了アドレスは　　変数。

　　　　グローバル。

"../file/osdefine.src"を　　コンパイルする。　　    （DOS/UNIXの指定）
"../file/cswitch.src"を 　　コンパイルする。　　　　（コンパイルスイッチ）
"../file/ckaridef.src"を　　コンパイルする。　　　　（仮定義）
"../file/cconvar.src"を　　コンパイルする。　　　　（大域定数／大域変数）
"../file/cerrmsg.src"を 　　コンパイルする。　　　　（エラー定数／エラー登録）
"../file/cconv.src"を     　コンパイルする。　　　　（数値／文字列変換）
"../file/coutput.src"を　　 コンパイルする。　　　　（Ｐｕｒｅな表示系）
"../file/cerror.src"を　　　コンパイルする。　　　　（エラー処理）

　　　　ローカル。

立ち上がり要求は　　　　ワード変数。
立ち下がり要求は　　　　ワード変数。

コンソール初期化・基本部とは　　（・  →  ・）
　（しばらくはシステムコールするな）
　　　　終了パラメータを　クリアし　　　　　　　　※CCONST.SRC
　　　　エラー文字列初期化し　　　　　　　　　　　※CERROR.SRC
　　　　空白文字列初期化し　　　　　　　　　　　　※COUTPUT.SRC
	。

各ライブラリ初期化とは　　　　　本定義　　　　　（・  →  ・）
　　　　コンソール初期化・基本部し　　　　　　　　　　　※本ソース
	。

　　　　グローバル。

$$COLD_FORTHは 　　 　　本定義
　（プログラム起動時のみの処理）
　　　　立ち上がり要求を　セットし
　　　　立ち下がり要求を　クリアし
　（ライブラリ初期化処理）
　　　　各ライブラリ初期化し　　　　　　　　　　　　　　※本ソース
　　　　「$$COLD_FORTH＆改行＆」を　＄＄表示。

※　～略～
※　終り(CONSDUMY.SRC)　※
```
conslevel1.srcとの違いは「各ライブラリ初期化し」の直後に下記の実行がないだけです。
```mind:consleve0.src
　　　　「各ライブラリ初期化後」で　このメッセージでスタック検査し
```
## お題のMind8のソースファイル
```mind:hellolevel0.src
メインとは
　　　　「Hello by mind8」を　表示すること。
```
## ビルド実行
横スクロールしてわかりずらいですが、こちらはC#用環境のため、Mind8コンパイラのライブラリ指定パスにはさきほどのC用環境の上にあるfilelevel0\objフォルダのconslevel0を指定します。
```
C:\developments\vscode\mind8dispatch>mind hellolevel0 c:\developments\vscode\mind8\filelevel0\obj\conslevel0     

日本語プログラミング言語 Ｍｉｎｄ Version 8.07 for Windows
          Copyright(C) 1985 Scripts Lab. Inc.
コンパイル中 .. 終了
Coping.. c:\pmind\bin\mindex.exe --> hellolevel0.exe
```

C側検証環境でhellolevel0.mcoでのスタートアップ処理を検証するため、hellolevel0.mcoをmindexec.mcoにリネームしてC側検証環境のkernelフォルダにコピーします。
```
C:\developments\vscode\mind8dispatch>copy hellolevel0.mco C:\developments\vscode\mind8\kernel\mindexec.mco
C:\developments\vscode\mind8\kernel\mindexec.mco を上書きしますか? (Yes/No/All):
 Y
        1 個のファイルをコピーしました。
```
# お題のMind8の中間コード実行リスト
C側検証環境で、前記手順でコピーしたお題の中間コードファイルをディスパッチャで処理させます。
```
SqNo mcode mc(dec) mpoint dtp.point  dtp+0   dtp+1 rtp.point  rtp+0  rtp+1
   1 8019  32793     57   1024        0        0   1024        0        0
   2 002F     47     51   1024        0        0   1023        0        0
   3 0012     18   2931   1024        0        0   1023        0        0
   4 0036     54   2932   1024        0        0   1023        0        0
   5 0080    128   2935   1024        0        0   1023        0        0
   6 0036     54   2936   1024        0        0   1023        0        0
   7 0070    112   2939   1024        0        0   1023        0        0
   8 803A  32826   2940   1024        0        0   1023        0        0
   9 002F     47    119   1024        0        0   1022        0 12544234
  10 80B8  32952   2929   1024        0        0   1022        0 12544234
  11 0012     18   2921   1024        0        0   1021        0 12550000
  12 0036     54   2922   1024        0        0   1021        0 12550000
  13 0071    113   2925   1024        0        0   1021        0 12550000
  14 8046  32838   2926   1024        0        0   1021        0 12550000
  15 8045  32837    163   1024        0        0   1020        0 12549978
  16 0012     18    157   1024        0        0   1019        0 12549972
  17 0036     54    158   1024        0        0   1019        0 12549972
  18 0074    116    161   1024        0        0   1019        0 12549972
  19 0020     32    162   1024        0        0   1019        0 12549972
  20 0020     32    164   1024        0        0   1020        0 12549978
  21 80A3  32931   2927   1024        0        0   1021        0 12550000
  22 0036     54   1942   1024        0        0   1020        0 12549978
  23 0012     18   1945   1024        0        0   1020        0 12549978
  24 016E    366   1946   1024        0        0   1020        0 12549978
  25 0020     32   1949   1024        0        0   1020        0 12549978
  26 0020     32   2928   1024        0        0   1021        0 12550000
  27 0020     32   2930   1024        0        0   1022        0 12544234
  28 00A5    165   2941   1024        0        0   1023        0        0
  29 00C1    193   2950   1022       14 12550004   1023       14        0
$$COLD_FORTH
  30 0020     32   2951   1024        0        0   1023        0        0
  31 80C3  32963     58   1024        0        0   1024        0        0
  32 00A5    165   3177   1024        0        0   1023        0        0
  33 8083  32899   3186   1022       14 12550476   1023       14        0
  34 0012     18   1755   1022       14 12550476   1022       14 12544236
  35 004E     78   1756   1022       14 12550476   1022       14 12544236
  36 00EC    236   1759   1020        0        0   1022        0 12544236
  37 0096    150   1762   1022       14 12550476   1022       14 12544236
  38 026D    621   1763   1020        0        1   1022        0 12544236
Hello by mind8
  39 0020     32   1764   1024        0        0   1022        0 12544236
  40 0020     32   3187   1024        0        0   1023        0        0
  41 801A  32794     59   1024        0        0   1024        0        0
  42 002F     47     53   1024        0        0   1023        0        0
  43 00A5    165   2965   1024        0        0   1023        0        0
  44 00C1    193   2972   1022       10 12550052   1023       10        0
実行終り
  45 801B  32795   2973   1024        0        0   1023        0        0
  46 002F     47     55   1024        0        0   1022        0 12544238
  47 00A5    165   2952   1024        0        0   1022        0 12544238
  48 00C1    193   2963   1022       18 12550026   1022       18 12544238
実行終り時の処理
  49 0020     32   2964   1024        0        0   1022        0 12544238
  50 004E     78   2974   1024        0        0   1023        0        0
  51 0014     20   2977   1022        0        0   1023        0        0
  ```

お題の「Hello by mind8」のコンソール出力までは38（同一コード含む）のmcodeを処理すればよく、終了までは51ステップです。hellolevel1の場合は46と60でしたので10ステップ弱の削減となりました。

# お題のMind8の中間コードのC#代替ディスパッチャ実行リスト
続いてC#側検証環境で、前記手順でビルドしたお題の中間コードファイルを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
   2 002F     47    102   1024        0        0   1023      114        0
   3 0012     18   5862   1024        0        0   1023      114        0
   4 0036     54   5864   1024        0        0   1023      114        0
   5 0080    128   5870   1024        0        0   1023      114        0
   6 0036     54   5872   1024        0        0   1023      114        0
   7 0070    112   5878   1024        0        0   1023      114        0
   8 803A  32826   5880   1024        0        0   1023      114        0
   9 002F     47    238   1024        0        0   1022     5880        0
  10 80B8  32952   5858   1024        0        0   1022     5880        0
  11 0012     18   5842   1024        0        0   1021     5858        0
  12 0036     54   5844   1024        0        0   1021     5858        0
  13 0071    113   5850   1024        0        0   1021     5858        0
  14 8046  32838   5852   1024        0        0   1021     5858        0
  15 8045  32837    326   1024        0        0   1020     5852        0
  16 0012     18    314   1024        0        0   1019      326        0
  17 0036     54    316   1024        0        0   1019      326        0
  18 0074    116    322   1024        0        0   1019      326        0
  19 0020     32    324   1024        0        0   1019      326        0
  20 0020     32    328   1024        0        0   1020     5852      326
  21 80A3  32931   5854   1024        0        0   1021     5858     5852
  22 0036     54   3884   1024        0        0   1020     5854      326
  23 0012     18   3890   1024        0        0   1020     5854      326
  24 016E    366   3892   1024        0        0   1020     5854      326
  25 0020     32   3898   1024        0        0   1020     5854      326
  26 0020     32   5856   1024        0        0   1021     5858     5854
  27 0020     32   5860   1024        0        0   1022     5880     5858
  28 00A5    165   5882   1024        0        0   1023      114     5880
  29 00C1    193   5900   1022       14        0   1023      114     5880
$$COLD_FORTH
  30 0020     32   5902   1024        0     5884   1023      114     5880
  31 80C3  32963    116   1024        0     5884   1024        0      114
  32 00A5    165   6354   1024        0     5884   1023      116     5880
  33 8083  32899   6372   1022       14        0   1023      116     5880
  34 0012     18   3510   1022       14        0   1022     6372     5858
  35 004E     78   3512   1022       14        0   1022     6372     5858
  36 00EC    236   3518   1020        0        0   1022     6372     5858
  37 0096    150   3524   1022       14        0   1022     6372     5858
  38 026D    621   3526   1020        0        0   1022     6372     5858
  39 0020     32   3528   1024        0     6356   1022     6372     5858
  40 0020     32   6374   1024        0     6356   1023      116     6372
  41 801A  32794    118   1024        0     6356   1024        0      116
  42 002F     47    106   1024        0     6356   1023      118     6372
  43 00A5    165   5930   1024        0     6356   1023      118     6372
  44 00C1    193   5944   1022       10        1   1023      118     6372
実行終り
  45 801B  32795   5946   1024        0     5932   1023      118     6372
  46 002F     47    110   1024        0     5932   1022     5946     5858
  47 00A5    165   5904   1024        0     5932   1022     5946     5858
  48 00C1    193   5926   1022       18        1   1022     5946     5858
実行終り時の処理
  49 0020     32   5928   1024        0     5906   1022     5946     5858
  50 004E     78   5948   1024        0     5906   1023      118     5946
  51 0014     20   5954   1022        0        1   1023      118     5946
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[6176] mind8dispatch.dll' がコード 0 (0x0) で終了しました。
```

最後が例外スローされていますが、これはmcode=0014の「プロセス終り０」で意図的にスローさせたアプリケーション例外です。
とりあえず終了動作としては意図したものですので、今回のlevel0はいちおう無事に完走したようでした！:tada::tada:

# お題のC#ソースコード
## Dispatcherクラス（C#関数配列）

### C#の関数配列
今回実装するのは未実装であったために落ちていたmcode=0x026Dの「ファイルハンドル指定で出力」です。
C版オリジナルでは3ker.cに実装されていますので分割クラスファイルのCsFunctions3kerc.csに実装しました。

```cs:CsFunctions3kerc.cs
using System.Runtime.InteropServices;
namespace Mind8Kernel
{
    public partial class Dispatcher
    {
        /*--------------------- 標準入出力  -----------------------------*/
        private void OutputDevice()	/* ;WORD ファイルハンドル指定で出力 */
        {
                /* Mコード=0x026D */  
            /* (strinfo, filehandle → .) */
            //     int		 filehandle;
            //     size_t		 length;
            //     UCHAR		*string;
            //#define  POP_U                ((ULONG)(*DstackPointer++))
            //#define  POP_U_OF_Q           (DROP_F,POP_U)
            // filehandle = POP_U_OF_Q;
            // length = POP_C;
            // string = POP_A;
            // write( filehandle, string, length );	/* エラーは見ない */
            dtp.PopUl();
            uint filehandle=dtp.PopUl();
            uint length=dtp.PopUl();
            uint index=dtp.PopUl();
            //保留
        }
     }
}
```
実はファイルハンドラを拾ってもそのままCのwrite関数の代替えが思い浮かばなかったため、スタックから拾って実質捨てている仮実装となっています。

SetupCsFunctions内ではC#関数配列のインデックス最大値が変化したので訂正しています。
```cs:CsFunctions.cs
using System.Text;
using System.Dynamic;
using System.Runtime.InteropServices;

namespace Mind8Kernel
{
    public partial class Dispatcher
    {
        private readonly int maxCountCsFunctions = 1 + 0x026D;
        /// <summary>C#の関数配列を準備する</summary>
        /// <param name="csFunc">C#関数配列の参照</param>
        private void SetupCsFunctions(ref Action[] csFuncs){
          //～略～      
        /*--------------------- 私のプログラム名  -----------------------*/
            csFuncs[0x0261]=CmcodeFullFilename;//
        /*--------------------- 標準入出力  -----------------------------*/
            csFuncs[0x026D]=OutputDevice;//
        //～略～
        }

    }
}
```
今回追加したのはOutputDeviceだけです。これはいずれ加筆実装します。


# つづく
生成されたhello.mcoを解釈して、C#側で「Hello by mind8」が出力されるようにするまでの長い道のりですが、正規版の処理内容に近づくにはまだまだ課題山積です。次回以降でもこのソースコードを肉付けして実際に動く範囲をステップバイステップで広げてまいります。

## 2024/06/12 追記

### C#の関数配列（修正後）
Mind開発者の@killyさんからコメントいただき、mcode=0x026Dの「ファイルハンドル指定で出力」はコンソール出力固定でよいのではとのことでしたので、いったんそのようにさせていただきます。mcode=0x00C1の「＄＄表示」と同じ実装となります。

```cs:CsFunctions3kerc.cs
using System.Runtime.InteropServices;
using System.Text;
namespace Mind8Kernel
{
    public partial class Dispatcher
    {
        /*--------------------- 標準入出力  -----------------------------*/
        private void OutputDevice()	/* ;WORD ファイルハンドル指定で出力 */
        {
                /* Mコード=0x026D */  
            /* (strinfo, filehandle → .) */
            //     int		 filehandle;
            //     size_t		 length;
            //     UCHAR		*string;
            //#define  POP_U                ((ULONG)(*DstackPointer++))
            //#define  POP_U_OF_Q           (DROP_F,POP_U)
            // filehandle = POP_U_OF_Q;
            // length = POP_C;
            // string = POP_A;
            // write( filehandle, string, length );	/* エラーは見ない */
            dtp.PopUl();
            uint filehandle=dtp.PopUl();//捨てる
            uint length=dtp.PopUl();
            uint index=dtp.PopUl();              
            byte[] chars=mp.GetUb(index,length);
            string text = Encoding.GetEncoding("shift_jis").GetString(chars);
            Console.Write(text);
        }
     }
}
```

# お題のMind8の中間コードの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
   2 002F     47    102   1024        0        0   1023      114        0
   3 0012     18   5862   1024        0        0   1023      114        0
   4 0036     54   5864   1024        0        0   1023      114        0
   5 0080    128   5870   1024        0        0   1023      114        0
   6 0036     54   5872   1024        0        0   1023      114        0
   7 0070    112   5878   1024        0        0   1023      114        0
   8 803A  32826   5880   1024        0        0   1023      114        0
   9 002F     47    238   1024        0        0   1022     5880        0
  10 80B8  32952   5858   1024        0        0   1022     5880        0
  11 0012     18   5842   1024        0        0   1021     5858        0
  12 0036     54   5844   1024        0        0   1021     5858        0
  13 0071    113   5850   1024        0        0   1021     5858        0
  14 8046  32838   5852   1024        0        0   1021     5858        0
  15 8045  32837    326   1024        0        0   1020     5852        0
  16 0012     18    314   1024        0        0   1019      326        0
  17 0036     54    316   1024        0        0   1019      326        0
  18 0074    116    322   1024        0        0   1019      326        0
  19 0020     32    324   1024        0        0   1019      326        0
  20 0020     32    328   1024        0        0   1020     5852      326
  21 80A3  32931   5854   1024        0        0   1021     5858     5852
  22 0036     54   3884   1024        0        0   1020     5854      326
  23 0012     18   3890   1024        0        0   1020     5854      326
  24 016E    366   3892   1024        0        0   1020     5854      326
  25 0020     32   3898   1024        0        0   1020     5854      326
  26 0020     32   5856   1024        0        0   1021     5858     5854
  27 0020     32   5860   1024        0        0   1022     5880     5858
  28 00A5    165   5882   1024        0        0   1023      114     5880
  29 00C1    193   5900   1022       14        0   1023      114     5880
$$COLD_FORTH
  30 0020     32   5902   1024        0     5884   1023      114     5880
  31 80C3  32963    116   1024        0     5884   1024        0      114
  32 00A5    165   6354   1024        0     5884   1023      116     5880
  33 8083  32899   6372   1022       14        0   1023      116     5880
  34 0012     18   3510   1022       14        0   1022     6372     5858
  35 004E     78   3512   1022       14        0   1022     6372     5858
  36 00EC    236   3518   1020        0        0   1022     6372     5858
  37 0096    150   3524   1022       14        0   1022     6372     5858
  38 026D    621   3526   1020        0        0   1022     6372     5858
Hello by mind8
  39 0020     32   3528   1024        0     6356   1022     6372     5858
  40 0020     32   6374   1024        0     6356   1023      116     6372
  41 801A  32794    118   1024        0     6356   1024        0      116
  42 002F     47    106   1024        0     6356   1023      118     6372
  43 00A5    165   5930   1024        0     6356   1023      118     6372
  44 00C1    193   5944   1022       10        1   1023      118     6372
実行終り
  45 801B  32795   5946   1024        0     5932   1023      118     6372
  46 002F     47    110   1024        0     5932   1022     5946     5858
  47 00A5    165   5904   1024        0     5932   1022     5946     5858
  48 00C1    193   5926   1022       18        1   1022     5946     5858
実行終り時の処理
  49 0020     32   5928   1024        0     5906   1022     5946     5858
  50 004E     78   5948   1024        0     5906   1023      118     5946
  51 0014     20   5954   1022        0        1   1023      118     5946
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[1092] mind8dispatch.dll' がコード 0 (0x0) で終了しました。
```