我实在是不怎么能写博客。。。就当Coursera课程的笔记了。
parsing是继lexical analysis之后的第二个内容,在我们完成了Lexical analysis之后,我们需要将输入的token对组成一个Parse Tree,为后来的语义分析做准备。那么Parsing到底有哪些内容呢?
Context Free Grammar,Derviation, Recursive Decent Algorithm, Bottom-up Parsing等等,我们一个一个看。
一: Context Free Grammar 又叫 CFG, 根据 CFG的定义,它包含以下几个方面:
{
a set of terminals;
a set of non-terminals;
a start symbol (non-terminals);
a set of production (can be anything);
}
先解释以下terminal 和non-terminal的问题,terminal是parsing中的最后单元,它不能被解释成其它东西了,好比说数字 int(我们不关心int的具体值),操作符(*+-/),关键字。而non-terminal是一种抽象的标号,它可以被解释成terminal或者non-terminal。看一个例子:
E -> E + E | E - E | E * E | E / E | int | epsilon
这句话的意思就是 E可以被解释成以下集中形式 E + E, E - E ..., 其中包括 int这样的 terminal还有一个特殊的符号 epsilon(它表示空)。 值得注意的是这种解释方法和Regular Expr很相近,其中的 '|' 和 Regular Expr 当中的 '|' 有相同的作用,“可以将E替换成右边的任何一种 production”。
总结以下,对CFG的操作:
1:从 Start Symbol开始(通常叫S);
2:将左边的任何一个non-terminal 替换为Production;
3:重复第二步知道没有全部都为terminal位置;
顺便我们可以定义CFG的 语言 L(G): 所有可以被G规则解释出来的字符串,我们就认为它在G的语言中(In the language of G)。
不幸的是,识别两种Grammar是否相同是一种non-trival的工作。由于很多时候你不能穷举所有在Language中的String,所以我们只能取写出一个足够好的Grammar,让它识别String是否在L(G)中。
二:Derviation:这是我们得到Parse Tree的方法。
一般构建的方法有两种,left most 和 right most, 它们是指我们要从当前的Production中的最左边的non-terminal开始还是从最右边的开始,该non-terminal可以被展开为Grammar当中的任何一种规则。
由于之前的CFG只能告诉我们一个string是否在L(G)中,我们确实需要一种方法来构建Parse树,还是举个例子:
假设我们的CFG为 "E -> E + E | E * E | (E) | id", 要匹配的string是 id * id + id, 则我们可以这样构建
E E
-> E + E / \
-> E * E + E E + E
-> id * E + E / \ |
-> id * id + E E * E id
-> id * id + id | |
id id
同时我们又可以这么构建:
E E
-> E * E / \
-> E * E + E E * E
-> id * E + E | / \
-> id * id + E id E + E
-> id * id + id | |
id id
这样就带了了ambiguity, and ambiguity is BAD! 下一篇我们在讨论ambiguity