更难构建的是仿真器还是编译器?

10

一个有10-20年经验的熟练开发人员,如果从未构建过编译器或模拟器,哪种更具挑战性?

你能比较一下两者可能遇到的障碍。

谢谢。

9个回答

10

仿真和编译是非常不同的,但由于两者都被视为“低级别”,所以往往被混在一起。

仿真一个简单的架构,比如6502或Z80,对于CPU部分来说将是相当简单的,但需要编写大量代码,因为你需要为每个指令编写一个函数。你需要以某种方式自动化这个过程,从指令集规范到所有时序等内容,因为手动输入这些将是非常繁琐的 :) 旧的CPU指令集规范很容易找到,因此在构建仿真器时这有很大的帮助。

除此之外,你还需要实现某种程度的硬件仿真,通常涉及处理和生成中断(例如,如果仿真器是为游戏机而设计,则需要处理和生成显示设备的垂直同步中断)。这又需要一定的规范和代码生成,但你可能需要手工编写大部分代码,因为它不会像指令集代码那样重复(因此无法自动化)。

编译将涉及到将要实现编译器的语言规范和目标输出代码的目标。输出可以是二进制的,也可以是汇编的,甚至可以是另一种语言(这实际上只是一个翻译器,但当目标被认为足够“低级别”时,它也被视为编译)。由于你将在某种硬件或虚拟机平台上运行,因此你不太可能担心中断处理等问题。

两者的难点都是复杂性和正确性-- 对于仿真器,除非你选择非常简单的东西进行仿真,否则你需要使其非常准确。你还需要为仿真器创建某种集成调试器,否则当它无法正常工作时,很难知道出了什么问题。对于编译器来说,将一个玩具语言或更复杂语言的小子集翻译成目标代码应该相对简单,并且可以逐步构建。

请记住,对于这两个项目,您需要能够生成输入以进行测试。如果您无法生成简单的输入,则会发现从一开始就很难进行调试。 仅此一点就使得编译器的工作更容易上手,这是我个人认为的看法 (还有,您可能需要立即拥有一个模拟完整控制台或类似东西的程序 :))


感谢您详细而周到的回复。看起来普遍的共识是模拟器会更加困难。 - Mark Lindell
2
不,看起来大家的共识是模拟器更容易。 - arturh

8
我已经写过两者,如果其他条件相同(语言或指令集的复杂性),我会说编写模拟器要容易得多,特别是如果您正在尝试编写一个有趣的模拟器或编译器。
原因是,在模拟器中,您正在尝试使用另一个类似的低级工具模拟低级事物。这不太难。而在编译器中,您可能正在尝试使用非常低级的工具(机器字和机器指令)实现非常高级的想法(例如对象、一级函数、托管内存、字符串扫描)。这个任务就更加困难了。
当然,为了获得乐趣,您可以编写一个通过动态二进制转换工作的模拟器,这是将模拟体系结构的机器代码编译成本地体系结构的机器代码。这样,您就可以同时拥有所有乐趣,并且可以生成像QEMU或已故的Digital FX!32那样的快速模拟器。

6

我写过两种方式,我认为模拟器通常更容易。当然,这在很大程度上取决于你想要模拟什么(在iPhone上模拟IBM大型机可能有些困难)以及你想要编译什么(一个小的C编译器相当容易,一个完整的C++编译器几乎是不可能的难度)。


3

这主要取决于你所模拟的内容以及你所编译的内容。

  • 在功能强大的系统(如现代PC)上模拟非常简单的系统(如四则运算计算器)将很容易实现。
  • 为单个目标编译非常简单的语言(如几乎直接映射到输出汇编的语言)将很容易实现。
  • 在非常简单的系统(如PDA)上模拟非常复杂的系统(如大型专有计算系统)将非常难以实现。
  • 为多个目标编译高级语言(如完整的C++)将非常难以实现。

