August 2021
Intermediate to advanced
450 pages
9h 36m
Chinese
诗云:不识庐山真面目,只缘身在此山中。类似地,如果我们只关心一个程序中的函数、类等的细节,就容易失去对程序的整体把握。因此,下面就忽略细节,看看程序的结构:
在这里,声明的顺序是很重要的,一个名字在被声明之前是不能使用的,因此ts必须在ts.get()使用之前声明,error()必须在语法分析函数之前声明。在调用图中有一个非常有趣的循环:expression()调用term(),term()调用primary(),primary()又调用了expression()。
下面是调用关系的图描述(由于所有的函数都调用error(),因此将其省略):
这就意味着我们不能简单地定义这三个函数:没有任何一种顺序能满足先定义后使用的原则。因此,至少有一个函数必须先只给出声明而非定义。我们选择先声明expression()函数,这种方式称为前置声明(forward declare)。
现在的计算器程序已经能正常工作了吗?某种程度上,确实可以了。它可以正常编译、运行、正确计算表达式,并给出适当的错误信息。但它是按照我们所希望的方式工作吗?答案并不出人意料——“不全是”。6.6节给出了程序的第一个版本并消除了一个严重的错误,6.7节中的第二个版本并没有多少改进。但这没有关系,这是意料之中的。我们本来的目标就是写一个可以运行的程序,能用来验证我们的基本思路,从中获得反馈,对于这个目标来说现在的版本已经足够好了。从这个角度来说,它是成功的,但试一下:它仍然存在很多问题! ...