我不知道LZ实在学习C语言还是在学习编译原理;
这个程序是使用递归下降的方法实现的表达式求解;也就是说语法分析时,将一个文本看作一个字符串流,通过扫描器每次取一个单词(token),与期望的文法中,产生式产生的单词是否匹配,将匹配点作为语法树的一个节点,当然在分析的同时可以进行语法树的修饰,也就是语义分析,为了以后正确得到这个字符串所需要告诉我们的信息。
最近我正好在写脚本编译器,举个简单的例子,关于如何获得token是扫描器事情,对于一种给定的语言如何识别,如何提取token,需要创建DFA之类的问题,希望LZ能去看看编译原理的书。
我这里个一个例子是如何获得一个实数,文法如下
DECIMAL --> SIGN UINT PRECISION EXPONENT
SIGN --> +|-|epsilon
UINT --> DIGIT DIGIT*
DIGIT --> [0-9]
PRECISION --> . UINT | epsilon
EXPONENT --> (e|E) SIGN UINT
epsilon表示空字(即什么都没有),其中符号|表示选择,比如SIGN --> +|-|epsilon,也就是说对于产生式SIGN可以生成+或-或者什么都不生成都是合法的,反之对产生式SIGN来说,其它符号都是不合法的,即语法错误;*是Kleene closure(闭包),DIGIT*表示可以重复从[0-9]这些字符中选择若干个,组成一个字符串,也就是说每一次循环选择一个字符,然后扩展字符串长度,重复这一过程;*的另一层涵义可以什么都不产生,即空字;
下面我们看看,对于-123.45e-6是怎样通过这个产生式产生的,并建立一棵语法书,首先无条件创建树根;
DECIMAL
* * * *
SIGN UINT PRECISION EXPOENT
[-] * * * * * *
DIGIT [.] UINT [e] SIGN UINT
[1] * [-] *
* DIGIT DIGIT
DIGIT [4] [6]
[2] *
* DIGIT
DIGIT [5]
[3]
其中大写单词表示产生式,[]表示数据,这些数据挂在树的不同节点上,是根据产生式调用的次序获得的;而这些数据决定了这个树将得出什么结果,也就是说如何从叶结点逐级向上传递结果,使得根的结果是一个浮点数-123.45e-6而不是一个字符串。
这就牵涉到如何修饰语法树了,这里我不详细说明,因为这个不是一段两段文字能说得清楚的,详细请学习编译原理。
我们都在命运湖上荡舟划桨,波浪起伏使我们无法逃离孤行;如果我们迷失方向,波浪将指引我们穿过另一天曙光