はじめに
前回はMind8の中間コードディスパッチャ(の一部)をCからC#に書き換えてみるという野望の序二段のあたりとして、Mind8のLocテーブルのアドレスポインタ、データ領域のAccessポインタを実装しました。
これにより、ディスパッチャループが少しづつ回るようになりました。今回はリターンスタックを実装します。
前回記事まではC#のスタックコレクションを使う想定でしたが、Cの関数配列に対応した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の動作をデバッグ実行で探るために使用します。こちらの記事の環境となります。
お題のMind8の中間コードファイル
こちらの記事をご参照ください。
下記はC版ディスパッチャのループ内のモニタを調整して出力したシーケンスNo順のmcodeの16進数表記のリストです。長くなるので下記は10までサンプル出力したものです。その下に全出力を掲示しています。
SqNo mcode
1 8019
2 002F
3 0036
4 0080
5 0036
6 0070
7 803A
8 002F
9 813E
10 0012
詳細展開で確認できます。お題の「Hello by mind8」のコンソール出力までは649のmcodeを処理しなければならないことがわかります。
SeqNo.11以降から終了までのmcode
11 0036
12 0071
13 8046
14 8045
15 0012
16 0036
17 0074
18 0020
19 0020
20 80BA
21 0036
22 0012
23 016E
24 0020
25 80A6
26 0097
27 0065
28 0020
29 80D7
30 0261
31 8053
32 8052
33 001A
34 006B
35 0055
36 008F
37 00ED
38 0055
39 0012
40 00A2
41 00BF
42 0095
43 01D7
44 006B
45 0055
46 00ED
47 0055
48 0055
49 0103
50 00BF
51 0055
52 0055
53 0107
54 0022
55 0122
56 0020
57 0012
58 0165
59 80D6
60 002F
61 0264
62 0104
63 0065
64 0012
65 0036
66 0071
67 0020
68 0036
69 0074
70 0264
71 0104
72 00EE
73 0020
74 80E8
75 80E6
76 80E2
77 0268
78 0020
79 0020
80 0020
81 813C
82 0095
83 0296
84 0298
85 0096
86 0296
87 0298
88 0097
89 0296
90 0298
91 0020
92 0020
93 801F
94 002F
95 0052
96 8175
97 8170
98 001D
99 006E
100 0058
101 0097
102 01D5
103 00A5
104 01DD
105 00EC
106 0058
107 006E
108 0042
109 0070
110 0058
111 015F
112 00EC
113 003E
114 01A5
115 00A0
116 00A0
117 0119
118 00EC
119 0042
120 0078
121 002E
122 0058
123 015F
124 00EC
125 003E
126 01A5
127 00A0
128 00A0
129 0119
130 00EC
131 0042
132 0078
133 002E
134 0058
135 015F
136 00EC
137 003E
138 01A5
139 00A0
140 00A0
141 0119
142 00EC
143 0042
144 0078
145 002E
146 0058
147 015F
148 00EC
149 003E
150 01A5
151 00A0
152 00A0
153 0119
154 00EC
155 0042
156 0078
157 002E
158 0058
159 015F
160 00EC
161 003E
162 01A5
163 00A0
164 00A0
165 0119
166 00EC
167 0042
168 0078
169 002E
170 0058
171 015F
172 00EC
173 003E
174 01A5
175 00A0
176 00A0
177 0119
178 00EC
179 0042
180 0078
181 002E
182 0058
183 015F
184 00EC
185 003E
186 01A5
187 00A0
188 00A0
189 0119
190 00EC
191 0042
192 0078
193 002E
194 0058
195 015F
196 00EC
197 003E
198 01A5
199 00A0
200 00A0
201 0119
202 00EC
203 0042
204 0078
205 002E
206 0058
207 015F
208 00EC
209 003E
210 01A5
211 00A0
212 00A0
213 0119
214 00EC
215 0042
216 0078
217 002E
218 0058
219 015F
220 00EC
221 003E
222 01A5
223 00A0
224 00A0
225 0119
226 00EC
227 0042
228 0078
229 002E
230 0058
231 015F
232 00EC
233 003E
234 01A5
235 00A0
236 00A0
237 0119
238 00EC
239 0042
240 0078
241 002E
242 0058
243 015F
244 00EC
245 003E
246 01A5
247 00A0
248 00A0
249 0119
250 00EC
251 0042
252 0078
253 002E
254 0058
255 015F
256 00EC
257 002E
258 0054
259 003A
260 01B7
261 0058
262 816D
263 001C
264 006E
265 0058
266 01D2
267 00A0
268 0114
269 00ED
270 0058
271 0024
272 011E
273 0025
274 0123
275 0020
276 8178
277 8171
278 001D
279 006E
280 0058
281 006E
282 0042
283 0070
284 0058
285 015F
286 00EC
287 003E
288 01A5
289 006A
290 0054
291 00A0
292 00A0
293 0119
294 00EC
295 0054
296 00A0
297 0114
298 00EC
299 0042
300 0078
301 002E
302 0058
303 015F
304 00EC
305 003E
306 01A5
307 006A
308 0054
309 00A0
310 00A0
311 0119
312 00EC
313 0054
314 00A0
315 0114
316 00EC
317 0042
318 0078
319 002E
320 0058
321 015F
322 00EC
323 003E
324 01A5
325 006A
326 0054
327 00A0
328 00A0
329 0119
330 00EC
331 0054
332 00A0
333 0114
334 00EC
335 0042
336 0078
337 002E
338 0058
339 015F
340 00EC
341 003E
342 01A5
343 006A
344 0054
345 00A0
346 00A0
347 0119
348 00EC
349 0054
350 00A0
351 0114
352 00EC
353 0058
354 015F
355 0058
356 8163
357 00A4
358 0020
359 01DD
360 00FE
361 00EC
362 0096
363 002E
364 00EC
365 0058
366 0054
367 003A
368 01B7
369 002E
370 0025
371 0122
372 0020
373 0012
374 0165
375 0012
376 0052
377 8174
378 8170
379 001D
380 006E
381 0058
382 0097
383 01D5
384 00A5
385 01DD
386 00EC
387 0058
388 006E
389 0042
390 0070
391 0058
392 015F
393 00EC
394 003E
395 01A5
396 00A0
397 00A0
398 0119
399 00EC
400 0042
401 0078
402 002E
403 0058
404 015F
405 00EC
406 003E
407 01A5
408 00A0
409 00A0
410 0119
411 00EC
412 0042
413 0078
414 002E
415 0058
416 015F
417 00EC
418 003E
419 01A5
420 00A0
421 00A0
422 0119
423 00EC
424 0042
425 0078
426 002E
427 0058
428 015F
429 00EC
430 003E
431 01A5
432 00A0
433 00A0
434 0119
435 00EC
436 0042
437 0078
438 002E
439 0058
440 015F
441 00EC
442 003E
443 01A5
444 00A0
445 00A0
446 0119
447 00EC
448 0042
449 0078
450 002E
451 0058
452 015F
453 00EC
454 003E
455 01A5
456 00A0
457 00A0
458 0119
459 00EC
460 0042
461 0078
462 002E
463 0058
464 015F
465 00EC
466 003E
467 01A5
468 00A0
469 00A0
470 0119
471 00EC
472 0042
473 0078
474 002E
475 0058
476 015F
477 00EC
478 003E
479 01A5
480 00A0
481 00A0
482 0119
483 00EC
484 0042
485 0078
486 002E
487 0058
488 015F
489 00EC
490 003E
491 01A5
492 00A0
493 00A0
494 0119
495 00EC
496 0042
497 0078
498 002E
499 0058
500 015F
501 00EC
502 003E
503 01A5
504 00A0
505 00A0
506 0119
507 00EC
508 0042
509 0078
510 002E
511 0058
512 015F
513 00EC
514 003E
515 01A5
516 00A0
517 00A0
518 0119
519 00EC
520 0042
521 0078
522 002E
523 0058
524 015F
525 00EC
526 003E
527 01A5
528 00A0
529 00A0
530 0119
531 00EC
532 0042
533 0078
534 002E
535 0058
536 015F
537 00EC
538 002E
539 0054
540 003A
541 01B7
542 0058
543 816D
544 001C
545 006E
546 0058
547 01D2
548 00A0
549 0114
550 00ED
551 0058
552 0024
553 011E
554 0025
555 0122
556 0020
557 0165
558 81A4
559 0012
560 0036
561 0070
562 0020
563 8149
564 002F
565 0012
566 0036
567 0071
568 0020
569 0012
570 0038
571 0075
572 0038
573 0095
574 01EC
575 0012
576 0068
577 8150
578 002F
579 8252
580 001C
581 004E
582 006B
583 0012
584 0036
585 0071
586 0055
587 00EE
588 00A5
589 803C
590 002F
591 001A
592 006E
593 0015
594 00ED
595 0022
596 004E
597 0012
598 0065
599 0012
600 0036
601 0081
602 0024
603 0020
604 8152
605 002F
606 821E
607 0036
608 0071
609 0020
610 0020
611 02CD
612 0020
613 8021
614 0020
615 802A
616 0020
617 802C
618 0020
619 004D
620 00EC
621 0012
622 0036
623 0070
624 802E
625 0020
626 8030
627 0020
628 8032
629 0020
630 8034
631 0020
632 0020
633 00A5
634 803C
635 002F
636 001A
637 006E
638 0015
639 00ED
640 0022
641 0020
642 828D
643 00A5
644 809A
645 0012
646 004E
647 00EC
648 0096
649 026D
Hello by mind8
650 0020
651 0020
652 801A
653 002F
654 801B
655 002F
656 0012
657 0036
658 0070
659 0036
660 0080
661 803B
662 002F
663 8035
664 0020
665 8033
666 0020
667 8031
668 0020
669 802F
670 0020
671 0012
672 004D
673 00EC
674 0012
675 0036
676 0070
677 802D
678 0020
679 802B
680 0020
681 8022
682 0020
683 8020
684 002F
685 8151
686 0020
687 0020
688 813F
689 0020
690 0020
691 0020
692 0012
693 004E
694 0014
お題のC#ソースコード
CsFunctions C#の関数配列
クラス構成は変えていないのですがソースファイルを分割するためクラスはpartialにしました。ソースファイル名をCsFuctions.csとしました。
public partial class Mind8Dispatcher
{
private static readonly int maxCountCsFunctions = 1 + 0x0261;
/// <summary>C#の関数配列を準備する</summary>
/// <param name="csFunc">C#関数配列の参照</param>
private static void SetupCsFunctions(ref Action[] csFuncs){
csFuncs=new Action[maxCountCsFunctions];
/*--------------------- 実行 -----------------------------------*/
//~略~
/*--------------------- 局所変数の直接書き込み ----------------*/
csFuncs[0x0069]=ZzWriteBvarLocal;
csFuncs[0x006A]=ZzWriteWvarLocal;
csFuncs[0x006B]=ZzWriteDvarLocal;
csFuncs[0x006C]=ZzWriteLvarLocal;
csFuncs[0x006D]=ZzWriteQvarLocal;
csFuncs[0x006E]=ZzWriteSvarLocal;
/*--------------------- 変数のクリア --------------------------*/
//~略~
csFuncs[0x0261]=CmcodeFullFilename;//
}
//~略~
/*--------------------- 局所変数の直接書き込み --------------------*/
private static void ZzWriteBvarLocal(){ /* ;WORD $$WRITE_BVAR_LOCAL */
/* Mコード=0x0069 */
// UCHAR *varAddr;
// varAddr = (UCHAR *)RstackPointer + FETCH_MCODE;
// *varAddr = POP_B_OF_Q;
// #define DROP_L DstackPointer++
// #define DROP_F DROP_L
// #define POP_L (*DstackPointer++)
// #define POP_F POP_L
// #define POP_B_OF_Q (DROP_F,(UCHAR)POP_L)
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
DataStack.Pop();//≒DROP Dataスタックから取り出して捨てる
rtp.PushUb((byte)DataStack.Pop());
}
private static void ZzWriteWvarLocal(){ /* ;WORD $$WRITE_WVAR_LOCAL */
/* Mコード=0x006A */
// USHORT *varAddr;
// varAddr = (USHORT *)((UCHAR *)RstackPointer + FETCH_MCODE);
// *varAddr = POP_W_OF_Q;
// #define DROP_L DstackPointer++
// #define DROP_F DROP_L
// #define POP_L (*DstackPointer++)
// #define POP_F POP_L
// #define POP_W_OF_Q (DROP_F,(USHORT)POP_L)
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
DataStack.Pop();//≒DROP Dataスタックから取り出して捨てる
rtp.PushUs((ushort)DataStack.Pop());
}
private static void ZzWriteDvarLocal(){ /* ;WORD $$WRITE_DVAR_LOCAL */
/* Mコード=0x006B */
// LONG *varAddr;
// varAddr = (LONG *)((UCHAR *)RstackPointer + FETCH_MCODE);
// *varAddr = POP_L_OF_Q;
// #define POP_L_OF_Q (DROP_F,POP_L)
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
DataStack.Pop();//≒DROP Dataスタックから取り出して捨てる
rtp.PushSl((int)DataStack.Pop());
}
private static void ZzWriteLvarLocal(){ /* ;WORD $$WRITE_LVAR_LOCAL */
/* Mコード=0x006C */
// ULONG *varAddr;
// varAddr = (ULONG *)((UCHAR *)RstackPointer + FETCH_MCODE);
// varAddr[1] = POP_L;
// varAddr[0] = POP_L;
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
uint var0=DataStack.Pop();//varAddr[0]用をデータスタックよりPOPしておく
rtp.SetUl2var(DataStack.Pop(),var0);
}
private static void ZzWriteQvarLocal(){ /* ;WORD $$WRITE_QVAR_LOCAL */
/* Mコード=0x006D */
// ULONG *varAddr;
// varAddr = (ULONG *)((UCHAR *)RstackPointer + FETCH_MCODE);
// varAddr[0] = POP_L;
// varAddr[1] = POP_L;
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
rtp.SetUl2var(DataStack.Pop(),DataStack.Pop());
}
private static void ZzWriteSvarLocal(){ /* ;WORD $$WRITE_SVAR_LOCAL */
/* Mコード=0x006E */
// ULONG *varAddr;
// varAddr = (ULONG *)((UCHAR *)RstackPointer + FETCH_MCODE);
// varAddr[0] = POP_C;
// varAddr[1] = (ULONG)POP_A;
// #define POP_A ((UCHAR *)(*DstackPointer++))
// #define POP_C POP_U
rtp.ResetStackIndex(mp.GetMCodeCurrentIndex());//returnスタックのインデックスをMCode領域の値で移動
rtp.SetUl2var(DataStack.Pop(),(byte)DataStack.Pop());
}
}
上記のコメント部分はオリジナル版のCマクロ定義によるコードで、マクロはステップインしなかったので、マクロの定義部分もその下に引用しています。
ここが極めて重要で、このレベルでオリジナルのC版とコンパチブルな動作をしないと、Mind中間コードの処理結果が異なっていってしまいますね。
今回、リターンスタックの実装を変更したのは、上記の関数のオリジナルコードにいわゆるスタック操作とは異なるアドレスポインタへの操作が読み取れたためです。
データスタックはまだC#のスタック型のままですが、この動作の互換性も足らない可能性が今回の実装状態でも出てきていますが、この記事を書く前の状態からとしては、リターンスタックを書き換えて、上記のマクロが書き換えるように独自のアドレスポインタを実装しています。
class StackPointer スタックポインタ
こちらが独自実装のリターンスタック操作用のスタック操作クラスです。スタックっぽいPush、Popも実装していますが、型に応じて入出力できるように少し独自っぽい実装となっています。上記のアドレス(この実装ではbyte配列インデックス)を操作して、type unionのアドレスポインタ操作クラスと似たような実装も追加してあります。
/// <summary>スタックポインタ</summary>
private class StackPointer{
private uint stackSize;
private uint stackIndex;
private byte[] dataArray =[];
public void SetupStackArray(uint size){
stackSize=size;
dataArray =new byte[stackSize];
stackIndex=0;
}
public void ResetStackIndex(uint index){
stackIndex=index*4;//byte配列インデックス=アドレスポインタ変数の値*4
}
public byte PopUb(){ /* for unsigned byte access */
if(stackIndex - 4 < 0)throw new Exception("stack user flow");
stackIndex -=4;
byte[] int32Byte = new byte[4];
for (ulong i = 0; i < 4; i++) int32Byte[i] = dataArray[stackIndex + i];
return (byte)BitConverter.ToUInt32(int32Byte, 0);
}
public void PushUb(byte b){ /* for unsigned byte access */
if(stackIndex + 4 > stackSize--)throw new Exception("stack over flow");
byte[] int32Byte = new byte[4];
int32Byte[3] =b;
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i]=int32Byte[i];
stackIndex +=4;
}
public ushort PopUs(){ /* for unsigned byte access */
if(stackIndex - 4 < 0)throw new Exception("stack under flow");
stackIndex -=4;
byte[] int32Byte = new byte[4];
for (ulong i = 0; i < 4; i++) int32Byte[i] = dataArray[stackIndex + i];
return BitConverter.ToUInt16(int32Byte, 0);
}
public void PushUs(ushort us){ /* for unsigned byte access */
if(stackIndex + 4 > stackSize--)throw new Exception("stack over flow");
byte[] int32Byte =BitConverter.GetBytes(us);
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i]=int32Byte[i];
stackIndex +=4;
}
public uint PopUl(){/* for unsigned long(int32) access */
if(stackIndex - 4 < 0)throw new Exception("stack under flow");
stackIndex -=4;
byte[] int32Byte = new byte[4];
for (ulong i = 0; i < 4; i++) int32Byte[i] = dataArray[stackIndex + i];
return BitConverter.ToUInt32(int32Byte, 0);
}
public void PushUl(uint ul){/* for unsigned long(int32) access */
if(stackIndex + 4 > stackSize--)throw new Exception("stack over flow");
byte[] int32Byte =BitConverter.GetBytes(ul);
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i]=int32Byte[i];
stackIndex +=4;
}
public void PushSl(int sl){/* for signed long(int32) access */
if(stackIndex + 4 > stackSize--)throw new Exception("stack over flow");
byte[] int32Byte =BitConverter.GetBytes(sl);
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i]=int32Byte[i];
stackIndex +=4;
}
public void SetUl2var(uint ul,uint ul2){/* for unsigned long access (for 1set of 2variable) */
//アドレス指定で直接セットしている元コードのためポインタインデックスの自動増加はなし
byte[] int32Byte =BitConverter.GetBytes(ul);
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i]=int32Byte[i];
int32Byte =BitConverter.GetBytes(ul2);
for (ulong i = 0; i < 4; i++) dataArray[stackIndex + i + 4]=int32Byte[i];
}
}
Main 暫定メイン
暫定メインがまた少し書き換わります。リターンスタックはスタックポインタの実装に変わります。従来のC#スタックのコレクション型のRetnStackは削除されました。データスタックは現状まだC#スタックのコレクション型のままです。
private static Stack<uint> DataStack = new();//データスタック
private static byte[] McodeBase =[];//MCode領域
private static byte[] WordOffsetTable=[];//LOCテーブル
private static byte[] DataBase =[];//データ領域
private static byte[] RetnStack =[];//リターンスタック
private static MCodePointer mp=new();//MCode領域用ポインタ
private static LocTablePointer lp=new();//LOCテーブル用ポインタ
private static AccessPointer ap =new(); //データ領域用ポインタ
private static StackPointer rtp =new(); //リターンスタック用ポインタ
/// <summary>メイン</summary>
/// <param name="args">引数</param>
static void Main(string[] args)
{
String mcodefilename="hello.mco";
McodeInfoStruct mcodeInfo =new();
/* ディスパッチャを準備する */
bool ret=SetupForDispatch(ref mcodeInfo,mcodefilename);
if(!ret){
return;
}
MonitorMcode(McodeBase);
DataStack = new();//resetDataStackPointer();//DstackPointer = DataStackBase[RestartEnvCount];
mp =new();
lp =new();
ap =new();
rtp=new();
mp.SetupMcodeArray(McodeBase);
lp.SetupLocArray(WordOffsetTable);
ap.SetupDataArray(ref DataBase);
rtp.SetupStackArray((ushort)mcodeInfo.minfoRstackSize);//resetRetnStackPointer();//RstackPointer = RetnStackBase;
//McodePointer.b = (UCHAR *)McodeBase + 0x70; /* 0x70=実行開始地点 */
mp.ResetMcodeIndex(0x70);
/* C#の関数を準備する */
Action[] csFuncs=[]; //C#の関数を格納する配列
/* C#の関数配列を準備する */
SetupCsFunctions(ref csFuncs);
/* ディスパッチャ開始 */
Dispatcher(ref mcodeInfo,ref csFuncs);
}
Dispatcher ディスパッチャ
リターンスタックの最初のPushが書き換わっています。
また、お題の中間コードの節でも説明しました、オリジナルのC版ディスパッチャが処理しているmcodeリストと同等のものを出力するようにしました。こちらは10進数表記も出力しています。
/// <summary>ディスパッチャ</summary>
/// <param name="McodeInfo">MCode情報構造体の参照</param>
/// <param name="csFunc">C#関数配列の参照</param>
private static void Dispatcher(ref McodeInfoStruct McodeInfo,
ref Action[] csFuncs){
ushort mcode;
int retcode=0;//setjmp( RESTARTENV ); /* ←ディスパッチャ再 */
if ( retcode != 2 ) /* 強制脱出の検査 */
{
int i=0;
for(;;)
{
mcode = mp.GetMCodeCurrentIndex();
Console.WriteLine("{0,4:d} {1,4:X4} {2,6:d}",++i,mcode,mcode);
if ( (mcode & 0x8000)==0 )
{
/* C#関数 */
csFuncs[mcode]();
}
else
{
/* Mind単語 */
//PUSH_R( McodePointer.l );
//#define PUSH_R(addr) *(--RstackPointer)=(ULONG)(addr)
rtp.PushUl((uint)mp.GetMcodeIndex());//現在のMCodeポインタの値をリターンスタックにプッシュする
//SET_MCODE_POINTER_BY_WORDNO( mcode & 0x7fff );
//McodePointer.b = (UCHAR *)(WordOffsetTable[wordNo])
mp.ResetMcodeIndex((ulong)lp.GetSl((ulong)(mcode & 0x7fff)));
}
}
}
return;
}
デバッグ実行の結果
ディスパッチャ内のループのMcodeポインタによるMCode領域からのmcode取得は34回までC版ランタイムと同じ動きをして、34回目のC#側関数mcode=006B ZzWriteDvarLocal内で
SqNo mcode mcode(dec)
1 8019 32793
2 002F 47
3 0036 54
4 0080 128
5 0036 54
6 0070 112
7 803A 32826
8 002F 47
9 813E 33086
10 0012 18
11 0036 54
12 0071 113
13 8046 32838
14 8045 32837
15 0012 18
16 0036 54
17 0074 116
18 0020 32
19 0020 32
20 80BA 32954
21 0036 54
22 0012 18
23 016E 366
24 0020 32
25 80A6 32934
26 0097 151
27 0065 101
28 0020 32
29 80D7 32983
30 0261 609
31 8053 32851
32 8052 32850
33 001A 26
34 006B 107
例外がスローされました: 'System.InvalidOperationException' (System.Collections.dll の中)
プログラム '[10784] mind8dispatch.dll' がコード -1 (0xffffffff) で終了しました。
下記のコードが'Stack empty.'で不正操作例外をスローしました。
DataStack.Pop();//≒DROP Dataスタックから取り出して捨てる
下記のマクロPOP_L_OF_Qを
// *varAddr = POP_L_OF_Q;
// #define POP_L_OF_Q (DROP_F,POP_L)
下記の定義から最初にデータスタックポインタを1つ動かすと解釈して、単にデータスタックからポップして捨てるで代替実装したのですが、そこがよくなかったのかも。あるいは手前の処理でスタック積み上げに不適合があったのかもしれませんね。
// #define DROP_L DstackPointer++
// #define DROP_F DROP_L
つづく
生成されたhello.mcoを解釈して、C#側で「Hello by mind8」が出力されるようにするまでの長い道のりですが、とりあえず構想段階のソースコードをざっと書くところまで到達して、序二段とかなという感じです。まだまだ課題山積ですが、次回以降でもこのソースコードを肉付けして実際に動く範囲をステップバイステップで広げてまいります。
補足
こちらの記事へのMind開発者@killyさんのコメントで気になっていた点が解明しましたのを受けて、今回記事ではソース長いので説明しませんでしたが、Accessクラスのフェッチっぽい動作は通常の読み取り動作に修正してあります。
class AccessePointer データ領域Accesseポインタ
訂正版ソースコード
```cs:Mind8Dispatcher.cs ///データ領域アクセスポインタ
private class AccessPointer{ private ulong dataIndex; private byte[] dataArray =[]; public void SetupDataArray(ref byte[] DataBase){ dataArray=DataBase; } public void ResetDataIndex(ulong index){ dataIndex=index; } public byte GetUb(){ /* for unsigned byte access */ return dataArray[dataIndex]; } public void SetUb(byte b){ /* for unsigned byte access */ dataArray[dataIndex] =b; } public void SetUb4Msi(byte b,uint length){ /* for unsigned byte access (for mind strings instance)*/ for (ulong i = 0; i < length; i++) dataArray[dataIndex + i]= b; } public ushort GetUs(){/* for unsigned short access */ byte[] int16Byte = new byte[2]; for (ulong i = 0; i < 2; i++) int16Byte[i] = dataArray[dataIndex + i]; return BitConverter.ToUInt16(int16Byte, 0); } public void SetUs(ushort us){/* for unsigned short access */ byte[] int16Byte =BitConverter.GetBytes(us); for (ulong i = 0; i < 2; i++) dataArray[dataIndex + i]=int16Byte[i]; } public short GetSs(){/* for signed short access */ byte[] int16Byte = new byte[2]; for (ulong i = 0; i < 2; i++) int16Byte[i] = dataArray[dataIndex + i]; return BitConverter.ToInt16(int16Byte, 0); } public void SetSs(short ss){/* for signed short access */ byte[] int16Byte =BitConverter.GetBytes(ss); for (ulong i = 0; i < 2; i++) dataArray[dataIndex + i]=int16Byte[i]; } public int GetSl(){/* for signed long access */ byte[] int32Byte = new byte[4]; for (ulong i = 0; i < 4; i++) int32Byte[i] = dataArray[dataIndex + i]; return BitConverter.ToInt32(int32Byte, 0); } public void SetSl(int sl){/* for signed long access */ byte[] int32Byte =BitConverter.GetBytes(sl); for (ulong i = 0; i < 4; i++) dataArray[dataIndex + i]=int32Byte[i]; } public uint GetUl(){/* for unsigned long access */ byte[] int32Byte = new byte[4]; for (ulong i = 0; i < 4; i++) int32Byte[i] = dataArray[dataIndex + i]; return BitConverter.ToUInt32(int32Byte, 0);
}
public void SetUl(uint ul){/* for unsigned long access */
byte[] int32Byte =BitConverter.GetBytes(ul);
for (ulong i = 0; i < 4; i++) dataArray[dataIndex + i]=int32Byte[i];
}
public void SetUl4Ms(uint ul,uint ul2){/* for unsigned long access (for mind string) */
byte[] int32Byte =BitConverter.GetBytes(ul);
for (ulong i = 0; i < 4; i++) dataArray[dataIndex + i]=int32Byte[i];
int32Byte =BitConverter.GetBytes(ul2);
for (ulong i = 0; i < 4; i++) dataArray[dataIndex + i + 4]=int32Byte[i];
}
public long GetSll(){/* for signed long long access */
byte[] int64Byte = new byte[8];
for (ulong i = 0; i < 8; i++) int64Byte[i] = dataArray[dataIndex + i];
return BitConverter.ToInt64(int64Byte, 0);
}
public void SetSll(long sll){/* for signed long access */
byte[] int64Byte =BitConverter.GetBytes(sll);
for (ulong i = 0; i < 8; i++) dataArray[dataIndex + i]=int64Byte[i];
}
public ulong GetUll(){/* for signed long long access */
byte[] int64Byte = new byte[8];
for (ulong i = 0; i < 8; i++) int64Byte[i] = dataArray[dataIndex + i];
return BitConverter.ToUInt64(int64Byte, 0);
}
public void SetUll(ulong ull){/* for unsigned long access */
byte[] int64Byte =BitConverter.GetBytes(ull);
for (ulong i = 0; i < 8; i++) dataArray[dataIndex + i]=int64Byte[i];
}
}
</details>
## 補足2
データスタックのPop例外は手前のmcode=0261のC#関数CmcodeFullFilenameの中身がまだ実装されていあないことによる原因でした。自ファイル名のアドレスをどうやってプッシュするか悩んで保留していたのが敗因でした。