详解递归下降分析法

详解递归下降分析法通过一个具体的例子来学习递归下降分析法 假设有文法 E gt TE E gt TE TE T gt FT T gt FT FT F gt E i 现在希望用递归下降的方式写一个能识别这种语言的 parser 首先我们去求非终结符的 FIRST 和 FOLLOW 集合 如下 nbsp nbsp FIRST

通过一个具体的例子来学习递归下降分析法。

假设有文法:

E -> TE` E` -> +TE` | -TE` | ε T -> FT` T` -> *FT` | /FT` | ε F -> (E) | i

现在希望用递归下降的方式写一个能识别这种语言的parser。

首先我们去求非终结符的FIRST和FOLLOW集合,如下: 

  FIRST FOLLOW
E ( i  )
E` + – ε )
T ( i + – )
T` * / ε + – )
F ( i * / + – )

在有的书里(比如虎书),ε是单独算在Nullable集合中的,此处为了方便,我们把它算到FIRST中,这并不影响什么。根据上面的表格,就可以来构造递归下降分析表了,构造的方法是:

对于规则A -> a,如果FIRST(a)不含ε,则在所有的(A,FIRST(a))处写上这条规则;如果含ε,还要在(A,FOLLOW(A))处补上这条规则。

举两个例子来说:

  1. 对于规则E` -> +TE`,显然FIRST(+TE`)={+},不含ε,所以只需要在(E`, +)处写上这条规则。
  2. 对于规则E` -> ε,FIRST(ε)=ε,因为FOLLOW(E`)={)},所以要在(E`,))处写上这条规则。

OK,我们如法炮制,可以得到如下的分析预测表:

  + * / ( ) i
E         E -> TE` E -> TE`  
E` E` -> +TE` E` -> +TE`       E` -> ε  
T         T -> FT`   T -> FT`
T` T` -> ε T` -> ε T` -> *FT` T` -> *FT`   T` -> ε  
F         F -> (E)   F -> i

然后根据这个表就可以写代码了:

#include 
  
    #include 
   
     using namespace std; const int pos = 0; string s = "i+(((((i*i*i*(i+i+(i/i))+i/i)))))$"; void eat(); void error(); void E(); void Eprime(); void T(); void Tprime(); void F(); void eat(){ s = s.substr(1); } void error(){ cout << "failed to match!" << endl; exit(1); } void E(){ switch(s[pos]){ case '$': break; case '(': case 'i': T(); Eprime(); break; default: error(); } } void Eprime() { switch(s[pos]){ case '$': break; case '+': case '-': eat(); T(); Eprime(); break; case ')': break; default: error(); } } void T() { switch(s[pos]){ case '$': break; case '(': case 'i': F(); Tprime(); break; default: error(); } } void Tprime() { switch(s[pos]){ case '$': break; case '+': case '-': case ')': break; case '*': case '/': eat(); F(); Tprime(); break; default: error(); } } void F() { switch(s[pos]){ case '$': break; case '(': eat(); E(); if(s[pos]==')') {eat(); break;} else error(); break; case 'i': eat(); break; default: error(); } } int main() { E(); cout << "finally s is " << s << endl; cout << "accepted!" < 
     
    
  

可以看到,每个非终结符就对应了一个函数,分析预测表中的每个entry就对应了函数中的一个case,非常清晰易懂。

Perfect!就写到这里吧。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214452.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午4:13
下一篇 2026年3月18日 下午4:14


相关推荐

  • 轻松学习RSA加密算法原理「建议收藏」

    轻松学习RSA加密算法原理「建议收藏」http://blog.csdn.net/q376420785/article/details/8557266http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html以前也接触过RSA加密算法,感觉这个东西太神秘了,是数学家的事,和我无关。但是,看了很多关于RSA加密算法原理的资料之后,我发现其

    2022年5月1日
    36
  • PEID Autism专版绿色版

    PEID Autism专版绿色版名称 PEIDAutism 专版绿色版版本 1 0 软件大小 609KB 软件语言 简体中文软件授权 免费版应用平台 Win7 Vista Win2003 WinXPPEiD 是一款著名的查壳工具 其功能强大 现在有软件很多都加了壳 给激活成功教程汉化带来非常大的不便 PEiD 几乎可以侦测出所有的壳 其数量已超过 470 种 PE 文档的加壳类型和签名 另外还可识别出 EXE 文件是用什么

    2026年3月19日
    2
  • 1.3 构建简单的用户界面

    1.3 构建简单的用户界面

    2022年3月4日
    53
  • Python标识符的命名规则,下列哪些是对的?_python标识符不能使用关键字

    Python标识符的命名规则,下列哪些是对的?_python标识符不能使用关键字[快速理解]Python标识符是指变量、函数、类、模块等的名称。例如:a=10中的a是标识符反例:foriin[1,2,3]中的for和in不是标识符,是保留字,i是标识符。Python保留字有特殊的语法功能。选择题以下选项中都可以作为Python标识符的是:选项:A_py99pyBcueba_intCandChinaDstr1else问题解析Python标识符的命名规则:1.标识符的第一个字符必须是字母、下划线,其后的字符可以是字…

    2025年10月12日
    5
  • c++map set_get post区别

    c++map set_get post区别setset的数据结构set的操作函数erasefindcount重载操作符multisetmapmap的数据结构map的构造函数map的操作函数erasecleanfind重载运算符其他操作函数multimap)setset是一种关联式容器,其特性如下:set以RBTree作为底层容器所得元素的只有key没有value,value就是key不允许出现键值重复所有的元素都会被自动排…

    2025年9月26日
    7
  • Windows Mobile 6.0 SDK和中文模拟器下载

    Windows Mobile 6.0 SDK和中文模拟器下载

    2021年11月29日
    70

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号