编译简单VM的switch语句

时间:2014-03-04 08:44:53

标签: c compiler-construction compilation switch-statement stack-machine

所以我将C的一个子集编译成一个简单的堆栈VM用于学习目的,我想知道如何最好地编译switch语句,例如。

switch (e) {
  case 0: { ... }
  case 1: { ... }
  ...
  case k: { ... }
}

我正在阅读的书提供了一种使用索引跳转编译它的简单方法,但书中描述的简单方案仅适用于连续的,递增的案例值范围。

现在我正在使用符号标签进行第一次传递,在第二次传递期间,我将把标签解析为实际的跳转目标,因为使用标签可以将初始编译简化为堆栈指令。我现在的想法是使用以下方案将书中的内容概括为任何顺序的任何顺序的案例值序列。调用案例值c1, c2, ..., cn和相应的标签j1, j2, ..., jn然后生成以下序列的指令,假设e的值位于堆栈顶部:

dup, loadc c1, eq, jumpnz j1,
dup, loadc c2, eq, jumpnz j2,
...
dup, loadc cn, eq, jumpnz jn,
pop, jump :default
j1: ...
j2: ...
...
jn: ...
default: ...

表示希望是清楚的,但如果没有:dup =堆栈顶部的重复值,loadc c =在堆栈顶部推送一个常量ceq =比较堆栈上的前两个值,并根据比较推送0或1,jumpnz j =如果顶部堆栈值不为0,则跳转到标签jlabel: =某个将在第二次编译过程中解析为实际地址。

那么我的问题是编译switch语句的其他一些方法是什么?对于连续的案例值范围,我的方法比索引跳转表紧凑得多,但是当存在大的间隙时,效果非常好。

1 个答案:

答案 0 :(得分:3)

首先对所有案例进行排序。然后识别所有(大到足够大)连续或接近连续的序列,并将它们视为用跳转表处理的单个单元。然后,使用平衡的分支二叉树代替比较和跳转的线性序列,以最小化平均跳跃次数。你可以通过递归地比较病例或病例块的中位数来做到这一点。