编译原理实验 递归下降子程序的编写

一、实验目的

通过本实验,了解递归下降预测分析的原理和过程以及可能存在的回溯问题,探讨解决方法,为预测分析表方法的学习奠定基础。分析递归下降子程序的优缺点。

二、实验准备

1.预习自上而下语法分析小节的内容;2.学生自己考虑使用的开发环境,如VC++,熟悉开发环境。

三、实验内容

下列文法中选做一题:

1.针对算术表达式文法:

	E → TE'
	E' → +TE'| ε
	T → FT'
	T' → *FT' | ε
	F → (E) | i

为其编写递归下降子程序,判定某个算术表达式是否正确:如j+k*m,j*k+m
输入:其输入数据应该为词法分析器输出的记号形式:i+i*i,i*i+i
输出:分析结果:算术表达式结构正确或结构错误。

显然这个文法属于LL(1)形文法,可以直接编写代码实现

2.给定文法(PASCAL语言标识符定义文法)(选做)

type   → simple | id | array [ simple ] of type
simple → integer | char | num dotdot num

其中:dotdot 表示 ..

编写递归下降子程序,判定一个句子结构是否正确:

array [num dotdot num] of integer

输出:分析结果

显然这个文法也属于LL(1)形文法,可以直接编写代码实现

四、实验要求

1.编写程序调试运行;考虑如果将你的程序改为识别其他的文法,你的递归下降子程序可否通用,考虑递归下降子程序方法的优缺点。

2.撰写实验报告:实验名称、实验目的、实验内容、实验结果、结果分析


1

#include <iostream>
#include <string>
#include <vector>

using namespace std;

/*
    递归下降语法分析器
    最左推导,自顶向下
*/


/// 枚举定义了我们支持的 Token 类型
enum class TokenType {
    Identifier,     // i
    Plus,           // +
    Star,           // *
    LParen,         // (
    RParen,         // )
    End             // 结束符 #
};

/// Token 类代表词法分析器输出的一个单词
struct Token {
    TokenType type;
    string text;
    // move 引用拷贝并解除原引用
    Token(TokenType type, string text) : type(type), text(move(text)) {}
};

/// 词法分析器:将原始字符串拆分成 Token 序列
class Lexer {
public:
    Lexer(const string& input) : input_(input), pos_(0) {}

    /// 执行词法分析,返回 Token 列表
    vector<Token> tokenize() {
        vector<Token> tokens;
        while (pos_ < input_.size()) {
            char ch = input_[pos_];
            if (isspace(ch)) {
                ++pos_; // 忽略空格
            } else if (ch == 'i') {
                tokens.emplace_back(TokenType::Identifier, "i");
                ++pos_;
            } else if (ch == '+') {
                tokens.emplace_back(TokenType::Plus, "+");
                ++pos_;
            } else if (ch == '*') {
                tokens.emplace_back(TokenType::Star, "*");
                ++pos_;
            } else if (ch == '(') {
                tokens.emplace_back(TokenType::LParen, "(");
                ++pos_;
            } else if (ch == ')') {
                tokens.emplace_back(TokenType::RParen, ")");
                ++pos_;
            } else {
                cerr << "未知字符: " << ch << endl;
                ++pos_;
            }
        }
        tokens.emplace_back(TokenType::End, "#"); // 表示输入结束
        return tokens;
    }

private:
    string input_;
    size_t pos_;
};

/// 语法分析器:根据 Token 序列判断语法是否正确
class Parser {
public:
    explicit Parser(const vector<Token>& tokens) : tokens_(tokens), pos_(0) {}

    /// 启动分析器,从文法的起点 E 开始
    bool parse() {
        return E() && match(TokenType::End);
    }

private:
    const vector<Token>& tokens_;
    size_t pos_;

    /// 获取当前 Token
    const Token& current() const {
        return tokens_[pos_];
    }

    /// 匹配当前 Token 是否为指定类型,并前进
    bool match(TokenType expected) {
        if (current().type == expected) {
            ++pos_;
            return true;
        }
        return false;
    }

    /// E → T E'
    bool E() {
        // cout << "Enter E" << endl;
        return T() && EPrime();
    }

    /// E' → + T E' | ε
    bool EPrime() {
        if (current().type == TokenType::Plus) {
            match(TokenType::Plus);
            return T() && EPrime();
        }
        return true; // 空产生式
    }

    /// T → F T'
    bool T() {
        return F() && TPrime();
    }

    /// T' → * F T' | ε
    bool TPrime() {
        if (current().type == TokenType::Star) {
            match(TokenType::Star);
            return F() && TPrime();
        }
        return true; // 空产生式
    }

    /// F → ( E ) | i
    bool F() {
        if (match(TokenType::Identifier)) {
            return true;
        } else if (match(TokenType::LParen)) {
            // 匹配左括号后必须是一个表达式,再跟右括号
            if (E() && match(TokenType::RParen)) {
                return true;
            } else {
                return false;
            }
        }
        return false; // 不符合任何形式
    }
};

int main() {
    // 测试表达式列表
    vector<string> tests = {
        "i+i*i",      // ✅
        "i*i+i",      // ✅
        "i+*i",       // ❌ 错误:+ 后不能跟 *
        "(i+i)*i",    // ✅
        "((i))",      // ✅
        "i+"          // ❌ 错误:+ 后缺少操作数
    };

    for (const auto& expr : tests) {
        Lexer lexer(expr);
        auto tokens = lexer.tokenize();

        Parser parser(tokens);
        cout << "测试表达式: " << expr << endl;
        if (parser.parse()) {
            cout << "✅ 表达式结构正确" << endl;
        } else {
            cout << "❌ 表达式结构错误" << endl;
        }
        cout << "-----------------------" << endl;
    }

    return 0;
}

2

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// ======================
// Token 类型定义
// ======================

/// 支持的词法单元(Token)类型
enum class TokenType {
    Identifier,   ///< 标识符(如变量名)
    Number,       ///< 数字常量
    Integer,      ///< 关键字 "integer"
    Char,         ///< 关键字 "char"
    Array,        ///< 关键字 "array"
    Of,           ///< 关键字 "of"
    LBracket,     ///< 左中括号 [
    RBracket,     ///< 右中括号 ]
    DotDot,       ///< 范围符号 ".."
    End           ///< 输入结束符 #
};

/// Token 结构:表示一个词法单元
struct Token {
    TokenType type;  ///< Token 类型
    string text;     ///< 原始文本

    Token(TokenType type, string text)
        : type(type), text(move(text)) {}  // 使用移动构造提高性能
};

// ======================
// 词法分析器:Lexer
// ======================

/// 将字符串输入转换为 Token 列表
class Lexer {
public:
    explicit Lexer(const string& input) : input_(input), pos_(0) {}

    /// 进行词法分析,返回 Token 序列
    vector<Token> tokenize() {
        vector<Token> tokens;
        while (pos_ < input_.size()) {
            char ch = input_[pos_];
            if (isspace(ch)) {
                ++pos_; // 跳过空白字符
            } else if (isalpha(ch)) {
                // 解析关键字或标识符
                string ident;
                while (isalnum(input_[pos_])) ident += input_[pos_++];
                if (ident == "array") tokens.emplace_back(TokenType::Array, ident);
                else if (ident == "of") tokens.emplace_back(TokenType::Of, ident);
                else if (ident == "integer") tokens.emplace_back(TokenType::Integer, ident);
                else if (ident == "char") tokens.emplace_back(TokenType::Char, ident);
                else tokens.emplace_back(TokenType::Identifier, ident);
            } else if (isdigit(ch)) {
                // 解析数字
                string num;
                while (isdigit(input_[pos_])) num += input_[pos_++];
                tokens.emplace_back(TokenType::Number, num);
            } else if (ch == '.' && peek() == '.') {
                // 范围符号 ..
                tokens.emplace_back(TokenType::DotDot, "..");
                pos_ += 2;
            } else if (ch == '[') {
                tokens.emplace_back(TokenType::LBracket, "[");
                ++pos_;
            } else if (ch == ']') {
                tokens.emplace_back(TokenType::RBracket, "]");
                ++pos_;
            } else {
                cerr << "非法字符: " << ch << endl;
                ++pos_;
            }
        }
        tokens.emplace_back(TokenType::End, "#");
        return tokens;
    }

private:
    string input_;
    size_t pos_;

    /// 预览下一个字符
    char peek() const {
        return (pos_ + 1 < input_.size()) ? input_[pos_ + 1] : '\0';
    }
};

// ======================
// 语法分析器:递归下降 Parser
// ======================

/// 解析 Pascal 类型定义文法
class Parser {
public:
    explicit Parser(const vector<Token>& tokens) : tokens_(tokens), pos_(0) {}

    /// 启动解析,从 type 开始
    bool parse() {
        return parseType() && match(TokenType::End);
    }

private:
    const vector<Token>& tokens_;
    size_t pos_;

    /// 获取当前 Token
    const Token& current() const {
        return tokens_[pos_];
    }

    /// 匹配并消费一个特定类型的 Token
    bool match(TokenType expected) {
        if (current().type == expected) {
            ++pos_;
            return true;
        }
        return false;
    }

    /// type → simple | id | array [ simple ] of type
    bool parseType() {
        if (match(TokenType::Integer) || match(TokenType::Char) || match(TokenType::Identifier)) {
            return true;
        }
        if (match(TokenType::Array)) {
            if (!match(TokenType::LBracket)) return false;
            if (!parseSimple()) return false;
            if (!match(TokenType::RBracket)) return false;
            if (!match(TokenType::Of)) return false;
            return parseType(); // 递归调用 type
        }
        return false;
    }

    /// simple → integer | char | num dotdot num
    bool parseSimple() {
        if (match(TokenType::Integer) || match(TokenType::Char)) {
            return true;
        }
        if (match(TokenType::Number)) {
            if (!match(TokenType::DotDot)) return false;
            if (!match(TokenType::Number)) return false;
            return true;
        }
        return false;
    }
};

// ======================
// 测试程序入口
// ======================

int main() {
    vector<string> tests = {
        "array[3..5] of integer",     // ✅ 合法
        "array [ integer ] of char", // ✅ 合法
        "char",                       // ✅ 合法
        "3..5",                       // ❌ 错误:不是完整的 type
        "array[3..x] of integer"      // ❌ 错误:x 不是 num
    };

    for (const auto& input : tests) {
        Lexer lexer(input);
        auto tokens = lexer.tokenize();

        Parser parser(tokens);

        cout << "测试: " << input << endl;
        if (parser.parse()) {
            cout << "✅ 语法结构正确\n";
        } else {
            cout << "❌ 语法结构错误\n";
        }
        cout << "------------------------\n";
    }

    return 0;
}

posted @ 2025-04-06 15:07  丘狸尾  阅读(115)  评论(0)    收藏  举报