加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 用FPC编写一个Scheme解释器:Allocation和Pointers

发布时间:2020-12-15 09:25:34 所属栏目:大数据 来源:网络整理
导读:作为一名历史学家,在第一阶段已经写了一个 Scheme interpreter in FPC转,对我来说是一个严肃的任务. :)我正在关注Peter Michaux的博客,who showed how to do it in C(还有一个 Ada的翻译,可能对Pascal有帮助). 从Michaux的工作中考虑C中的这两个函数(v 0.1)
作为一名历史学家,在第一阶段已经写了一个 Scheme interpreter in FPC转,对我来说是一个严肃的任务. :)我正在关注Peter Michaux的博客,who showed how to do it in C(还有一个 Ada的翻译,可能对Pascal有帮助).

从Michaux的工作中考虑C中的这两个函数(v 0.1):

object *alloc_object(void) {
    object *obj;

    obj = malloc(sizeof(object));
    if (obj == NULL) {
        fprintf(stderr,"out of memoryn");
        exit(1);
    }
    return obj;
}

object *make_fixnum(long value) {
    object *obj;

    obj = alloc_object();
    obj->type = FIXNUM;
    obj->data.fixnum.value = value;
    return obj;
}

据我所知(只是C中的基本阅读知识),构造函数make_fixnum返回一个指向struct的指针(类型为fixnum的标记数据);对于构造的对象,必须分配内存(感谢@David Heffernan为他的point昨天).

这是我到目前为止对FPC的翻译,它编译时没有任何错误:

program scheme;

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

var Test: PScmObject = nil;

procedure AllocateObject(x: PScmObject);
begin
    new(x);
end;

function MakeFixnum(x: integer): PScmObject;
var
   fixnum: PScmObject = nil;
begin
   AllocateObject(fixnum);
   fixnum^.ScmObjectTag := ScmFixnum;
   fixnum^.ScmObjectFixnum := x;
   MakeFixnum := fixnum;
end;

begin
   Test := MakeFixnum(1);
   writeln(Test^.ScmObjectTag);
   writeln(Test^.ScmObjectFixnum);
end.

然而…:

$./test 
Runtime error 216 at $080480DD
  $080480DD
  $08048117
  $08063873

我怀疑,我使用和引用指针有一个严重的缺陷.

非常感谢任何帮助我理解指针和记忆内容如何工作的人(也欢迎参考常见问题解答,论文等).

解决方法

您的AllocateObject函数是错误的.它在变量x中创建一个新对象,但它不会将创建的对象传递给调用函数,因为它是通过值调用的.如果您更改调用约定,它将起作用:

procedure AllocateObject(out x: PScmObject);
 begin 
    new(x);
 end;

您可以看到如果您在调试器中查看fixnum变量,它保持为零.

与您的问题无关,我认为在翻译中使用记录并不是一个好主意.它很快就变成了一个管理噩梦的内存(至少在我接近20 kloc的时候写的翻译中发生了这种情况,我不得不更换记录如下:)

而不是你的记录

PScmObject = ^TScmObject;
 TScmObject = record
    case ScmObjectTag: TTag of
       ScmFixnum: (ScmObjectFixnum: integer);
    end;

你可以使用类,如:

TScmObject = class()
  function Tag: TTag; virtual; abstract;
  function Fixnum: integer; virtual; abstract;
end;
TScmObjectFixNum = class(TScmObject)
  function Tag: TTag; override;
  function Fixnum: integer; override;
private
  value: integer;
end;

function TScmObjectFixNum.Tag: TTag;
begin
  result := ScmFixnum; 
end;
function TScmObjectFixNum.Fixnum: integer; 
begin
  result := value; 
end;

然后你可以轻松地创建它

var x: TScmObject;
 x := TScmObjectFixNum.create() ;
 if x.tag = scmfixnum (* or x is TScmObjectFixNum *) then
    ... x.scmfixnum ...
 x.free

如果您的方案实现中没有循环引用,您甚至可以使用接口.然后它被引用计数并自动释放:

IScmObject = interface
  function Tag: TTag;
  function Fixnum: integer;
end;
TScmObject = class(TInterfacedObject,IScmObject)
  function Tag: TTag; virtual; abstract;
  function Fixnum: integer; virtual; abstract;
end;
TScmObjectFixNum = class(TScmObject)
  function Tag: TTag; override;
  function Fixnum: integer; override;
private
  value: integer;
end;



 var x: IScmObject;
 x := TScmObjectFixNum.create() ;
 if x.tag = scmfixnum (* or x is TScmObjectFixNum *) then
    ... x.scmfixnum ...
 //x.free no longer necessary (or allowed)!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读