文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++编译原理之求解First集合

2024-04-02 19:55

关注

1、上机要求

目的:熟练掌握自上而下的语法分析方法,并能用程序实现。

要求:

例如,使用的文法如下:
编写First函数,实现其求解过程。

E -> TE'
E' -> +TE' | #
T -> FT'
T' -> *FT' | #
F -> (E) | id
end

提示:

不针对特定文法,编写求first函数。

2、原理

A -> a, 则将 a 加入 First(A)
A -> Y1Y2···Yn

First(Y1) 除空串外的字符加入到First(A)中,若 1 =< i < n - 1,Y1,Y2, Yi中均含有空串,则将First(Yi + 1)加入到First(A)中,若Y1Y2,···,Yn都有空串,则将空串加入到First(A)

First(a) = {a}

3、一点思路及优化

将输入格式化(扫描输入)
将产生式转换为哈希map

4、代码




#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <fstream>
#include <unordered_set>

using namespace std;

unordered_map<string, vector<string>> P; //产生式P的集合

void scan(){
    //scan函数实现从文件扫描文法,将对应的产生式加入到映射P中
    fstream fs;
    string input;
    fs.open("lan.txt");
    if(!fs.is_open()){ // 文件打开失败
        cout << "Error: Could not open the file" << endl;
        exit(-1);
    }
    fs >> input;
    while(input != "end"){
        string VN = input; // 产生式的非终结符

        fs >> input; //跳过推导符号
        if (input != "->" && input != "→"){
            cout << "Error: undefined symbol [" << input << "]" << endl;
            exit(-2);
        }

        fs >> input; //产生体拆开后加入到set集合中,默认推导符号后必有一个产生体
        P[VN].emplace_back(input);
        while( fs >> input && input == "|"){
                fs >> input;
                P[VN].emplace_back(input);
        }
    }
}

// void generate(){
// }

unordered_set<char> First(const string& str){
    // 终结符以及空串情况下, whether has the VN or not
    if(str == "" || str == "#" || P.find(str) == P.end())
        return {};
    if(!(str[0] >= 'A' && str[0] <= 'Z'))
        return {str[0]};

    vector<string> bodys = P[str]; // str -> bodys
    unordered_set<char> res = {};
    for(auto &s: bodys){
        bool hasBlank = true;//是否含有空串,是否继续读产生体
        for (int i = 0; i < s.size() && hasBlank; ++i){
            if(s[i] >= 'A' && s[i] <= 'Z'){//是否为终结符
                unordered_set<char> temp = {};//递归的临时集
                string next;
                if(i < s.size() - 1 && s[i + 1] == '\''){ // 大写字母 + ' 的非终结符
                    next = s.substr(i, 2);
                    ++i;
                }else{ //仅仅是大写字母的终结符
                    next = s[i];
                }
                if(next != str){ //避免无限递归,默认自身是含有空串(hasBlank为True)
                    temp = First(next); //递归求解
                    hasBlank = false; //先默认temp中没有空串
                    for(auto &c : temp)
                        if(c == '#')
                            hasBlank = true;//temp中发现了空串
                        else
                            res.emplace(c);
                }
            }else{
                res.emplace(s[i]);
                hasBlank = false;//默认连接的终结符不为空,故此终结符后不会再有新元素加入First集
            }
        }
        if(hasBlank) //产生体中所有非终结符都包含空串,则将空串加入first集中
            res.emplace('#');
    }
    return res;
}

 

int main(){
    // unordered_map<string, vector<char>> First; //First集合
    scan();
    cout << "输入的产生式如下:\n"
         << "********************************\n";
    for(auto &[vn, bodys]: P){
        cout << vn << " -> " << bodys[0];
        for (int i = 1; i < bodys.size(); ++i)
            cout << " | " << bodys[i];
        cout << endl;
    }
    cout << "********************************\n";

    for(auto &[vn,_]: P){
        unordered_set<char> f = First(vn);
        cout << "First(" << vn << ") : ";
        auto iter = f.begin();

        if(iter != f.end()){
            cout << *iter;
            while(++iter != f.end()){
                cout << " , " << *iter;
            }
        }
        cout << endl;
    }

    return 0;
}

4.1 lan.txt文件内容


E -> TE'
E' -> +TE' | #
T -> FT'
T' -> *FT' | #
F -> (E) | id
end

运行结果

4.2 lan.txt文件内容


S -> SaRb | #
R -> RSQ | #
Q -> e
end

运行结果

到此这篇关于C++/编译原理之求解First集合的文章就介绍到这了,更多相关C++ 求解First集合内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