【问题标题】:Is the primary implementation of *any* popular programming language interpreter written in C++?*任何*流行的编程语言解释器的主要实现是用 C++ 编写的吗?
【发布时间】:2010-07-06 10:56:53
【问题描述】:

目前我正在考虑是否重写我用 C++ 维护的编程语言解释器。解释器目前是用 C 语言实现的。

但我想知道,primary 实现——因为,当然,人们已经使用不同于原作者使用的语言制作了许多解释器的版本——任何流行的 目前使用的编程语言解释器是用 C++ 编写的?

如果没有,是否有充分的理由不用 C++ 编写解释器?我的理解是,如果正确编写 C++ 代码,它可以非常便携,并且可以编译以与执行相同操作的已编译 C 代码一样快。

【问题讨论】:

  • 您的解释器运行了吗?稳定吗?被人使用?为什么要全部重写?
  • 如果你已经有一个 C 实现,那是一个很好的理由不用 C++ 重写它。
  • 当然,我的解释器可以运行,但它存在许多问题——尤其是笨拙的符号处理和大量内存泄漏。这些缺陷是如此之大,以至于我认为解决它们的最佳方法是从头开始重写解释器。鉴于重写语言的唯一两个真正的竞争者是 C 和 C++,我想知道 C++ 是否是实现解释器的更好语言,考虑到它为内存管理和字符串提供(似乎是)更直观的设施处理。
  • +1 因为不认为 C 和 C++ 基本相同。
  • 您对 C++ 的了解与对 C 的了解一样多吗?您对 C++ 的了解是否足以编写程序而无需花费大量时间学习习语和实现目标的最佳方法?本质上,您会在进行此重写的同时学习 C++ 吗?如果是这样,那么恕我直言,您应该坚持您的 C 实现,除非您想在知道自己在做什么后可能再次重写。

标签: c++ c interpreter


【解决方案1】:

我用 C++ 编写了一个解释器(在多年使用 C 之后),我认为 C++ 是一种体面的语言。关于实现,我只会回到过去,改变我对实现同时运行多个不同解释器(每个多线程)的可能性的选择,仅仅是因为它使代码更复杂,而且它从未使用过。多线程非常有用,但是解释器的多个实例毫无意义......

然而,现在我最大的遗憾确实是我编写了那个解释器,因为现在它已在生产中使用,编写了相当多的代码并经过培训,而且因为该语言相当丑陋并且不如 python 强大......但现在切换到 python 会增加成本。它没有我知道的错误......但它比 python 更糟糕,这是一个错误(除了无缘无故支付编写成本的错误之外)。

我最初应该使用 python 代替(或 lua 或任何其他易于嵌入且具有合理许可的现成解释器)......我唯一的借口是我不了解 python 或那时的lua。

虽然编写解释器作为编程练习是一件有趣的事情,但我建议您避免为生产环境编写自己的解释器,尤其是(请不要将其视为个人),如果低级别复杂性所需的关注已不复存在在你的范围内(例如,我发现几个内存泄漏的存在非常令人震惊)。

C++ 仍然是一种低级语言,虽然您可以在内存处理方面获得一些帮助,但 该语言的主要假设是您的代码是 100% 正确,因为没有运行时错误会帮助你(只有未定义的行为守护进程)。

如果您错过了 C(一种更简单的语言)代码 100% 正确的假设,那么我看不出您怎么能确信您会用 C++ 编写正确的代码(相比之下,这是一个复杂的怪物)。我怀疑你最终会得到另一个你必须扔掉的错误解释器。

【讨论】:

  • 我不同意用 C++ 编写 buggy。 C++ 是类型安全的(没有void*),并允许诸如 RAII 之类的习惯用法来管理资源。在我看来,这两个特性使编写无错误代码变得更加容易。说实话,我认为更容易出错的功能实际上来自 C...
  • 对不起,我认为你完全错了。 C++ 最大的问题是复杂性,这并非来自 C。还有一个严重的问题是它可能看起来像一门高级语言,但实际上并非如此,如果你不理解这意味着您将在 C++ 中遭受很多痛苦。编写看起来不错的 C++ 代码非常容易,而这只是一个定时炸弹......例如v.push_back(v.back()); 向非空向量添加最后一个元素的副本。在 C++ 中有很多这样的陷阱。当然这不是 K&R 的错。
  • 好吧,解释器本来不是我写的;我从其他人那里“采用”了它,因此已经存在许多内存泄漏和其他问题。我成功删除了一些,但总体而言,整个实现仍然是一团糟——不是因为原作者是一个糟糕的程序员,而是因为解释器代表了十多年的演变。
  • @Thomas 事情就不同了...我会尝试将 X=(重写和重新调试的成本 + 由于语言不佳而导致脚本的未来成本)与 Y =(嵌入成本)进行比较python和转换脚本(或编写转换器)+程序员培训)。在我看来,用于编写解释器的 C++ 与 C 相比还可以……例如,C++ 异常在解释器中很适合用于处理运行时错误,因为关于状态有一个明确的逻辑“边界”(能够捕获和吞下异常)在一般的“洒水状态”中,C++ 程序在 IMO 中更难正确执行)。
