使解释器执行得更快

Make interpreter execute faster

我为一种简单的语言创建了一个解释器。它是基于 AST 的(更准确地说,是一种不规则的异构 AST),访问者执行和评估节点。但是我注意到它与 "real" 解释器相比非常慢。为了测试,我 运行 这个代码:

i = 3
j = 3
has = false
while i < 10000
     j = 3
     has = false
     while j <= i / 2
          if i % j == 0 then
              has = true
          end
          j = j+2
     end
     if has == false then
          puts i
     end
     i = i+2
end

在 ruby 和我的解释器中(只是简单地找到素数)。 Ruby 不到 0.63 秒完成,我的翻译超过 15 秒。

我用 C++ 和 Visual Studio 开发解释器,所以我使用探查器来查看最耗时的内容:求值方法。 50% 的执行时间用于调用抽象评估方法,然后转换传递的表达式并调用适当的评估方法。像这样:

Value * eval (Exp * exp)
{
   switch (exp->type)
   {
   case EXP_ADDITION:
        eval ((AdditionExp*) exp);
        break;

    ...
   }
}

我可以将 eval 方法放入 Exp 节点本身,但我想保持节点清洁(Terence Parr 在他的书中谈到了可重用性)。

同样在求值时,我总是重建 Value 对象,它存储求值表达式的结果。实际上 Value 是抽象的,它具有针对不同类型的派生值 类(这就是我使用指针的原因,以避免在返回时进行对象切片)。我认为这可能是速度慢的另一个原因。

如何使我的解释器尽可能优化?我应该从 AST 中创建字节码然后解释字节码吗? (据我所知,他们可以更快)

如果它有助于理解我的问题,这是来源:src

注意:我还没有做任何错误处理,所以非法语句或错误只会冻结程序。 (也对不起笨蛋"error messages" :))

语法很简单,当前执行的文件在OTZ1core/testfiles/test.txt(这是prime finder)中。

我很感激能得到任何帮助,我真的是编译器和解释器的初学者。

一种加速的可能性是使用函数 table 而不是动态重新键入的开关。您对 typed-eval 的调用至少要经过一个(可能是几个)间接级别。如果您改为 通过名称 来区分类型化函数并赋予它们相同的签名,则可以将指向各种函数的指针打包到一个数组中并由类型成员进行索引。

value (*evaltab[])(Exp *) = {  // the order of functions must match
    Exp_Add,                   // the order type values
    //...
};

那么整个开关就变成了:

evaltab[exp->type](exp);

1 个间接,1 个函数调用。快.