3

基本的に、これは Pascal (FPC) の再帰的データ構造に関する質問です。SICPの第4章に示されているようなSchemeインタープリターを実装したいので、この質問はSchemersにも関係があるかもしれません。:)

S 式は、タグ付きデータとして表されます。ここまでで、数字とペアを表すバリアント レコードを作成しました。コードが読みやすく、自明であることを願っています。

program scheme;

type
   TTag = (ScmFixnum, ScmPair);
   PScmObject = ^TScmObject;
   TScmObject = record
      case ScmObjectTag: TTag of
         ScmFixnum: (ScmObjectFixnum: integer);
         ScmPair: (ScmObjectCar, ScmObjectCdr: PScmObject);
      end;

var
   Test1: TScmObject;
   Test2: TScmObject;
   Test3: TScmObject;

function MakeFixnum(x: integer): TScmObject;
var
   fixnum: TScmObject;
begin
   fixnum.ScmObjectTag := ScmFixnum;
   fixnum.ScmObjectFixnum := x;
   MakeFixnum := fixnum;
end;

function MakePair(car, cdr: PScmObject): TScmObject;
var
   pair: TScmObject;
begin
   pair.ScmObjectTag := ScmPair;
   pair.ScmObjectCar := car;
   pair.ScmObjectCdr := cdr;
   MakePair := pair;
end;

begin
   Test1 := MakeFixnum(7);
   writeln('Test1, Tag: ', Test1.ScmObjectTag,
           ', Content: ', Test1.ScmObjectFixnum);
   Test2 := MakeFixnum(9);
   writeln('Test2, Tag: ', Test2.ScmObjectTag,
           ', Content: ', Test2.ScmObjectFixnum);
   Test3 := MakePair(Test1, Test2);
end.

ただし、コードをコンパイルすると、次のようなエラーが発生します。

$ fpc scheme.pas
(...)
Compiling scheme.pas
scheme.pas(43,34) Error: Incompatible type for arg no. 2: Got "TScmObject", expected "PScmObject"
scheme.pas(45) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted

関数にエラーがあることは明らかですMakePair。しかし、私が間違っていることを正確に理解していません。どんな助けでも大歓迎です。:)

4

2 に答える 2

7

MakePair関数は次のように定義されます。

function MakePair(car, cdr: PScmObject): TScmObject;

タイプの2つのポインタを受け取ることに注意してくださいPScmObject。次に、次のように呼び出します。

MakePair(Test1, Test2);

しかしTest1、とTest2はタイプTScmObjectです。したがって、コンパイラが言うように、渡される実際のパラメータには互換性がありません。

代わりに、これらのレコードへのポインタを渡す必要があります。

MakePair(@Test1, @Test2);

長期的には、これらのレコードの存続期間に注意する必要があります。ヒープに割り当てる必要があり、ガベージコレクションがないと、レコードの所有者を追跡しようとして苦痛の世界に入ると思います。おそらく、寿命を管理するためにインターフェース参照カウントを使用することを検討できます。

于 2013-01-04T21:03:18.050 に答える
4

プロシージャは、レコード自体ではなく、レコードへのポインタを予期しています。

@ (at) 演算子をコール ポイントで使用して、その場でレコードへのポインターを作成し、コンパイラの型チェックを満たすことができます。

begin
   Test1 := MakeFixnum(7);
   writeln('Test1, Tag: ', Test1.ScmObjectTag,
           ', Content: ', Test1.ScmObjectFixnum);
   Test2 := MakeFixnum(9);
   writeln('Test2, Tag: ', Test2.ScmObjectTag,
           ', Content: ', Test2.ScmObjectFixnum);
   Test3 := MakePair(@Test1, @Test2);
end.
于 2013-01-04T21:04:06.043 に答える