Delphi 用FPC编写Scheme解释器:递归数据结构
本质上,这是一个关于Pascal(FPC)中递归数据结构的问题。由于我想实现一个方案解释器,如SICP第4章所示,这个问题也可能与方案制定者有关: S表达式应表示为标记数据。到目前为止,我已经构建了一个变体记录,它表示数字和对。希望代码可读且自解释:Delphi 用FPC编写Scheme解释器:递归数据结构,delphi,scheme,pascal,freepascal,sicp,Delphi,Scheme,Pascal,Freepascal,Sicp,本质上,这是一个关于Pascal(FPC)中递归数据结构的问题。由于我想实现一个方案解释器,如SICP第4章所示,这个问题也可能与方案制定者有关: S表达式应表示为标记数据。到目前为止,我已经构建了一个变体记录,它表示数字和对。希望代码可读且自解释: program scheme; type TTag = (ScmFixnum, ScmPair); PScmObject = ^TScmObject; TScmObject = record case ScmObje
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
中存在错误。但我还不明白我到底做错了什么。感谢您的帮助。:) MakePair函数的定义如下:
function MakePair(car, cdr: PScmObject): TScmObject;
MakePair(Test1, Test2);
注意,它接收两个类型为PScmObject
的指针。你可以这样称呼它:
function MakePair(car, cdr: PScmObject): TScmObject;
MakePair(Test1, Test2);
但是Test1
和Test2
属于TScmObject
类型。因此,正如编译器所说,传递的实际参数是不兼容的
您需要传递指向这些记录的指针:
MakePair(@Test1, @Test2);
从长远来看,您需要注意这些记录的生命周期。您将需要在堆上进行分配,而无需进行垃圾收集。我怀疑,您将进入一个痛苦的世界,试图跟踪记录的所有者。也许您可以考虑使用接口引用计数来管理生存期。< P>程序正在期待一个指向记录的指针,而不是记录本身。 您可以在调用点使用@(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.