一个完整的C++编译器将非常难编写,即使只针对单一目标也是如此! - Paul
@Colin:当然,我想要举例说明这个极端情况,并找到一些非常、非常难的东西! - Daniel LeCheminant

2
在我看来,编写复杂的编译器比编写复杂的模拟器更难,原因是编译器涉及到更多理论。当设计你的语言XX时,需要考虑很多因素,更不用说优化编译器生成的代码输出了,这本身就是一门黑艺术。而对于模拟器,你已经有一个定义良好的环境和大部分定义良好的语言要实现。
无论如何,我建议任何人都应该编写编译器,因为它可以让你更深入地了解编程,就像医生需要了解身体解剖学一样,即使他在日常工作中可能用不到它。
编辑:我认为这两种技能都非常有用,实际上可以将它们结合起来使用——它们不是互斥的。
我想补充一下我的观点,创建一个包括与驱动程序、数据库等交互的运行时库,并且可以随着未来版本的演变而发展但仍保持向后兼容性的非平凡编程语言是计算机科学中较具挑战性的领域之一。
我也同意,如果平台是未知的,即你正在反向工程某个东西,那么做模拟器会更加困难,但另一方面,这不是OP的问题所在,对吧?

1
没有理由看到 -1。+1。 - Joey Robert
1
模拟未知平台需要了解数学、加密算法、网络/磁盘协议等。我不会说它需要的理论比编译器少。 - friol

1

编写已知模拟平台的仿真器并不难(您也可以使用预制的CPU仿真器,以节省一些开发时间)。

编写未知模拟硬件的仿真器则要困难得多,并将难度转移到与代码开发不同的领域:数学、密码分析、安全协议等。作为开发人员,您必须对涉及到的试错过程有耐心。

例如,想想CPS2仿真所需的时间(CPS2 ROM是加密的)。


1

如果没有上下文,就没有明确的答案:一切都取决于你想要实现什么,以及你正在面对什么。

如果只是一个“概念验证”,那么在这两种情况下,它都相当简单。

但是,如果您试图模拟具有高精度的复杂硬件或者想要达到AAA编译质量,事情很快就会变得非常复杂。复杂性不仅出现在“主”代码的算法/理论中,还出现在您将不得不构建的所有支持工具中(调试器、反汇编器、分析器等),以便您可以进入下一步。

话虽如此,另一个需要考虑的方面是,为几乎任何编程语言编写工作编译器都具有合理的复杂性。另一方面,如果存在易于模拟的硬件,也有硬件的编写甚至基本仿真器都可能非常复杂。

因此,总体而言,我会说编写编译器更容易,因为您几乎可以保证获得一个工作版本,无论目标硬件或语言如何。对于仿真器则没有这样的保证。


1

软件仿真相对来说比较简单,但可能会很繁琐。

编写编译器可能非常困难,但如果您对所编写的语言有良好的工作知识或拥有一组良好的规范(例如Backus-Naur形式符号),则可以使其变得更简单。

如果您的目标是使仿真器在许多不同的平台上运行(例如,在MSDOS下使用正确的调整常数可以运行软盘驱动器的定时仿真,但在像Vista或Linux这样的多任务平台上仿真失败),那么硬件仿真可能会非常困难。当关于如何通过软件控制其操作模式的知识不足时,硬件仿真也非常困难。这迫使进行漫长而烦人的逆向工程才能取得进展。

总的来说,我认为仿真更加困难。


0

编写编译器要困难得多,因为你要处理更低级别的东西(链接、特定于你的架构的汇编语言等)。

模拟器只需要执行输入给它的每个指令的逻辑即可(我知道我在简化这个过程,但我假设你有指令集的规格),现在,编写一个快速的模拟器要困难得多。


你没有考虑 CPU JIT 重新编译器(在模拟器中使用)。 - friol
6
编写一个快速模拟器要困难得多。 - CookieOfFortune

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接