Writing a schema interpreter with FPC: recursive data structures

Essentially, this is a question about recursive data structures in Pascal (FPC). Since I would like to use the Schema interpreter, as shown in SICP chapter 4, this question may be relevant for Schemers. :)

S-expressions should be represented as tagged data. So far I have created a variant record that represents numbers and pairs. We hope that the code is readable and requires no explanation:

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 results in an error:

 $ 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 

Obviously, there is an error in the MakePair function. But I still do not understand what exactly I am doing wrong. Any help is appreciated. :)

+3
source share
2 answers

The MakePair function MakePair defined as follows:

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

Notice that it gets two pointers of type PScmObject . Then you call it like this:

 MakePair(Test1, Test2); 

But Test1 and Test2 are of type TScmObject . Thus, the actual parameters passed are incompatible, as the compiler says.

You need to pass pointers to these entries:

 MakePair(@Test1, @Test2); 

In the long run, you need to be careful about the life of these records. You will need to allocate a bunch without garbage collection. I suspect you will enter a world of pain trying to keep track of who owns the recordings. Perhaps you could use an interface reference counter to control the lifetime.

+7
source

The procedure expects a pointer to the record, not the record itself.

You can use the @ (at) operator at the point of call to create an on-the-fly pointer in a record, and thus perform a compiler type check:

 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. 
+4
source

All Articles