XDS Modula-2の例外検出について。

XDS Modula-2 のランタイムシステムは、以下のすべてを検出します。
【整数のゼロ除算】
【整数のオーバーフロー】
【配列の範囲オーバー】
【不正アドレス(nilポインター)のアクセス】
【スタックオーバーフロー】

XDS 2.51、XDS 2.6 beta 2 ともにクリアです。

ちなみに、ADW Modula-2 では、配列の範囲オーバーは検出しませんでした。他のチェックオプションはありましたが、なぜか範囲チェックのオプション設定自体が見当たりません。

ExTest.p の Modula-2 版のソースを以下に示します。ソースはExTest.modとます。
コンパイラのチェックも厳しく、単純に例外が予測できるコードを書くとコンパイル時にエラーとなるので、若干変えています。また、Pascal版もModula-2版も、メニューは繰返し表示するようにしていますが、実際には例外の捕捉はしていないので、例外検出でプログラムが終了します。ここではプログラムが終了してしまうことが問題では無く、終了しないことを問題としています。Free PascalとXDS Modula-2/ADW Modula-2では例外の捕捉を追加し、処理を継続させることができます。
コンパイルは、XDS Modula-2 をインストールし、次のようにします。

xc =make ExTest.mod
(* 例外テストプログラム *)
MODULE ExTest;

FROM STextIO  IMPORT WriteString, WriteLn, SkipLine;
FROM SWholeIO IMPORT WriteInt, ReadInt;
FROM RealMath IMPORT round;
FROM SYSTEM   IMPORT CAST;

VAR
    N : INTEGER;

PROCEDURE Menu;
BEGIN
  WriteLn;
  WriteString('*** テストケース ***');
  WriteLn;
  WriteString('1) 整数のゼロ除算');
  WriteLn;
  WriteString('2) 整数のオーバーフロー(加算)');
  WriteLn;
  WriteString('3) 整数のオーバーフロー(乗算)');
  WriteLn;
  WriteString('4) 整数のオーバーフロー(実数⇒整数)');
  WriteLn;
  WriteString('5) 配列範囲オーバー');
  WriteLn;
  WriteString('6) nilポインターアクセス');
  WriteLn;
  WriteString('7) スタックチェック');
  WriteLn;
  WriteString('9) 終了');
  WriteLn;
  WriteString('テストNo. (1..7, 9)?');
  ReadInt(N);
  SkipLine;
END Menu;

PROCEDURE IntZero(): INTEGER;
BEGIN
    RETURN 0;
END IntZero;

PROCEDURE MaxInt(): INTEGER;
BEGIN
    RETURN MAX(INTEGER);
END MaxInt;

PROCEDURE Test1;
VAR
    A, B, C: INTEGER;
BEGIN
    A := 1;
    B := IntZero();
    C := A DIV B;                       (* ここで整数のゼロ除算 *)
    WriteInt(A, 0);
    WriteString(' div ');
    WriteInt(B, 0);
    WriteString(' = ');
    WriteInt(C, 0);
    WriteLn;
END Test1;

PROCEDURE Test2;
VAR
    A: INTEGER;
BEGIN
    WriteString('A := MAX(INTEGER)');
    WriteLn;
    A := MaxInt();
    WriteString('A := A + 100');
    WriteLn;
    A := A + 100;                       (* ここで整数オーバフロー *)
    WriteString('A = ');
    WriteInt(A, 0);
    WriteLn;
END Test2;

PROCEDURE Test3;
VAR
    A: INTEGER;
BEGIN
    WriteString('A := MAX(INTEGER)');
    WriteLn;
    A := MaxInt();
    WriteString('A := A * 100');
    WriteLn;
    A := A * 100;                       (* ここで整数オーバフロー *)
    WriteString('A = ');
    WriteInt(A, 0);
    WriteLn;
END Test3;

PROCEDURE Test4;
VAR
    A: INTEGER;
BEGIN
    WriteString('A := MAX(INTEGER)');
    WriteLn;
    A := MaxInt();
    WriteString('A := A * 100');
    WriteLn;
    A := round(CAST(REAL, A) * 100.0);  (* ここで整数オーバフロー *)
    WriteString('A = ');
    WriteInt(A, 0);
    WriteLn;
END Test4;

PROCEDURE Test5;
VAR
    V: ARRAY [1..10] OF INTEGER;
    I: INTEGER;
BEGIN
    FOR I := 1 TO 11 DO
        WriteString('V[');
        WriteInt(I, 2);
        WriteString('] = ');
        WriteInt(I, 2);
        WriteLn;
        V[I] := I;                      (* I=11で範囲オーバー *)
    END;
END Test5;

PROCEDURE Test6;
VAR
    A: INTEGER;
    P: POINTER TO INTEGER;
BEGIN
    WriteString('P := NIL');
    WriteLn;
    P := NIL;
    WriteString('P^ := 10');            (* ここでNILアクセス *)
    WriteLn;
    P^ := 10;
    WriteString('A := P^');
    WriteLn;
    A := P^;
    WriteInt(A, 0);
    WriteLn;
END Test6;

PROCEDURE Test7;
    PROCEDURE Test7a(D: INTEGER);
    VAR
        V: ARRAY [1..1000] OF INTEGER;
    BEGIN
        WriteInt(D, 8);
        INC(D);
        Test7a(D);
    END Test7a;
BEGIN
    Test7a(1);
END Test7;

BEGIN
    REPEAT
        Menu;
        CASE N OF
              1: Test1;
            | 2: Test2;
            | 3: Test3;
            | 4: Test4;
            | 5: Test5;
            | 6: Test6;
            | 7: Test7;
        ELSE
            ; (* 何もしない *)
        END;
    UNTIL N = 9;
END ExTest.

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください