实验 2 递归下降语法分析程序设计-编译原理(湖工大)

【实验目的】

(1)理解语法分析在编译程序中的作用,以及它与词法分析程序的关系 (2)加深对递归下降语法分析原理的理解 (3)掌握递归下降语法分析的实现方法

【实验内容】

编制一个递归下降分析程序,实现对词法分析程序提供的单词序列的语法检查和结构分析。

【实验要求】

(1)待分析的简单语言的词法同实验 1

(2)待分析的简单语言的语法 用扩充的 BNF 表示如下:

         1)::=beginend、 2) ::={;} 、3) ::= 、4) ::=ID:= 、5) ::={+|-}、

         6) ::={*|/} 、7) ::=ID|NUM|()

(3)语法分析程序的功能 输入单词串以”#”结束,如果是文法正确的句子,输出成功信息;否则输出错误信息。

                例如: 输入 begin a:=9; x:=2 * 3; b:=a + x end # 输出 success

                            输入 x:=a + b * c end # 输出 error

【实验代码】

        实验二是在实验一的基础上进行的,只需对实验一的头文件稍作修改,再加入一点语法判断即可。

        下面的三个文件都需要,根据实验要求对不需要的代码做注释即可

做了修改的实验一的头文件.hpp

#ifndef TEST_HPP_2_1
#define TEST_HPP_2_1

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cctype>
#include "2.2_test.hpp"

std::unordered_map<std::string, int> TOKEN_MAPPING = {
    {"begin", 1},
    {"if", 2},
    {"then", 3},
    {"while", 4},
    {"do", 5},
    {"end", 6},
    {"letter(letter|digit)*", 10},
    {"digitdigit*", 11},
    {"+", 13},
    {"-", 14},
    {"*", 15},
    {"/", 16},
    {":", 17},
    {":=", 18},
    {"<", 20},
    {"<>", 21},
    {"<=", 22},
    {">", 23},
    {">=", 24},
    {"=", 25},
    {";", 26},
    {"(", 27},
    {")", 28},
    {"#", 0}};

// 函数声明
bool isLetter(char c);
bool isDigit(char c);
bool isOperator(char c);
bool isDelimiter(char c);
bool isValidIdentifierChar(char c);
bool isAssignmentOperator(const std::string &token);

// 逻辑函数实现
std::vector<int> Scanner(std::string input)
{
    std::vector<int> v;
    for (size_t i = 0; i < input.size(); ++i)
    {
        char c = input[i];
        if (isspace(c)) // Skip whitespace
            continue;
        else if (isLetter(c)) // Variable or keyword
        {
            std::string token = "";
            while (i < input.size() && isValidIdentifierChar(input[i]))
                token += input[i++];
            --i; // 循环中增加了i,这里需要减回来
            auto it = TOKEN_MAPPING.find(token);
            if (it != TOKEN_MAPPING.end())
            {
                std::cout << "(" << it->second << ", " << token << ") ";
                v.push_back(it->second);
            }
            else
            {
                std::cout << "(" << TOKEN_MAPPING["letter(letter|digit)*"] << ", " << token << ") ";
                v.push_back(TOKEN_MAPPING["letter(letter|digit)*"]);
            }
        }
        else if (isDigit(c)) // Number
        {
            std::string token = "";
            while (i < input.size() && isDigit(input[i]))
                token += input[i++];
            --i; // 循环中增加了i,这里需要减回来
            std::cout << "(" << TOKEN_MAPPING["digitdigit*"] << ", " << token << ") ";
            v.push_back(TOKEN_MAPPING["digitdigit*"]);
        }
        else if (isOperator(c) || c == ':') // Operator or start of assignment operator
        {
            std::string token = "";
            token += c;
            if (c == ':' && i + 1 < input.size() && input[i + 1] == '=')
                token += input[++i]; // 捕获 :=
            if (c == '<' || c == '>')
                if (i + 1 < input.size() && input[i + 1] == '=')
                    token += input[++i]; // Capture <= or >=
            auto it = TOKEN_MAPPING.find(token);
            if (it != TOKEN_MAPPING.end())
            {
                std::cout << "(" << it->second << ", " << token << ") ";
                v.push_back(it->second);
            }
        }
        else if (isDelimiter(c)) // Delimiter
        {
            std::string token = "";
            token += c;
            std::cout << "(" << TOKEN_MAPPING[token] << ", " << token << ") ";
            v.push_back(TOKEN_MAPPING[token]);
        }
    }
    std::cout << "\nProgram ended." << std::endl;
    Print(v);
    return v;
}

// 函数定义
bool isLetter(char c)
{
    return std::isalpha(c);
}

bool isDigit(char c)
{
    return std::isdigit(c);
}

bool isOperator(char c)
{
    return c == '+' || c == '-' || c == '*' || c == '/' || c == '>' || c == '<';
}

bool isDelimiter(char c)
{
    return c == '(' || c == ')' || c == ';' || c == '#';
}

bool isValidIdentifierChar(char c)
{
    return isLetter(c) || isDigit(c);
}

