写一个Scheme解释与FPC:递归数据结构(Writing a Scheme interprete

2019-08-05 15:42发布

本质上,这是一个关于在帕斯卡(FPC)递归数据结构的问题。 当我想实现一个Scheme解释就像是在SICP章4所示,这个问题可能是相关的有计划的为好。 :)

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 。 但我不明白,但究竟我做错了。 任何帮助表示赞赏。 :)

Answer 1:

MakePair函数的定义如下:

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

需要注意的是它接收类型的两个指针PScmObject 。 然后调用它像这样:

MakePair(Test1, Test2);

Test1Test2是类型的TScmObject 。 所以传递的实际参数是不兼容的,只是因为编译器说。

您需要将指针传递给这些记录,而不是:

MakePair(@Test1, @Test2);

从长远来看,你将需要要小心这些记录的寿命。 你需要在堆上分配,无垃圾收集我怀疑你会进入一个痛苦的世界试图跟踪谁拥有这些记录。 也许你可以考虑使用接口引用计数来管理寿命。



Answer 2:

该过程被期待的指针记录,而不是记录本身。

您可以使用@(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.


文章来源: Writing a Scheme interpreter with FPC: Recursive data structures