我须要定义出 tao 语言的细节,在此,须要引出文法这一律念。所谓文法,便是用于描述语言的一种工具。
例如,一个赋值语句可能写成以下形式:工具
variable = 1 + 3递归
如何充分定义这个赋值语句的形式呢?若用天然语言描述,我能够说,赋值语句最左边是一个标示符,而后紧接一个“=”符号,而后再接一个表达式。知足这个条件的,便是赋值语句啦。语法
S → abE语言
用符号来描述的话,就是如上形式,这种形式称之为 S 的产生式。其中 S 表示赋值语句,a 表示一个标示符,b 是“=”符号,E 表示表达式。这里用到了S、a、b、E 四个不一样的字母。源代码
等等,彷佛还有什么没说完,由于标示符(字母a表示)与“=”符号(字母b表示)都与 Tokenizer 生成的 Token 对应,可是表达式(字母E表示)却没有对应的 Token 呀。block
因而,我还要进一步描述表达式。这里为了避免让问题变得过于繁琐,我先假定表达式只出现加减号和数字。那么表达式的定义以下。数字
E → d | E+d | E-d生成
这里出现的“|”表示“或”,这代表表达式(字母E)能够展开成三种不一样的式子。同时,E 展开后的式子中可能再次出现 E 自己,这种递归形式足以涵盖任意长度的表达式形式。index
因而,咱们又获得字母 d,d 表示一个数字(也与某种 Token 对应)。ab
至此,咱们一共获得了 S、a、b、E、d 五个不一样的字母,其中 a、b、d 都与 Token 对应。然而,虽然 S、E 却没有对应的 Token,但它们都有至少有一个属于本身的产生式。
对于 a、b、d,称之为终结符。即它们不会再有本身的产生式了。而 S、E,称之为非终结符。
当咱们为式子中某个非终结符挑选一个特定的产生式,并用产生式的右边部分代替这个非终结符在式子中的位置,那么咱们将这个过程称之为非终结符的展开。
考虑下面这行代码:
index = 15 + 7 - 3
其形如 abd+d-d(a 为 "index"、b 为"="、d 为"15", "7", "3")
对于 S 有以下展开方式:
S → abE
→ abE-d(展开 E → E-d)
→ abE+d-d(展开 E → E+d)
→ abd+d-d(展开 E → d)
其中 S 表示一个赋值语句。既然 S 存在某种展开方式,其形式与这行代码彻底相同,咱们说,这行代码与 S 是匹配的。对于 Parser 而言,便可判定这行语句是一个赋值语句。
所以,Parser 读取语言的文法定义。而后,经过找到一个展开方案以匹配源代码。而这个展开方案中对各个非终结符产生式的选择过程,便是对源代码中每个部分的定性过程。这个过程让 Parser 可以理解源代码各个部分表示的含义,并以今生成对应的语法树(Syntax Tree)。