bool isAssignmentOperator(const std::string &token)
{
    return token == ":=";
}

#endif // TEST_HPP_2_1

实验二要求的语法分析的头文件.hpp

#ifndef TEST_HPP_2_2
#define TEST_HPP_2_2

#include <vector>
#include <iostream>

std::vector<std::vector<int>> splitSegments(const std::vector<int> &input, int delimiter);
void Print(std::vector<int> v);
void PrintTwo(std::vector<std::vector<int>> segments);
bool Assign(std::vector<int> row);
bool check_alternate(const std::vector<int> &num, int data, const std::vector<int> &sequence);

bool Yucu(std::vector<int> v)
{
    if (v[0] != 1 || v[v.size() - 1] != 0 || v[v.size() - 2] != 6)
        return false;
    // 弹出首元素
    v.erase(v.begin());
    // 弹出两个尾元素
    v.pop_back();
    v.pop_back();

    // Print(v);

    int delimiter = 26;
    // 调用函数将输入数据分割成多个段(用;分隔语句)
    std::vector<std::vector<int>> segments = splitSegments(v, delimiter);

    // PrintTwo(segments);

    // 逐句检查
    // 赋值语句: 找值为18的元素,且前面只有一个元素为10,后面为表达式   √ 只实现这个应付实验足矣
    // 分支语句:找到if2,直接用then3进行分段,如果then3前面没有if2,则语句出错
    // 表达式语句: 特征就是没有赋值符18,只有运算符和数字11间隔出现,没有变量10
    // 比较语句: 出现[20,25](不包括21)且不为首尾的表达式语句,和表达式语句类似
    for (const auto &row : segments)
    {
        for (int num : row)
        {
            // if (num == 2) // 分支语句
            //     return IsIfThen(row);
            if (num == 18) // 赋值语句
                return Assign(row);
        }
    }
    return true;
}

// // 判断是否为if...then...语句
// bool IsIfThen(std::vector<int> row)
// {
//     // 没有then(3)就不会分段
//     std::vector<std::vector<int>> IfThen = splitSegments(row, 3);
//     PrintTwo(IfThen);
// }

// 判断是否为赋值语句
bool Assign(std::vector<int> row)
{
    if (row.size() <= 2 || row[0] != 10)
        return false;
    std::vector<int> num = {13, 14, 15, 16};
    int data = 11;
    return check_alternate(num, data, row);
}

// 数字和运算符是否交叉出现
bool check_alternate(const std::vector<int> &num, int data, const std::vector<int> &sequence)
{
    if (num.empty() || sequence.empty())
        return false;
    bool is_num_turn = true; // 表示当前轮到数字11
    size_t index = 0;
    for (int i = 0; i < sequence.size(); ++i)
        if (sequence[i] == data)
            if (is_num_turn)
                is_num_turn = false;
            else
                return false;
        else
        {
            if (index < i && sequence[index] == sequence[i])
                return false;
            index = i;
        }
    return !is_num_turn;
}

// 遍历vector
void Print(std::vector<int> v)
{
    std::cout << "Elements:";
    for (int elem : v)
        std::cout << " " << elem;
    std::cout << std::endl;
}

// 打印分组的二维 vector
void PrintTwo(std::vector<std::vector<int>> segments)
{
    std::cout << "Remaining elements:" << std::endl;
    for (const auto &row : segments)
    {
        for (int num : row)
            std::cout << num << " ";
        std::cout << std::endl;
    }
}

std::vector<std::vector<int>> splitSegments(const std::vector<int> &input, int delimiter)
{
    std::vector<std::vector<int>> segments;
    std::vector<int> segment;

    for (int num : input)
    {
        if (num == delimiter)
        {
            // 如果遇到分隔符,则将当前段存储到结果中,并开始一个新段
            if (!segment.empty())
            {
                segments.push_back(segment);
                segment.clear();
            }
        }
        else
        {
            // 将数字添加到当前段中
            segment.push_back(num);
        }
    }

    // 将最后一个段添加到结果中(如果它不为空)
    if (!segment.empty())
    {
        segments.push_back(segment);
    }

    return segments;
}

#endif // TEST_HPP_2_2

实验二的逻辑函数源文件.cpp

#include "2.1_test.hpp"
#include "2.2_test.hpp"
#include <iostream>
using namespace std;

int main()
{
    string prog;
    do
    {
        cout << "Please input string: ";
        getline(cin, prog);
        if (prog.length() >= 2 && prog[prog.length() - 1] != '#')
            cout << "\nInput string should end with '#'." << endl;
        else
        {
            vector<int> vector = Scanner(prog);
            if (Yucu(vector))
                cout << "\nsuccess" << endl;
            else
                cout << "\nerror" << endl;
        }
    } while (prog.length() < 2 || prog[prog.length() - 1] != '#');
    return 0;
}

// begin x:=9;if x>0 then x:=2*x+1/3;end#

// 输入 begin a:=9; x:=2 * 3; b:=a + x end #
// 输出 success
// 输入 x:=a + b * c end #
// 输出 error

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值