4

我有一种基于堆栈的自定义语言,我正在尝试将其编译为 CIL,因此可以对其进行 JIT 处理。该语言本身相当简单,因为它只有整数和布尔值。但是,每种数据类型都有一个专用堆栈。语言本身是一个命令流,其中每个命令都可以从任一堆栈中查看、推送和/或弹出值。命令推送/弹出的整数或布尔值的数量永远不会改变(因此命令具有固定的数量)。还有一个平面整数数组,该语言可以读取和写入值,表示外部存储器。堆栈本身可以任意深。

对于像“add”、“subtract”等简单的命令,将整数堆栈命令转换为 CIL 几乎是微不足道的:CIL 堆栈可以完全替换整数堆栈(尽管我有一个附带问题:是否有限制如何CIL 堆栈的深度可以在规范中还是在实践中?)但是也有像 StoreIfTrue 这样的命令,它只会将一个值(来自整数堆栈)存储到某个索引处的平面整数数组(索引也来自整数堆栈) 如果布尔堆栈的顶部值为真。因此,对于某些命令,我​​需要同时访问布尔堆栈和整数堆栈。

现在我必须维护一个 System.Collections.Generic.Stack 来表示布尔堆栈。但是我想知道是否有一种已知的算法或方法可以将我的自定义语言的两个堆栈模型“扁平化”为一个与 CIL 更直接兼容的单一堆栈模型。

4

2 回答 2

1

我认为在一个堆栈中存储两个独立的堆栈是不可能的(至少没有外部临时存储,但是你会得到糟糕的性能)。这是因为无论您使用什么表示,都无法让两个堆栈的顶部以某种方式始终接近实际堆栈的顶部。

但是 CIL 不仅有栈和堆,它还有局部变量。但是您只能通过常量索引访问局部变量。所以,如果你在编译时就一直知道栈顶的索引,而且你也知道栈的最大大小,你就可以用局部变量来表示它。但我认为这两个条件不适用于您的情况。

正因为如此,我认为使用Stack<T>你的一个或两个堆栈是你最好的选择。

于 2012-07-21T08:34:29.360 回答
0

我无法从您的问题中推断出您是否知道如何从例如 C# 生成 CIL 代码。为此,您可以使用ReflectionCecil

对于虚拟执行系统(VES,将执行 CIL 指令的虚拟系统模型)堆栈(和寄存器)上的值没有关联的复杂类型。VES 仅跟踪简单类型(int32、int64、托管对象引用、托管指针和浮点数)。因此,VES 无法看到堆栈上的布尔值和整数之间的区别(在内部,VES 将布尔值视为 32 位整数),因此无法使用执行堆栈来模拟布尔堆栈和整数堆栈。您也可以这样做:将布尔值视为整数,将非零整数视为布尔值 true。因此,对两个整数进行比较会产生另一个整数。但是,那么你只有一个堆栈而不是两个。


编辑

啊,我明白了。您的语言旨在成为通用编程语言,因此必须高度健壮,并且对所有可能的输入(包括无效输入)具有一些预定义(或没有)行为。通过为每种可能的类型设置单独的堆栈,更有可能使用兼容的操作数而不是任何随机操作数。

由于不可能使用单个堆栈来模拟多个堆栈,因此我会Stack<T>为每种类型使用一个真实对象,而不是尝试使用 CIL 堆栈。这有几个优点:

  • 将来更容易添加新类型
  • 允许堆栈边界检查(例如,使操作成为无操作)
  • 比在一个堆栈上混合类型的任何自定义方案更易于管理
  • 随机访问,如果您需要它
  • 无需了解 CIL 内部结构,因此可以在 Mono 和 .Net 上运行
  • CIL 堆栈仅用于临时操作数、堆栈帧和返回地址
于 2012-07-20T22:31:22.903 回答