2016开户就送体验金
2016开户赠金100无需入金
Portraits
Journal
Contact
准备工作就到这里。现在我来谈一下,解释器到底是什么。说白了,解释器跟计算器差不多。解释器是一个函数,你输入一个“表达式”,它就输出一个 “值”,像这样:
比如,你输入表达式 '(+ 1 2) ,它就输出值,整数3。表达式是一种“表象”或者“符号”,而值却更加接近“本质”或者“意义”。解释器从符号出发,得到它的意义,这也许就是它为什么叫做“解释器”。
需要注意的是,表达式是一个数据结构,而不是一个字符串。我们用一种叫“S表达式”(S-expression)的结构来存储表达式。比如表达式 '(+ 1 2) 其实是一个链表(list),它里面的内容是三个符号(symbol):+, 1 和 2,而不是字符串"(+ 1 2)"。
从S表达式这样的“结构化数据”里提取信息,方便又可靠,而从字符串里提取信息,麻烦而且容易出错。Scheme(Lisp)语言里面大量使用结构化数据,少用字符串,这就是 Lisp 系统比 Unix 系统先进的地方之一。
从计算理论的角度讲,每个程序都是一台机器的“描述”,而解释器就是在“模拟”这台机器的运转,也就是在进行“计算”。所以从某种意义上讲,解释器就是计算的本质。当然,不同的解释器就会带来不同的计算。你可能没有想到,CPU 也是一个解释器,它专门解释执行机器语言。
抽象语法树(Abstract Syntax Tree)我们用S表达式所表示的代码,本质上是一种叫做“树”(tree)的数据结构。更具体一点,这叫做“抽象语法树”(Abstract Syntax Tree,简称 AST)。下文为了简洁,我们省略掉“抽象”两个字,就叫它“语法树”。
跟普通的树结构一样,语法树里的节点,要么是一个“叶节点”,要么是一颗“子树”。叶节点是不能再细分的“原子”,比如数字,字符串,操作符,变量名。而子树是可以再细分的“结构”,比如算术表达式,函数定义,函数调用,等等。
举个简单的例子,表达式 '(* (+ 1 2) (+ 3 4)),就对应如下的语法树结构:
其中,*,两个+,1,2,3,4 都是叶节点,而那三个红色节点,都表示子树结构:'(+ 1 2),'(+ 3 4),'(* (+ 1 2) (+ 3 4))。
树遍历算法在基础的数据结构课程里,我们都学过二叉树的遍历操作,也就是所谓先序遍历,中序遍历和后序遍历。语法树跟二叉树,其实没有很大区别,所以你也可以在它上面进行遍历。解释器的算法,就是在语法树上的一种遍历操作。由于这个渊源关系,我们先来做一个遍历二叉树的练习。做好了之后,我们就可以把这段代码扩展成一个解释器。
这个练习是这样:写出一个函数,名叫tree-sum,它对二叉树进行“求和”,把所有节点里的数加在一起,返回它们的和。举个例子,(tree-sum '((1 2) (3 4))),执行后应该返回 10。注意:这是一颗二叉树,所以不会含有长度超过2的子树,你不需要考虑像 ((1 2) (3 4 5)) 这类情况。需要考虑的例子是像这样:(1 2),(1 (2 3)), ((1 2) 3)((1 2) (3 4)),……
(为了达到最好的学习效果,你最好试一下写出这个函数再继续往下看。)
好了,希望你得到了跟我差不多的结果。我的代码是这个样子:
#lang racket
2016开户赠金100无需入金
Portraits
Journal
Contact