如何用JavaScript编写简单的解释器

源码下载-2.9KB

编写解释器和编译器

编写解释器或编译器是编程方面最有教育意义的任务之一,因为你可以熟悉代码解释和求值过程。你可以更深入地掌握哪些任务在后台运行、以及语言设计背后的决定方面的见解。

本文向你展示如何为一种简单语言编写用于计算器应用程序的解释器,以呈现此过程的基本概观。

本文假设你具备了中级编程经验和基本熟悉JavaScript。

背景

解释器、编译器和转换编译器的区别

本文,我们将创建解释器,而非编译器。我们的程序将要把一些代码做为输入,并立即计算。

如果我们在写编译器,我们将把源语言里的输入代码转换成某种较低级的目标语言的代码,比如MSIL,或汇编语言,甚至机器代码。

转换编译器除了源语言和目标语言都是同样等级的抽象之外,其它地方与编译器相似。在客户端的web编程世界里,标准例子就是CoffeeScript,它转换编译为JavaScript。

为什么你的代码如此难以理解

“我到底在想什么?!?”

凌晨1:30分,我正盯着不到一个月前我写的一段代码。当时它看起来像是件艺术品,全部是可理解的,优雅、简单、让人叹为观止。这一切都不再了,明天是我的最后期限,数小时前我发现了一个bug。当时看起来的简单和逻辑再也说不通了。可以肯定的是,如果我写代码,我应该足以聪明到理解代码?

经过了多次这种经历以后,我开始认真思考,为什么我的代码在我编写的时候很清楚、而当我数周或数月后回头看的时候,它们却那么费解。

问题1,过度复杂的心智模型

为了理解当你间隔一段时间返回到你的代码、却发现代码难以理解的第一步,就是理解我们如何从心智上建立问题模型。你写的几乎所有代码都是尽量解决现实世界的问题。在你写代码之前,你需要理解你正试图解决的问题。这常常是编程里最难的一步。

为了解决现实世界的问题,我们首先需要形成该问题的心智模型【注1】,以此作为编程意图。接下来你需要形成实现编程意图的方案模型,我们姑且称为语义模型(semantic model)。从来不要混淆你的编程意图和此意图的方案。我们倾向于主要考虑方案方面的东东,而常常忽略意图的模型。

你接下来的步骤是形成可能最简单的语义模型。这是容易搞错的第二步。如果你不花时间去真正理解你正试图解决的问题,你将在写代码时被绊倒在模型上。另一方面,如果你真正考虑了你正尽量做的事情,你经常得到一个非常简单的模型,这足以让你掌握最初的意图。

如果你想容易地维护简单的代码,就尽可能多些地消除意外的复杂性。我们正试图解决的问题是足够复杂的。如果你不必那么做,就不要把意外的复杂性增加进来。

问题2,语义模型到代码的糟糕转化

一旦你尽全力形成了最好的语义模型,那么就到了把它转化为代码的时候了。我们称之为句法模型(syntactic model)。你正试图把你的语义模型的意义转化为计算机能够理解的句法。

如果你有非常不错的语义模型、而在转化为代码时搞砸了,那么在你需要在以后某个阶段回头修改代码时,你将比较痛苦。当你脑子里还有语义模型时,把你代码映射到语义模型是容易的。回忆起变量“x”实际上代表一条记录被创建的日期、而“y”代码记录被删除的日期,这是不难的。当你3个月后再回来看代码,你的脑子里将没有这个语义模型了,因此无法理解同样的变量名字。

把语义模型转化为句法的任务就是尽量多地留下线索,让你在今后返回时,能够重建当初的语义模型。

好了,你该怎么做呢?

类结构和命名

...

当心隔阂

译者注:原文第一段貌似有重复的语句,我理解不够,略去。

一周前,我收到了第一个被打回的补丁。拒绝原因不是“哦,我们将需要一些修改”;我们正在实际地讨论,“我们不想要这段代码”而当场拒绝。啊。

这个补丁为OpenStack的队列服务Zaqar做的,它在一个基类修改了__getattr__,以允许淘汰子类的相似方法。不是多大的事情,但是这些方法是不同的、足以让它显得不同寻常;还有这事我第一次与OpenStack协作,也是我尝试的第一个bug,它没有明显地标记为“容易”、或适合初学者。

伙计,当我搞定这玩意儿时,我感觉良好吗。减少了100行代码,伙计!当irc上有人称赞我的工作“令人印象深刻”时,我没有反对。哦,是的,我是一名OpenStack开发者。你懂的,令人印象深刻的开发者?

但是……只是有点儿难以读懂。

尽管如此,这不是我的问题。我的意思是,他们想要,我就给了他们,因此我算帮了他们一个忙,好嘛?他们知道他们在干什么。在代码评审过程我加了足够多的评论,让它易于理解。

就在它将要被合并的时候,另一名开发者跳出来说了一些我一直感到不安的话。这是复杂的代码,它很神奇,将来看到这些类(class)的人将浪费很多脑细胞才能理解,这本应是简单的,如果它需要被修改的话……他很圆滑,但是消息是清晰的。经过irc来来回回的沟通,他们觉得没有必要打这个补丁。

这不太容易听懂。然而,我有些轻松了。我知道我的技能还需要锻炼,但是我对爱好有信心,当看到有经验的开发者对代码感到激动时,它让我嗅出了一点点爱好,我受到了一点儿震动。它是对我工作的拒绝,也是对我爱好的验证。

这是我态度上巨大的转变。在不远的将来,我将崩溃。

我猜,我将给还在那条船上的人讲这个故事。博客不是日记,它们是蓄意的、专业的演示,你的RSS feed无休止的成功信息流就是这种体现。他们标红的每个成功,都有20个没有记录下来的失败(很可能有一两个灾难)。这就给你一个印象:你是唯一在奋斗的人。

或许在不远的将来,我就首次为OpenStack贡献代码的事情写篇欢快的博文。我不会为此道歉,但是我将链接回这篇博文。

如果自信对你而言是一种奋斗,请看看我链接的这幅漫画(中文版),然后以你的爱好为荣吧。

原文地址:http://rose.github.io/posts/in-which-i-mind-the-gap/