用FPC编写方案解释器:递归数据结构 [英] Writing a Scheme interpreter with FPC: Recursive data structures

查看:166
本文介绍了用FPC编写方案解释器:递归数据结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,这是Pascal(FPC)中递归数据结构的一个问题。正如我想实施一个像SICP第4章一样的一个Scheme解释器,这个问题也可能与Schemers有关。 :)



S表达式应表示为标记数据。到目前为止,我已经构建了一个变量记录,它表示数字和对。希望代码是可读的和不言自明的:

 程序方案; 

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

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

函数MakeFixnum(x:integer):TScmObject;
var
fixnum:TScmObject;
begin
fixnum.ScmObjectTag:= ScmFixnum;
fixnum.ScmObjectFixnum:= x;
MakeFixnum:= fixnum;
结束

函数MakePair(car,cdr:PScmObject):TScmObject;
var
pair:TScmObject;
begin
pair.ScmObjectTag:= ScmPair;
pair.ScmObjectCar:= car;
pair.ScmObjectCdr:= cdr;
MakePair:= pair;
结束

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);
结束。

但是,编译代码会产生如下错误:

  $ fpc scheme.pas 
(...)
编译scheme.pas
scheme.pas(43,34)错误:参数号不兼容的类型2:得到TScmObject,预期PScmObject
scheme.pas(45)致命:有1个错误编译模块,停止
致命:编译中止

很明显,函数 MakePair 中有一个错误。但我不明白我究竟做错了什么。任何帮助是赞赏。 :

解决方案

MakePair 函数定义如下:函数MakePair(car,cdr:PScmObject):TScmObject; p>

 

请注意,它接收两个类型为的指针PScmObject 。你可以这样调用:

  MakePair(Test1,Test2); 

但是 Test1 Test2 的类型为 TScmObject 。所以传递的实际参数是不兼容的,正如编译器所说。



您需要将指针传递给这些记录:

  MakePair(@ Test1,@ Test2); 






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


Essentially, this is a question about recursive data structures in Pascal (FPC). As I would like to implement a Scheme interpreter like it is shown in SICP chapter 4, this question may be relevant for Schemers as well. :)

S-expressions shall be represented as tagged data. So far, I have constructed a variant record, which represents numbers and pairs. Hopefully the code is readable and self-explanatory:

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.

However, compiling the code yields an error as follows:

$ 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

It is obvious that there is an error in the function MakePair. But I do not understand yet what exactly I am doing wrong. Any help is appreciated. :)

解决方案

The MakePair function is defined like this:

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

Note that it receives two pointers of type PScmObject. You then call it like this:

MakePair(Test1, Test2);

But Test1 and Test2 are of type TScmObject. So the actual parameters passed are not compatible, just as the compiler says.

You need to pass pointers to these records instead:

MakePair(@Test1, @Test2);


In the longer term you are going to need to be careful about the lifetime of these records. You'll need to allocate on the heap and without garbage collection I suspect that you'll enter a world of pain trying to keep track of who owns the records. Perhaps you could consider using interface reference counting to manage lifetime.

这篇关于用FPC编写方案解释器:递归数据结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