【解决方案2】:

如果您编写了当前的实现并且 - 正如您在评论中所说的那样 - 它具有:

笨拙的符号处理和众多 内存泄漏

然后用 c++ 重写对你没有帮助。首先尝试理解为什么当前的实现会出错。另一方面,如果您不是原始开发人员,那么只需选择您最了解的语言并移植即可。

更新: 我认为sth's comment 正确解释了为什么许多语言是用 C 而不是 C++ 实现的。关于完全重写的话题,heed the words of Joel Spolsky。

【讨论】:

  • 就是这样:我不是最初的开发者。就目前而言,解释器代表了大约 10--15 年的演变,这就是为什么它的代码在某些地方如此混乱的原因。我相当确信,解决其所有缺陷的唯一实用方法是用 C 或 C++ 从头开始​​重写它。但我想知道为什么没有或至少似乎没有用 C++ 编写的流行解释器。但是,当然,总会有第一次。 ;-)
  • 我不认为你写了原版。我更新了我的答案。
【解决方案3】:

是的,很多都是。 IIRC Hotspot Java VM 是用 C++、Haskells ghc、...

编写的

正如这里的许多人所指出的,您真的应该看看LLVM,它是一个用于构建编译器、解释器和虚拟机的工具包。你基本上做前端工作,(即在 LLVM IR 中解析你的语言 + 语义分析 + 代码生成),LLVM 将立即为你提供针对不同平台的构建、jit、优化、编译为本机代码,...... 它还有一些用于解析和 AST 以及错误处理和通知的工具(但也许这是 Clang 子项目的一部分。)

【讨论】:

  • 注意:所有这些都是二手知识。 AFAIK 只是一部分,或者参考实现是用 Haskell 编写的,要生成优化的程序,您需要 gcc 或 LLVM 后端,然后分别用 C 或 C++ 编写。见这里:Fast Haskell using LLVM
  • GHC 编译器是用 Haskell 编写的,GHC 的运行时系统是用 C 编写的,而不是 C++。
【解决方案4】:

大多数流行的编程语言在出现许多优秀的 C++ 编译器之前就已经开始创建。因此,这些语言的主要解释器并不是从 C++ 开始的,一旦你在一个工作解释器中投入了大量工作,你通常不会因为它现在也可以用 C++ 编写而将其丢弃。

如果您为用 C++ 编写的解释器启动一个新项目,它必须走很长的路才能成为 主要 实现。

【讨论】:

  • 使用 LLVM 可能会有所帮助(那是 c++)。
  • @Klaim:是的,例如,clang 是一个严肃的 C/C++/Objective-C 编译器,基于 LLVM 并用 C++ 编写,但很难说它是 primary 那些语言的编译器...
  • 很难说这些语言的任何编译器都是“主要的”。
  • 我还在考虑像 D 这样的新语言。事实上,对于任何新的语言编译器,建议从 LLVM 开始。
  • 然而,编译器和解释器之间的一个根本区别是后者对速度和效率的需求要大得多。当然,没有人愿意整天坐在那里等待程序编译,但如果结果经过优化并且编译后运行迅速,人们就不会真的抱怨。但是解释器每次执行时都必须从头开始运行程序,因此速度是一个真正的问题; “编译”步骤(程序是否编译为字节码、抽象语法树或其他)确实会影响整体运行时速度。
【解决方案5】:

Google Chrome V8 Javascript 引擎实现了 ECMA-262,而且速度极快。也许你可以用 C++ 重写它,但你应该考虑其他特性,比如实现字节码规范,而不是用 C++ 重写你的自动化。重写它只会帮助组织代码(这对团队工作来说是件好事),但对性能没有任何帮助。

