0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

自顶向下的语法分析器—采用递归下降方法

冬至子 来源:赵同学的代码时间 作者:Jun. 2023-05-23 11:24 次阅读

在之前已经通过手写的方式实现了一个词法分析器,现在,我将利用之前手写的词法分析器,使用递归下降的方式,实现一个简单的语法分析器。

首先看看实验要求:

递归下降法编写一个语法分析程序,使之与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。

为减轻实验编程负担,这里只要求实现部分产生式,文法的开始符号为 program

图片

第一步,消除左递归。观察上面各个产生式,出现左递归的地方有expr和term。

图片

针对以上式子,首先提取左因子:

图片

消除左递归:

图片

观察到 在if语句处也存在左公因子,一并提取,最终文法定义为:

图片

定义好文法后,考虑词法分析与语法分析的接口,由于采用递归下降的分析过程中,存在对token的回溯操作,因此,每次逐个获取词法单元并不容易实现,考虑将token对应的标志和内容使用pair的数组保存下来。

pair<int, string> tokens[10000];
int cursor_;
int tokens_size_;

并使用cursor_记录当前准备分析的位置,通过移动cursor_实现对token串的回溯过程。然后根据每一条语句,写出对应的梯度下降递归函数,就可以完成本实验,使用yylex自动生成的方法也类似,只需要维护tokens数组即可。

// 工具函数:获得一个向前看,但并不移动指针
pair<int, string> get_ahead(){
    return tokens[cursor_];
}


// 工具函数:尝试匹配一个类型,匹配返回真
bool match(int type){
    if(cursor_ >= tokens_size_) return false;
    if(tokens[cursor_].first == type)
    {
        cursor_ ++;
        return true;
    }
    return false;
}


// 工具函数:尝试匹配一个类型和字符串,都匹配返回真
bool match(int type, string target){
    if(tokens[cursor_].first == type && tokens[cursor_].second == target)
    {
        cursor_ ++;
        return true;
    }
    return false;
}


bool factor(){
    cout << "Try to match factor" << endl;
    if(match(IDENTITY)) return true;
    if(match(DIGIT)) return true;
    return match(SYMBOL, "(") && expr() && match(SYMBOL, ")");
}


bool B3(){
    cout << "Try to match B3" << endl;
    return match(SYMBOL, "%") && factor();
}


bool B2(){
    cout << "Try to match B2" << endl;
    return match(SYMBOL, "/") && factor();
}


bool B1(){
    cout << "Try to match B1" << endl;
    return match(SYMBOL, "*") && factor();
}


bool B(){
    cout << "Try to match B" << endl;
    int backup_cursor = cursor_;
    if(B1()) return true;
    cursor_ = backup_cursor;
    if(B2()) return true;
    cursor_ = backup_cursor;
    if(B3()) return true;
    cursor_ = backup_cursor;
    return false;
}


bool D(){
    cout << "Try to match D" << endl;
    pair<int, string> ahead = get_ahead();
    if(ahead.first == SYMBOL && (ahead.second == "*" || ahead.second == "/" || ahead.second == "%")) return B() && D();
    return true;
}


bool term(){
    cout << "Try to match term" << endl;
    return factor() && D();
}


bool A2(){
    cout << "Try to match A2" << endl;
    return match(SYMBOL, "-") && term();
}


bool A1(){
    cout << "Try to match A1" << endl;
    return match(SYMBOL, "+") && term();
}


bool A(){
    cout << "Try to match A" << endl;
    int backup_cursor = cursor_;
    if(A1()) return true;
    cursor_ = backup_cursor;
    if(A2()) return true;
    cursor_ = backup_cursor;
    return false;
}


bool C(){
    cout << "Try to match C" << endl;
    pair<int, string> ahead = get_ahead();
    if(ahead.first == SYMBOL && (ahead.second == "+" || ahead.second == "-")) return A() && C();
    return true;
}


bool expr(){
    cout << "Try to match expr" << endl;
    return term() && C();
}


bool F(){
    cout << "Try to match F" << endl;
    pair<int, string> ahead = get_ahead();
    if(ahead.first == RELOP) return match(RELOP) && expr();
    return true;
}


bool bool_(){
    cout << "Try to match bool" << endl;
    return expr() && F();
}


bool E(){
    cout << "Try to match E" << endl;
    pair<int, string> ahead = get_ahead();
    if(ahead.first == KEYWORD && ahead.second == "else") return match(KEYWORD, "else") && stmt();
    return true;
}


