カテゴリー別アーカイブ: 一般

XDS Modula-2 2.51 インストール時の注意事項

ADW Mudula-2 がしばらく待たされそうなので、XDS Modula-2 をインストールする場合、以下の点に注意して下さい。Windows版の話です。
Version 2.51 のインストールの途中で以下の画面が現れます。「Personal」がログインユーザのみで「Common」が全ユーザというお決まりの選択です。ここで「Common」を選択すると、システムのPATHの設定が「C:\XDS\BIN」で上書きされ、「C:\XDS\BIN」だけになってしまいます。ユーザのPATH設定は変りませんが、これまでのシステムのPATHが丸ごと消えることになるので、ここでは「Personal」を選んで下さい。その場合は、ユーザの環境変数の末尾に「C:\XDS\BIN」が追加され、既存の設定は消えません。
「Common」にしたい場合は、事前にシステムの環境変数の設定値をテキストファイルなどに保存しておいて事後にそれから設定を復元して下さい。

万が一、システムの環境変数を書き換えられて事前の保存もしていなかった場合は、[システムのプロパティ]-[システムの保護]の[システムの復元]で、直近の復元ポイントに戻すとPATHもその時点に復元されます。ただし、復元ポイント以降のインストールや設定は無効になります。

また、XDS Modula-2 2.6 Beta の場合は上記の画面は出ません。インストールすると「C:\XDS\bin;」がシステムの環境変数の先頭に挿入されます。既存の設定が消されることはありません。

でも、環境変数の状態は何かインストールする場合の前後で保存しておくのが賢明です。

 

問い1(続々々)

【なぜ「Pascal 日和」でC言語の話か?】

実はC言語がどうこうというのはどうでも良い話で、Modula-2 R10 の仕様が気になったからです。
C言語は、副作用の問題を抱えながら長年使用され続け、定着しているのでどうこう言うつもりはありません。

現在進んでいる Modula-2 R10 の「Modula-2 R10 Language Report」を見ると、これまでのModula-2に無かった‘++’‘–‘が追加されていました。
もし「問い1(続々)」の話の様なことが突然Modula-2にも起こったら皆さん困ると思います。

しかし、「Modula-2 R10 Language Report」の記載を見ると
‘++’は Increment Statement Suffix
‘–‘は Decrement Statement Suffix
となっています。

Operator(演算子)ではなくStatement(文)となっているので、C言語とは違う扱いで実装されるようです。
X++;INC(X, 1); と同じ。
X–;DEC(X, 1); し同じ。

これらは文なので値として評価できないので、Y := X++;A[X++] := Y;IF X++ = Y THEH… などはできません。

つまり、Modula-2 R10 では、「問い1(続々)」の様なことは起こらないということになります。
まずまず一安心というところです。

ちなみに

Free Pascal(Lazarus)ではどうかというと、代入文(Assignment Statement)として、‘+=’‘-=’‘*=’‘/=’が実装されていますが、Pascalではこれらは代入式ではなく代入文なので、これについても問題ありません。
X += Y;X := X + Y; と同じ。
X -= Y;X := X – Y; と同じ。
X += Y;X := X * Y; と同じ。
X /= Y;X := X / Y; と同じ。’div’ではなく’/’なので、実数演算に限定されます。
Inc()Dec()手続きがあるので、‘++’‘–‘は実装していないようです。‘+=’‘-=’もいらないと思いますが。

ということで、Free Pascalも大丈夫そうです。

.NETのObject Pascalである、RemObject社のOxygeneはイベントの割当てと解除のための‘+=’‘-=’はありますが、数値の演算に‘++’、’–‘‘+=’‘-=’‘*=’‘/=’はありません。
こちらも大丈夫そうです。

Modula-2やPascal系のコンパイラは、C言語ライクな表現を取り入れる場合も、副作用の問題などは取り込まない様になっているようですね。

以上

 

問い1(続々)

【解説】(少しだけ)

間違っている部分もあると思いますので、参考程度に見て下さい。

回答例で「不定」とした部分は、実際には「未定義」という扱いとなり、極端な解釈をすれば全く想定外の結果となり、【C】【F】【G】【I】も含め全て未定義となり全体が木っ端みじんみたいなこともあり得るのかもしれません。
現実的には未定義に対してそこまで暴れまくる実装をしているコンパイラは無いと思うので、それぞれのコンパイラがそれぞれのルールを決めて実装していると考えます。

今回の問題点は、式内で、副作用がある変数に複数回参照している点です。
副作用とは、式の中で演算をしたときに、演算とは別に変数に対して作用を及ぼすことです。
たとえば、次の式があったとき、(これは副作用がある変数(x)に複数回参照していないケース)

 /* x は 0 で初期化済 */
 y = x++;

普通は「yにxの今の値を代入し、xをインクリメントする」という説明になります。

これを演算と副作用に分解します。
使用されている演算子は代入演算の’=’と後置インクリメントの演算’++’の2つです。各演算子の優先度は ‘++’ > ‘=’ です。
演算は優先順位と結合性(左から/右から)に従って評価されます。
【演算】評価順序は①→②→③
①: ‘x++’ を評価して演算前の x の値を返す。つまり 0。
②: ‘y = 0’ を評価して、第1演算項 y に代入されるべき値(つまり第2演算項の値)を返す。つまり 0。
③: ‘0’ という評価値になったが、誰も拾わないので結果は捨てられる。もし、z = y = x++ ならばさらに z = 0 が評価される。
【副作用】A,Bの適用順は未定義
A: x の値を1つ増やす。
B: y の値を 0 にする。

ここで、演算には優先度と結合性がありますが、副作用については式の評価の始まりから、副作用完了点まで間に行えばよいというだけです。
この場合の副作用完了点は終端記号(;)のところになります。
つまり、「*①*②*③*」の任意の場所(*)でAとBは実行されます。この副作用の実行場所がコンパイラによって違う可能性があるわけです。
この式の場合は、xに対して副作用が1回のみしかし要されていないので、どのコンパイラでも結果は同じ(x == 1, y == 0)ということになりそうですが?
しかし、もし、「AB①②③」というように最初に副作用を実行したら y は 1 になるのではないかとふと思いました。単純にそのままの実装なら本当にそうなるかもしれません(???)。

演算項の評価に先立ち全ての副作用を最初に適用するという実装はちょっと除外して話を進めます(複雑になりすぎるので)。

次は、副作用がある変数(x)に複数回参照しているケース。

 /* x は 0 で初期化済、a[]は{9,9}で初期化済 */
 a[x] = x++;

演算子は、配列添え字の'[]’と代入演算の’=’と後置インクリメント演算の’++’。各演算子の優先度は ‘[]’ > ‘++’ > ‘=’ です。
【演算】評価順序は①→②→③→④
①: a[x]を評価して配列 a の場所を特定します。場所は x の値で特定されます。x の値は副作用の実行場所により 0 または 1 となる。評価結果が2つに分かれてしまう。
②: ‘x++’ を評価して演算前の x の値を返す。つまり 0
③: ‘a[0または1] = 0’ を評価して第1演算項 y に代入されるべき値(つまり第2演算項の値)を返す。
④: ‘0’ という評価値になったが、誰も拾わないので結果は捨てられる。もし、z = a[x] = x++ ならばさらに z = 0 が評価される。
【副作用】A,Bの適用順は未定義
A: x の値を1つ増やす。
B: a[0または1] の値を 0 にする。

ということになります。

その他の式も「演算」(値の評価)と「副作用」(変数・オブジェクトの変更)と分けて考え、各幅作用がどこで適用されるかでどう変るかを検証してみて下さい。

一番安全なのは、++, — は単独の式(x++;や–y;など)で使用するのが良いと思います。

「C言語 副作用」や「C言語 副作用完了点」で検索するといろいろ説明しているページが出てきます。

【式と手続き】

プログラムの実行部分は、「式」、「手続き」、「制御文」などありますが、C言語とPascalでは違いがありますね。

C言語の、y = x; は式(代入演算)で、この式自体が値を持ちます。z = y = x; は可。
Pascal言語の Y := X; は代入文で、この文自体は値を持ちません。z := y := x; は不可。

また、変数のインクリメントやデクリメントもC言語では演算子でPascal言語では手続きです。

C言語の x++; はxをインクリメントするだけではなく、これ自体が演算項になり得る。y = x++; は可。
Pascal言語の Inc(X); はXをインクリメントするだけの手続きで、これ自体が演算項にはなり得ない。Y := Inc(X); は不可。

Pascal言語の代入やインクリメントは、「演算と副作用」が発生するのではなく、単純に「作用」を及ぼすものと言えます。

続きは改めて...

問い1(続)

回答例は以下のようになります。

-- 回答欄 --
①【A】 不定   【B】 不定  【C】   1 
②【D】 不定   【E】 不定  【F】   2 
③【G】   9    【H】 不定 
④【I】   9    【J】 不定 

ここでの「不定」は、実行の都度どうなるか分からないという意味ではなく、コンパイラの実装に依存するということです。同じコンパイラで同じオプションでコンパイルされたものは同じ結果になります。

【実行結果の例】

Cコンパイラは、Microsoft Visual C、gcc、OpenWatcomを使用しました。
その他に、JavaとC#を加えてみました。

■ Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80×86 (Visual Studio 6.0)

① a[0] = 0, a[1] = 9, x = 1
② a[0] = 0, a[1] = 9, x = 2
③ x = 9, y = 0
④ x = 9, y = 46


■ Microsoft(R) C/C++ Optimizing Compiler Version 17.00.61030 for x86 (Visual Studio 2012)

① a[0] = 0, a[1] = 9, x = 1
② a[0] = 0, a[1] = 9, x = 2
③ x = 9, y = 0
④ x = 9, y = 81


■ gcc version 4.8.1 (GCC)

① a[0] = 9, a[1] = 0, x = 1
② a[0] = 1, a[1] = 0, x = 2
③ x = 9, y = 36
④ x = 9, y = 46


■ Open Watcom C/C++ x86 32-bit Compile and Link Utility Version 2.0 beta Jan 14 2014 11:34:32 (64-bit)

① a[0] = 9, a[1] = 0, x = 1
② a[0] = 9, a[1] = 0, x = 2
③ x = 9, y = 36
④ x = 9, y = 46


■ javac 1.7.0_45

① a[0] = 0, a[1] = 9, x = 1
② a[0] = 1, a[1] = 9, x = 2
③ x = 9, y = 36
④ x = 9, y = 45


■ Microsoft (R) Visual C# Compiler Version 4.0.30319.18408

① a[0] = 0, a[1] = 9, x = 1
② a[0] = 1, a[1] = 9, x = 2
③ x = 9, y = 36
④ x = 9, y = 45

 

マイクロソフト内でも、VC 6.0、VC 2012、C#4.0 のすべてが違う結果になっています。
JavaとC#は同じ結果になっています。

続きは改めて...


プログラムソースは、Cの他、JavaとC#を加え以下の通りです。

- プログラム(Prog01.c) -

#include <stdio.h>

int main(void)
{
	int x, y;
	int a[2] = {9, 9};

	x = 0;
	a[x] = x++;
	printf("① a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

	x = 0;
	a[x++] = x++;
	printf("② a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

	x = 0;
	y = x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++;
	printf("③ x = %d, y = %d\n", x, y);

	x = 0;
	y = ++x + ++x + ++x + ++x + ++x + ++x + ++x+ ++x + ++x;
	printf("④ x = %d, y = %d\n", x, y);

	return 0;
}


- プログラム(Prog01j.java) -

class Prog01j {
    public static void main(String[] args) {
        int x, y;
        int[] a = new int[]{9, 9};

        x = 0;
        a[x] = x++;
        System.out.printf("① a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

        x = 0;
        a[x++] = x++;
        System.out.printf("② a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

        x = 0;
        y = x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++;
        System.out.printf("③ x = %d, y = %d\n", x, y);

        x = 0;
        y = ++x + ++x + ++x + ++x + ++x + ++x + ++x+ ++x + ++x;
        System.out.printf("④ x = %d, y = %d\n", x, y);
    }
}


- プログラム(Prog01cs.cs) -

using System;

class Prog01cs
{
    static void Main(String[] args)
    {
        int x, y;
        int[] a = new int[]{9, 9};

        x = 0;
        a[x] = x++;
        Console.WriteLine("① a[0] = {0}, a[1] = {1}, x = {2}", a[0], a[1], x);

        x = 0;
        a[x++] = x++;
        Console.WriteLine("② a[0] = {0}, a[1] = {1}, x = {2}", a[0], a[1], x);

        x = 0;
        y = x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++;
        Console.WriteLine("③ x = {0}, y = {1}", x, y);

        x = 0;
        y = ++x + ++x + ++x + ++x + ++x + ++x + ++x+ ++x + ++x;
        Console.WriteLine("④ x = {0}, y = {1}", x, y);
    }
}

 

問い1

もし、以下のような問題があったらどう答えますか。そしてそれをどう説明しますか。
機会があったら新人プログラマーさんに出してみてはどうでしょう。

■ 問い1

以下のCプログラム(Prog01.c)を実行すると、実行結果の【A】~【J】はどういう値になるでしょうか。
回答欄に書きなさい。

— プログラム(Prog01.c) —

#include <stdio.h>

int main(void)
{
    int x, y;
    int a[2] = {9, 9};

    x = 0;
    a[x] = x++;
    printf("① a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

    x = 0;
    a[x++] = x++;
    printf("② a[0] = %d, a[1] = %d, x = %d\n", a[0], a[1], x);

    x = 0;
    y = x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++ + x++;
    printf("③ x = %d, y = %d\n", x, y);

    x = 0;
    y = ++x + ++x + ++x + ++x + ++x + ++x + ++x+ ++x + ++x;
    printf("④ x = %d, y = %d\n", x, y);

    return 0;
}

-- 実行結果 --
① a[0] =【A】, a[1] =【B】, x =【C】
② a[0] =【D】, a[1] =【E】, x =【F】
③ x =【G】, y =【H】
④ x =【I】, y =【J】

-- 回答欄 --
①【A】_____  【B】_____  【C】_____
②【D】_____  【E】_____  【F】_____
③【G】_____  【H】_____
④【I】_____  【J】_____

続きは改めて...

 

SyntaxHighlighter

WordPressで「Pascal 日和 ホームページ」と同様にSyntaxHighlighterの設定ができました。

Ada(GNAT)の例です。

with Greetings;
procedure Gmain is
begin
   Greetings.Hello;
   Greetings.Goodbye;
end Gmain;

枠と背景色をつけるとこんな感じ。

pragma Ada_05;
-- pragma Wide_Character_Encoding('s');

with Ada.Wide_Text_IO; use Ada.Wide_Text_IO;

package body Greetings is

   pragma Implicit_Packing;
   type elm is range 1 .. 100;
   type arr is array (1 .. 100) of elm;
   --  pragma Pack(arr);
   pragma Component_Alignment (Form => Storage_Unit, Name => arr);
   for arr'Size use 800;

   procedure Hello is
      -- 各種数値表現
      a : Integer := -16#22#E2;
      b : Integer := -12_323e3;
      c : Integer := 8#5#;
      d : Integer := 3e+4;
      x : Float   := +0.3_212E-4;
      y : Float   := 16#11234_f.E#E3;
   begin
      a := 3 + 2;
      Put_Line ("Hello WORLD!");
      Put ('A');
      -- Put ('あ');    -- 「あ」は1文字 - 「pragma Wide_Character_Encoding('s')」が必要
      Put ("あ");       -- 「あ」は文字列
      Put ('"');        -- ダブルクォーテーション1文字
      Put (''');        -- シングルクォーテーション1文字
      Put_Line ("ハロー、ワールド!");
   end Hello;

   procedure Goodbye is
   begin
      Put_Line ("Goodbye WORLD!");
   end Goodbye;

end Greetings;

テキストエディタ「PSPad」用の設定ファイルをアップしました。

「ダウンロード1」ページで、テキストエディタ「PSPad」の書式設定ファイル(構文色分け)をアップしました。
メニューの「ダウンロード1」を選択すると開きます。
PSPadは海外(チェコ)のフリーのテキストエディタで、プログラム言語用の書式設定ファイルを自作できる機能を持っているので、ISO Pascal、ADW Modula-2、GNAT(Ada)の書式設定ファイルを作成してみました。
メニューなど日本語にも対応しています。
キーワード指定に正規表現が指定できないので、数値表現のバリエーションに対応できない部分があります。GNAT(Ada)については、'”‘、”’を使用したときも正しく表示できませんが、変数’属性は正しく表示できるのでGNAT(Ada)も対応しました。

テキストエディタ「Peggy」用の設定ファイルをアップしました。

「ダウンロード1」ページで、テキストエディタ「Peggy」の書式設定ファイル(構文色分け)をアップしました。
メニューの「ダウンロード1」を選択すると開きます。
Peggyは有償のテキストエディタ(Free版のPeggy Padもある)で、プログラム言語用の書式設定ファイルを自作できる機能を持っています。
Peggyのサイトで、Ada、XDS Modula-2、Python2.4の書式設定ファイルを公開していましたが、こちらに移動しました。”Ada”は”GNAT(Ada)”と名称変更しました。
キーワード指定に正規表現が指定できるので、数値表現のバリエーションにも対応しています。
私の知る限りでは、Peggyが一番柔軟に対応できる機能を持っていると思います。最近メンテナンスが止まっているのが残念です。
また、この当時 ADW Modula-2 がなかったため、XDS Modula-2 を使用していました。ADW Modula-2については今後作成したいと思います。