将未分类的Lisp数据映射为类型化的二进制格式,以便在编译函数中使用

时间:2011-06-30 02:55:03

标签: data-structures haskell lisp scheme llvm

背景:我正在Haskell写一个玩具Lisp(Scheme)解释器。我希望能够使用LLVM编译代码。我花了几天时间想出各种方法将无类型的Lisp值提供给编译函数,这些函数希望知道它们的数据格式。在我看来,我不是第一个需要解决这个问题的人。

问题:将无类型数据映射为高效二进制格式的历史成功方法是什么。

附录:事实上,我确实知道数据中的十几种不同类型,我只是不知道在编译时可能会将哪一种发送到该函数。函数本身需要一种方法来确定它得到了什么。

2 个答案:

答案 0 :(得分:3)

你的意思是,“我只是不知道哪些[类型]可能被发送到运行时的功能”?并不是数据没有打字;当然1'()有不同的类型。相反,数据不是静态类型的,即,在编译时不知道给定变量的类型是什么。这称为dynamic typing

你是对的,你不是第一个需要解决这个问题的人。规范解决方案是标记每个运行时值及其类型。例如,如果您有十几种类型,请将它们编号为:

  • 0 =整数
  • 1 = cons
  • 2 = vector

完成此操作后,请为标记保留每个单词的前四位。然后,每次将两个对象传入+时,首先执行一个简单的位掩码,以验证两个对象的前四位是0b0000,即它们都是整数。如果不是,则跳转到错误消息;否则,继续添加,并确保结果也相应标记。

这种技术本质上使得每个运行时值都是手动的 - tagged union,如果您使用过C,这对您来说应该很熟悉。事实上,它也像Haskell数据类型一样,除了在Haskell中标记性更加抽象。

如果您正在尝试编写Scheme编译器,我猜您熟悉指针。为避免限制可用内存空间,使用底部(最低有效)四位而不是顶部位可能更为敏感。更好的是,因为对齐的双字指针底部已经有三个无意义的位,所以只要取消引用实际地址而不是标记的地址,就可以简单地为这些位添加这些位。

这有帮助吗?

答案 1 :(得分:2)

您的默认解决方案应该是一个简单的标记联合。如果你想缩小你的打字范围到更具体的类型,你可以做到 - 但它不再是那个“玩具”了。需要注意的是abstract interpretation

这种优化的成功实施很少,V8可能是最普遍的。在Scheme世界中,最积极的优化实现是Stalin