关于编译原理——递归下降分析器的设计

学习目标:根据文法编制递归下降分析程序,以便对输入的符号串进行语法分析。通过编写递归下降分析程序掌握递归下降分析法的基本原理以及递归下降分析程序的构造方法。


1.分析原理

①E->TE'

②E'->+TE' | ---TE' |ε

③T->FT'

④T'->*FT' | /FT' |ε

⑤F->(E) | id | num

注:文法中id表示标识符(此处标识符的定义与实验一中标识符的定义相同),num表示数字(简单处理可以认为是整数)

2.具体案例分析

输入一个字符串,输出该字符串是否为正确的句子。

例如:输入a+xyz*10+(c/d),输出"正确的表达式"

输入a+*xyz,输出"错误的表达式"

3.设计思路

可以将整个系统分为主函数、解析函数以及辅助函数三个模块:

①主函数模块:main,负责读取输入表达式并调用解析函数。

②解析函数模块:parse_expression、parse_E、parse_E_prime、parse_T、parse_T_prime、parse_F,分别对应文法中的非终结符号。

③辅助函数模块:skip_whitespace、match、is_id_char、is_num_char,用于处理空白字符、字符匹配、判断标识符字符和数字字符。

4.模块关系简图

5.函数接口

①主函数:int main(void)

功能:读取输入表达式,调用解析函数,输出解析结果。

②解析函数:bool parse_F(void)、bool parse_T_prime(void)、bool parse_T(void)、bool parse_E_prime(void)、bool parse_E(void)、bool parse_expression(void)

参数:无

返回值:解析成功返回true,失败返回false。

③辅助函数:void skip_whitespace(void)、bool match(char expected)、bool is_id_char(char c)、bool is_num_char(char c)

参数:根据函数功能而定。

返回值:根据函数功能而定。

6.测试方案及结果

①测试方案:样例表达式a+xyz*10+(c/d)

②测试方案:样例表达式a+*xyz

7.优缺点分析

优点:实现简单直观,易于理解和调试,不需要复杂的表格结构;对语法错误的处理比较灵活。

缺点:只能处理LL(k)文法,特别是LL(1)文法;需要手动处理左递归和左公因子;递归调用可能导致栈溢出等等。

8.学习小结

在本次设计中,我通过编写递归下降分析程序,掌握递归下降分析法的基本原理以及递归下降分析程序的构造方法,不仅提升了我的编程和调试能力,让我掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法,体现了编译原理中"分治"和"递归"的核心思想,也让我对编译器的工作原理有了更深入的认识,为后续学习打下了坚实基础。

附录:主要方法的源代码

复制代码
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
 
 // 函数原型声明
bool parse_F(void);
bool parse_T_prime(void);
bool parse_T(void);
bool parse_E_prime(void);
bool parse_E(void);
bool parse_expression(void);

// 定义输入字符串的最大长度
#define MAX_INPUT_LENGTH 1024
 
// 当前解析的索引
int current_index = 0;
 
// 输入字符串
char input_str[MAX_INPUT_LENGTH];
 
// 判断是否为标识符(简单处理,只包含字母和下划线,以字母开头)
bool is_id_char(char c) {
    return isalpha(c) || c == '_';
}
 
// 判断是否为数字(简单处理,只处理整数)
bool is_num_char(char c) {
    return isdigit(c);
}
 
// 跳过空白字符
void skip_whitespace() {
    while (current_index < strlen(input_str) && isspace(input_str[current_index])) {
        current_index++;
    }
}
 
// 匹配并消耗一个字符
bool match(char expected) {
    if (current_index < strlen(input_str) && input_str[current_index] == expected) {
        current_index++;
        return true;
    }
    return false;
}
 
// 解析因子 F
bool parse_F() {
    skip_whitespace();
    if (match('(')) {
        if (!parse_E()) {
            return false;
        }
        if (!match(')')) {
            fprintf(stderr, "表达式错误:缺少闭合括号 ')' 在位置 %d\n", current_index);
            return false;
        }
        return true;
    } else if (is_id_char(input_str[current_index])) {
        while (current_index < strlen(input_str) && (is_id_char(input_str[current_index]) || isdigit(input_str[current_index]))) {
            current_index++;
        }
        return true;
    } else if (is_num_char(input_str[current_index])) {
        while (current_index < strlen(input_str) && is_num_char(input_str[current_index])) {
            current_index++;
        }
         //可以扩展为支持浮点数,这里仅处理整数
         if (match('.')) {
             while (current_index < strlen(input_str) && is_num_char(input_str[current_index])) {
                 current_index++;
             }
         }
        return true;
    } else {
        fprintf(stderr, "表达式错误:无效的因子 在位置 %d\n", current_index);
        return false;
    }
}
 
// 解析 T'
bool parse_T_prime() {
    skip_whitespace();
    if (match('*')) {
        if (!parse_F()) {
            return false;
        }
        return parse_T_prime() || true; // 递归或 ε
    } else if (match('/')) {
        if (!parse_F()) {
            return false;
        }
        return parse_T_prime() || true; // 递归或 ε
    } else {
        return true; // ε
    }
}
 
// 解析 T
bool parse_T() {
    if (!parse_F()) {
        return false;
    }
    return parse_T_prime();
}
 
// 解析 E'
bool parse_E_prime() {
    skip_whitespace();
    if (match('+')) {
        if (!parse_T()) {
            return false;
        }
        return parse_E_prime() || true; // 递归或 ε
    } else if (match('-')) {
        if (!parse_T()) {
            return false;
        }
        return parse_E_prime() || true; // 递归或 ε
    } else {
        return true; // ε
    }
}
 
// 解析 E
bool parse_E() {0
    if (!parse_T()) {
        return false;
    }
    return parse_E_prime();
}
 
// 主解析函数
bool parse_expression() {
    current_index = 0;
    return parse_E();
}
 
int main() {
    printf("请输入算术表达式:");
    fgets(input_str, MAX_INPUT_LENGTH, stdin);
    
    // 移除换行符
    input_str[strcspn(input_str, "\n")] = 0;
    
    if (parse_expression()) {
        printf("正确的表达式\n");
    } else {
        printf("错误的表达式\n");
    }
    
    return 0;
}
相关推荐
Gauss松鼠会几秒前
openGauss新特性 | 自动参数化执行计划缓存
java·数据库·spring·缓存·性能优化·database
martian6654 分钟前
C++算法优化实战:破解性能瓶颈,提升程序效率
开发语言·c++·性能优化
ytz02087 分钟前
讲解贪心算法
算法·贪心算法
努力的搬砖人.9 分钟前
搭建一个Spring Boot聚合项目
java·spring boot·后端
有什么东东21 分钟前
山东大学软件学院创新项目实训开发日志(12)之将对话记录保存到数据库中
java·数据库·vue·springboot
Seven9739 分钟前
ZooKeeper实现分布式锁
java·zookeeper
小鱼人爱编程43 分钟前
糟糕,又得重新认识上古技术--Servlet/JSP
java·前端·后端
东方醴歌44 分钟前
本地Docker部署开源AI功能笔记Blinko并实现跨网络环境远程使用
开发语言·后端·golang
xiezhr1 小时前
SpringBoot3整合SpringSecurity6(一)快速入门
java·spring boot·spring