bool stmt6(){
    cout << "Try to match stmt choice 6" << endl;
    return block();
}


bool stmt5(){
    cout << "Try to match stmt choice 5" << endl;
    return match(KEYWORD, "break") && match(SYMBOL, ";");
}


bool stmt4(){
    cout << "Try to match stmt choice 4" << endl;
    return match(KEYWORD, "do") && stmt() && match(KEYWORD, "while") && match(SYMBOL, "(") && bool_() && match(SYMBOL, ")") && match(SYMBOL, ";");
}


bool stmt3(){
    cout << "Try to match stmt choice 3" << endl;
    return match(KEYWORD, "while") && match(SYMBOL, "(") && bool_() && match(SYMBOL, ")") && stmt();
}


bool stmt2(){
    cout << "Try to match stmt choice 2" << endl;
    return match(KEYWORD, "if") && match(SYMBOL, "(") && bool_() && match(SYMBOL, ")") && stmt() && E();
}


bool stmt1(){
    cout << "Try to match stmt choice 1" << endl;
    return match(IDENTITY) && match(SYMBOL, "=") && expr() && match(SYMBOL, ";");
}


bool stmt(){
    cout << "Try to match stmt" << endl;
    int backup_cursor = cursor_; // 指针的回溯
    if(stmt1()) return true;
    cursor_ = backup_cursor;
    if(stmt2()) return true;
    cursor_ = backup_cursor;
    if(stmt3()) return true;
    cursor_ = backup_cursor;
    if(stmt4()) return true;
    cursor_ = backup_cursor;
    if(stmt5()) return true;
    cursor_ = backup_cursor;
    if(stmt6()) return true;
    cursor_ = backup_cursor;
    return false;
}


bool stmts(){
    cout << "Try to match stmts" << endl;
    pair<int, string> ahead = get_ahead();
    if(ahead.first == SYMBOL && ahead.second == "}") return true;
    else return stmt() && stmts();
}


bool block(){
    cout << "Try to match block" << endl;
    return match(SYMBOL, "{") && stmts() && match(SYMBOL, "}");
}


bool program(){
    cout << "Try to match program" << endl;
    return block();
}

由于已经高度模块化,main函数很简单:

int main()
{
    if(!DFA()) return 0; // 词法分析
    tokens_size_ = cursor_; 
    cursor_ = 0; // 初始化指针
    if(program()) cout << "ACCEPT !" << endl;
    else cout << "ERROR !" << endl;
}

测试:

使用实验指导代码测试:

input:
{
i = 2;
   sum = 0;
     while (i <=100)   {
          sum = sum + i;
       i = i + 2;
          if(i%5==0) break;
     }
}


output:
SYMBOL : {
i = 2;
IDENTITY : i
SYMBOL : =
DIGIT : 2
SYMBOL : ;
   sum = 0;
IDENTITY : sum
SYMBOL : =
DIGIT : 0
SYMBOL : ;
KEYWORD : while
SYMBOL : (
IDENTITY : i
RELOP : <=
DIGIT : 100
SYMBOL : )
SYMBOL : {
IDENTITY : sum
SYMBOL : =
IDENTITY : sum
SYMBOL : +
IDENTITY : i
SYMBOL : ;
IDENTITY : i
SYMBOL : =
IDENTITY : i
SYMBOL : +
DIGIT : 2
SYMBOL : ;
KEYWORD : if
SYMBOL : (
IDENTITY : i
SYMBOL : %
DIGIT : 5
RELOP : ==
DIGIT : 0
SYMBOL : )
KEYWORD : break
SYMBOL : ;
SYMBOL : }
SYMBOL : }
Try to match program
Try to match block
Try to match stmts
Try to match stmt
Try to match stmt choice 1
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match stmts
Try to match stmt
Try to match stmt choice 1
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match stmts
Try to match stmt
Try to match stmt choice 1
Try to match stmt choice 2
Try to match stmt choice 3
Try to match bool
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match F
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match stmt
Try to match stmt choice 1
Try to match stmt choice 2
Try to match stmt choice 3
Try to match stmt choice 4
Try to match stmt choice 5
Try to match stmt choice 6
Try to match block
Try to match stmts
Try to match stmt
Try to match stmt choice 1
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match A
Try to match A1
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match stmts
Try to match stmt
Try to match stmt choice 1
Try to match expr
Try to match term
Try to match factor
Try to match D
Try to match C
Try to match A
Try to match A1
Try to match term
Try to match factor
Try to match D
Try to match E
Try to match stmts
Try to match stmts
ACCEPT !

最后发现梯度递归函数已经成功地接受了我们的输入。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 分析器
    +关注

    关注

    0

    文章

    92

    浏览量

    12486
收藏 人收藏

    评论

    相关推荐

    [4.1.1]--向下语法分析及其面临的问题

    编译原理
    jf_60701476
    发布于 :2022年12月27日 11:27:59

    基于向下技术的工程机械Digital Prototyping设计方法及应用

    【作者】:刘雪冬【来源】:《华南理工大学》2009年【摘要】:向下的设计方法及装配建模技术是在消费品行业应用比较成熟的一种设计方法和理论
    发表于 04-24 09:20

    postgreSQL命令的词法分析语法分析

    PostgreSQL查询SQL的语法分析(1)——词法分析
    发表于 05-16 16:33

    如何实现扩频通信调制向下的设计?

    如何实现扩频通信调制向下的设计?如何实现扩频通信调制的仿真测试?
    发表于 04-29 06:46

    一个高效的语法分析器生成工具

    VPGE(Visual Parser Generation Environment)是一个可视化语法分析器集成开发环境,除了具有良好的界面和强大的调试功能,其LALR(1)分析器的生成速度达到并超过公认的分析器生成速度最快
    发表于 08-29 10:04 16次下载

    YACC在ATLAS语言语法分析中的冲突消解研究

    对使用YACC工具进行ATLAS语言语法分析过程中出现的大量冲突进行了详细的分类讨论与研究,给出了实现过程中出现的主要冲突类型及相应解决方案:文法符号的不断自身循环产生
    发表于 09-08 15:30 0次下载

    网络分析器,网络分析器原理是什么?

    网络分析器,网络分析器原理是什么? 网络分析器   具有发现并解决各种故障特性的硬件或软件设备
    发表于 03-22 11:25 1044次阅读

    编译原理实践环节模拟试题

    1.为以下文法构造递归下降语法分析程序,并能对输入串进行语法分析。 S aBc|bAB A aAb|b B b 2.试写出简单的词法分析程序
    发表于 04-11 22:19 24次下载

    借助Lex和Yacc进行词法语法分析

    实验目的: 1.通过对实验型程序设计语言C1的定义,掌握程序设计语言的基本语法和语义; 2.使用Lex及Yacc实现词法分析语法分析
    发表于 04-18 23:04 30次下载

    交换机端口分析器

    本文将重点介绍“交换端口分析器(SPAN)”的工作原理及配置方法
    发表于 02-03 14:09 994次阅读

    通过模块之间的调用实现向下的设计

    通过模块之间的调用实现向下的设计目的:学习状态机的嵌套使用实现层次化、结构化设计。
    发表于 02-11 05:53 2440次阅读
    通过模块之间的调用实现<b class='flag-5'>自</b><b class='flag-5'>顶</b><b class='flag-5'>向下</b>的设计

    EDA设计一般采用向下的模块化设计方法

    三方面的电子设计工作,即集成电路设计、电子电路设计以及PCB设计。总之,EDA技术的基本特征是采用具有系统仿真和综合能力的高级语言描述。它一般采用
    发表于 01-21 16:50 9012次阅读
    EDA设计一般<b class='flag-5'>采用</b><b class='flag-5'>自</b><b class='flag-5'>顶</b><b class='flag-5'>向下</b>的模块化设计<b class='flag-5'>方法</b>

    开源L2C编译前端语法分析器及验证过程

    Jourdan等在其2012年发表的论文“ Validating Lr(1) Parsers”中提出了一种形式化验证语法分析器方法,并将其成功地应用于 Compcert编译(2.3以上版本
    发表于 05-19 10:55 5次下载

    计算机网络:向下

    本文档包含Jim Kurose和Keith Ross编写的《计算机网络:向下方法(第7版)》复习题和问题的参考答案。这些答案只对指导老师有效。请不要复制或者分发给其他人(即使是其他指导老师)。请
    发表于 03-13 14:23 0次下载

    eda向下的设计方法 eda自顶向下设计优点

    EDA(Electronic Design Automation,电子设计自动化)向下的设计方法是一种常见的电子电路设计方法。该
    发表于 04-10 16:49 3745次阅读