【讨论】:

    【解决方案6】:

    GNU 基金会最近刚刚宣布所有新版本的 gcc 都将使用 c++ 编写。

    【讨论】:

    • @spongL allanmcrae.com/2010/06/gcc-in-cxx 采用/转换会很慢,并且不会在“c++ for c++”中完成,但它最终会发生。
    • 我相信 gcc.gnu.org/ml/gcc/2010-05/msg00705.html> 是宣布他们决定在 GCC 代码中允许 C++的线程,但 不意味着它将被重写。这太疯狂了,IMO。
    • 现在对 GCC 来说为时已晚。面对 Clang,我猜他们会慢慢放弃 GCC。
    • @litb: 它将再次成为 egcc,虽然这一次,GCC 很可能会永久退役,我只是希望 GCC 的一些自我放屁不要进入铿锵行列。
    • @litb “他们”是谁? fsf的人? @Hippicoder 如果来自 gcc 的“ego-farts”是优秀的程序员,他们为什么不应该去铿锵行列? (无论如何,他们应该尊重设计、指导方针和任何东西)
    【解决方案7】:

    Tamarin - Adob​​e 和 Mozilla ECMAScript 解释器是用 C++ 编写的。作为原始语言作者负责的那个,它可能被认为是主要的(IIRC ECMA 参考实现是用 OCaml 编写的,但实际上除了作为参考之外并没有使用它)

    【讨论】:

      【解决方案8】:

      Sun 的 Java 实现似乎主要是用 C++ 编写的。

      【讨论】:

        【解决方案9】:

        如果内存泄漏是您当前程序的唯一问题,请尝试使用 valgrind。我的软件中从未出现过 valgrind 无法为我追踪的内存泄漏。事实上,它在很多场合都救了我的命。

        这里有教程

        http://www.cprogramming.com/debugging/valgrind.html

        【讨论】:

        • Valgrind 是一个非常有用的工具,但在我采用的解释器中 (1) 内存泄漏需要影响深远的“彻底”修复,这些修复需要我重写部分代码并有可能弄乱程序的某些部分(可能导致悬空指针等),并且(2)内存泄漏不是唯一的问题;我想对符号处理进行大量更改,如果有意义的话,现有系统太复杂而无法安全更改。
        【解决方案10】:

        我认为我不能(或不想)对此表示“是”。我认为这是一个实用主义结合个别语言需求的问题,还取决于它是编译语言(或字节码编译)还是解释语言,还是......

        如果你正在尝试编写跨平台代码,你会发现最低公分母通常是 C 编译器(由于 CPU 架构不同,汇编器不适合部署到很多平台上)。由于 C++ 被编码为位于大多数 C 基础架构之上(例如使用名称修饰来使类型重载适合 C 链接器理解的内容),因此它通常是即使在嵌入式系统上也可用的最低公分母 OO 语言。这使其成为希望以高级、可维护的方式编写语言的人们的热门选择。

        此外,大多数编程语言都有存在的理由,希望以不同的方式解决问题(更好必然意味着不同,毕竟),这意味着他们对代码需要能够做什么有相当不寻常的需求,并且不要使用其他实现语言提供的大量支持工具,因为它们对它没有足够的控制权。因此,鉴于您需要重新实现很多例如无论如何,对象模型和数据类型,C++ 的低级方面实际上是一个优势。

        也就是说,许多语言都是从用 C++ 编写的第一个版本开始的,例如第一个简单的编译器,然后在那个简单的版本中编写下一个版本(“引导程序”)。这样做的好处是您可以使用自己的语言对其进行扩展。为了移植它,他们只修改他们的编译器以交叉编译到所需的平台,然后用这个交叉编译器构建编译器,结果是新平台的完整语言的本机版本。

        倾向于不这样做的语言通常主要是脚本语言,它们倾向于保持为解释型 C++ 实现的语言(尽管其他人提到了流行的例外)。

        选择 C++ 的另一个常见原因是现有的基础架构。例如。如果你想绑定到现有的系统框架,你通常需要下拉到 C++,或者如果你想利用现有的编译器后端(如 LLVM,它是用 C++ 编写的),或者即使它们只使用 C,通常C++ 是最合适的类 OO 实现语言,可以轻松与系统的 C 部分进行对话。

        所以你想问自己的问题很可能是:我的需求是什么,哪种语言最适合这些需求?

        有些语言只是另一种语言的预处理器(C++ 和 Objective-C 都是作为 C 之上的预处理器开始的)。他们添加自己的语法或特性,将它们翻译成实现语言,然后使用现有编译器编译修改后的代码。如果一种语言已经可以满足您的所有需求,那可能是一种更好的方法,并且可以让您利用使用该语言的工程师的经验,将您的工作时间组合成您一个人无法提供的更多时间。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-20
          相关资源
          最近更新 更多