在C / C ++中实现解释器所需的参考文献

我发现自己附属于一个项目,将口译员融入到现有的应用程序中。 要解释的语言是Lisp的一个衍生物,具有特定于应用程序的内置函数。 个别“程序”将在应用程序中以批处理方式运行。

我感到惊讶的是,多年来我写了几个编译器和几个数据语言翻译器/parsing器,但是我从来没有真正写过翻译器。 原型在C ++中被实现为一个语法树walker。 我可能会影响架构超出原型,但不是实现语言(C ++)。 所以,约束:

  • 实现将在C ++中进行
  • parsing可能会用yacc / bison语法来处理(现在是这样)
  • 完整的虚拟机/解释器生态系统,如NekoVM和LLVM的build议可能不适合这个项目。 自给自足是更好的,即使这听起来像NIH。

我真正想要的是阅读实施口译员基本原理的材料。 我做了一些浏览SO,另一个网站叫做Lambda Ultimate ,虽然他们更倾向于编程语言理论。

到目前为止,我收集的一些花絮:

  • Lisp in Small Pieces ,作者:Christian Queinnec。 推荐它的人说:“从简单的解释器到更高级的技术,完成字节码和'Scheme to C'编译器。

  • NekoVM 。 正如我上面提到的,我怀疑我们会被允许整合一个VM框架来支持这个项目。

  • 计算机程序的结构和解释 。 本来我build议这可能是矫枉过正,但通过一个健康的块,我同意@JBF。 非常丰富的信息,并扩大思维。

  • 关于Lisp by Paul Graham。 我已经阅读了这篇文章,虽然这是对Lisp原理的丰富介绍,但还不足以启动构build一个解释器。

  • 鹦鹉执行 。 这似乎是一个有趣的阅读。 不知道它会为我提供基础。

  • 计划从零开始 。 Peter Michaux正在攻击Scheme的各种实现,从用C语言编写的快速简洁的Scheme解释器(用作后面项目中的引导程序)到已编译的Scheme代码。 到目前为止非常有趣。

  • 语言实现模式:创build您自己的特定领域和一般编程语言 , 在创build解释语言书籍的评论主题中推荐。 这本书包含了两个章节,专门介绍build立口译员的做法,所以我将其添加到我的阅读队列中。

  • 新的 (还有旧的 ,即1979年): 编写 PJ布朗交互式编译器和口译员 。 这已经很长时间了,但是在提供与实施基本解释器相关的各种任务的大纲方面很有意思。 我已经看到了这个评论的混合,但因为它很便宜(我已经订购了大约3.50美元)我会给它一个旋转。

那么怎么样? 有没有一本好书能够让初学者学习如何在C / C ++中为Lisp类语言构build一个解释器? 你有偏好的语法树步行者或字节码解释器?

要回答@JBF:

  • 目前的原型是一个解释器,对我来说是合理的,因为我们正在接受一个任意代码文件的path,并在我们的应用程序环境中执行它。 内build函数用来影响我们的内存数据表示。

  • 它不应该是非常缓慢。 目前的树步行者似乎可以接受。

  • 该语言基于 Lisp,但不是Lisp,所以不需要遵守标准。

  • 如上所述,我们不太可能会被允许添加一个完整的外部虚拟机/解释器项目来解决这个问题。

对其他海报,我也会检查你的引文。 谢谢,所有!

简短的回答:

口译员的基本阅读清单是SICP。 如果你觉得你对本书第一部分的评价过高,你可以跳到第四章开始解释(尽pipe我觉得这会是一个损失,因为1-3章确实很好! 。

LISP添加小件(LISP从现在开始),第1-3章。 特别是第3章,如果你需要实施任何不平凡的控制forms。

Jens AxelSøgaard在一个最小的自我托pipe计划上看到这篇文章: http : //www.scheme.dk/blog/2006/12/self-evaluating-evaluator.html 。

稍微长一点的答案:

如果不知道口译员需要什么,很难给出build议。

  • 它确实需要做一个解释器,还是你真的需要能够执行lisp代码?
  • 它需要快速吗?
  • 它是否需要遵守标准? 常见的嘴唇? R5RS? R6RS? 你需要什么SFRI?

如果你需要比简单的语法树walker更花哨,我强烈build议embedded一个快速scheme子系统。 Gambit计划浮现在脑海中: http : //dynamo.iro.umontreal.ca/~gambit/wiki/index.php/Main_Page 。

如果这不是SICP中的第5章和LISP目标编译中的第5章选项,则可以加快执行速度。

为了更快的解释我会看看最近的JavaScript解释器/编译器。 快速执行JavaScript似乎有很多想法,你可以从中学习。 V8引用了两篇重要论文: http : //code.google.com/apis/v8/design.html和squirrelfish引用了一对夫妇: http : //webkit.org/blog/189/announcing-squirrelfish/ 。

RABBIT编译器还有一些规范的scheme论文: http ://library.readscheme.org/page1.html。

如果我进行一些过早的猜测,内存pipe理可能成为一个难题。 Nils M Holm出版了一本书“来自空地的计划9” http://www.t3x.org/s9fes/ ,其中包括一个简单的“停止世界”标记和清扫垃圾收集器。 包括来源。

约翰·罗斯(更新的JVM名气)写了一篇关于将Scheme与C整合的文章: http : //library.readscheme.org/servlets/cite.ss?pattern=AcmDL-Ros-92 。

是的,在SICP。

我已经多次完成了这个任务,如果我是你,我会这样做:

先devise你的记忆模型。 你会需要某种GC系统。 这是WAAAAY更容易做到这一点,而不是稍后进行。

devise你的数据结构。 在我的实现中,我有一个基本的基本types的基本框:primefaces,string,数字,列表,布尔,原始函数。

devise您的虚拟机,并确保保持API清洁。 我最后的实现有这个作为一个顶级的API(原谅的格式 – 这是pooching我的预览)

ConsBoxFactory &GetConsBoxFactory() { return mConsFactory; } AtomFactory &GetAtomFactory() { return mAtomFactory; } Environment &GetEnvironment() { return mEnvironment; } t_ConsBox *Read(iostream &stm); t_ConsBox *Eval(t_ConsBox *box); void Print(basic_ostream<char> &stm, t_ConsBox *box); void RunProgram(char *program); void RunProgram(iostream &stm); 

RunProgram是不需要的 – 它是按照Read,Eval和Print来实现的。 REPL是解释者的一种常见模式,特别是LISP。

ConsBoxFactory可用于制作新的缺陷盒并对其进行操作。 AtomFactory被用来使等价的符号primefaces映射到一个对象。 一个环境用于维护符号与cons箱的绑定。

你的大部分工作应该进入这三个步骤。 然后你会发现你的客户端代码和支持代码开始看起来非常像LISP:

 t_ConsBox *ConsBoxFactory::Cadr(t_ConsBox *list) { return Car(Cdr(list)); } 

你可以在yacc / lex中编写parsing器,但是为什么呢? Lisp是一个令人难以置信的简单的语法和扫描/recursion下降parsing器对,因为它大约需要两个小时的工作。 最糟糕的部分是编写谓词来识别令牌(即IsString,IsNumber,IsQuotedExpr等),然后编写例程将令牌转换为cons箱。

在C代码中写入和粘贴胶水很容易,并且在事情出错时很容易debugging问题。

塞缪尔·卡明(Samuel Kamin)的书“ 编程语言 ”( Programming Languages,The Interpreter-Based Approach)一书中的Kamin解释器由Timothy Budd翻译成C ++。 我不确定裸露的源代码是多么有用,因为它本来就是本书的用武之地,但它是一本很好的书,涵盖了使用低级语言实现Lisp的基础知识,包括垃圾收集等。这不是本书的重点,一般来说这是编程语言,但它已经被覆盖。)

Lisp in Small Pieces更深入,但是这对你的情况来说是好的和坏的。 编译有很多资料,这些资料与你无关,而且它的简单解释器在Scheme中,而不是在C ++中。

SICP是好的,当然。 不过分,但是当然,编写口译只是本书的一小部分。

JScheme的build议也是一个很好的(它包含了我的一些代码),但不会帮助你像GC一样。

我可能会在后面提出更多的build议。

编辑:有几个人说,他们从我的awklisp了解到。 这确实是一个奇怪的build议,但它非常小,可读,实际上可用,并且不像其他可读的小玩意儿Lisp实现它自己的垃圾收集器和数据表示,而不是依靠底层的高级实现语言来提供他们。

查看Peter Norvig的JScheme 。 我发现这非常简单,理解和移植到C ++。 呃不知道如何使用scheme作为一种脚本语言 – 教给人们很麻烦,而且感觉过时(1980年代)。

我想扩展我对编程语言:应用和解释的build议 。 如果你想写一个口译员,那本书就会把你带到一个很短的路上。 如果你通过编写你阅读的代码来阅读和做练习,你会得到一堆类似的解释器,但是不同的是(一个是热切的,另一个是懒惰的,一个是dynamic的,另一个是打字的,一个是dynamic范围的,其他有词汇范围等)。