欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++編譯原理之求解First集合

 更新時(shí)間:2021年10月19日 08:50:12   作者:立秋小豬  
這篇文章主要介紹的是C++/編譯原理求解First集合,本文將圍繞該話題詳細(xì)展開全文,需要的小伙伴可以參考一下

1、上機(jī)要求

目的:熟練掌握自上而下的語法分析方法,并能用程序?qū)崿F(xiàn)。

要求:

例如,使用的文法如下:
編寫First函數(shù),實(shí)現(xiàn)其求解過程。

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

提示:

  • 非終結(jié)符為 大寫字母;或 后面帶'的大寫字母
  • 終結(jié)符為 小寫字母和符號(+、*)
  • 推導(dǎo)符號→為或->
  • 用end結(jié)束文法。

不針對特定文法,編寫求first函數(shù)。

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)中,若Y1,Y2,···,Yn都有空串,則將空串加入到First(A)

First(a) = {a}

3、一點(diǎn)思路及優(yōu)化

將輸入格式化(掃描輸入)
將產(chǎn)生式轉(zhuǎn)換為哈希map

  • 對任一產(chǎn)生式: A -> body_1 | body_2 | ··· | body_n,
  • 將 A 作為mapkey
  • map的value為一個string類的向量(vector<string> ),
  • body_1,body_2,···,body_n 都加入value中。
  • 求解First(str)
  • 特殊情況處理,str為空或str不在產(chǎn)生式的key中,返回空;str的首個字符是終結(jié)符,返回首個字符構(gòu)成的集合。
  • 一般情況,獲取str推導(dǎo)產(chǎn)生的產(chǎn)生體集bodys(其中的每個產(chǎn)生體為body),遍歷產(chǎn)生體集合求解First集
  • 針對空串,我們加入標(biāo)記hasBlank = true,往下遍歷body的字符
  • body的首個字符為終結(jié)符,直接將該字符加入first集,記hasBlank = false以便遍歷下一body(如果有的話)。
  • body的首個字符為非終結(jié)符,遞歸求解該非終結(jié)符first集,記為temp,同時(shí)將空串標(biāo)記記為false,將temp的中除空串外的字符加入first集;若temp中有空串,記空串標(biāo)記為true,繼續(xù)遍歷當(dāng)前body的字符,理解上可以將body后面的字符串視為一個新的body繼續(xù)進(jìn)行求解步驟。
  • body的字符遍歷結(jié)束后若空串標(biāo)記hasBlank仍然為true,則將空串加入first集。
  • 優(yōu)化:遞歸求解的中間結(jié)果可以放在全局哈希First(或者換個名字避免沖突)中,避免重復(fù)的迭代(本代碼沒實(shí)現(xiàn),下次一定)。

4、代碼

/**
 * @brief Function for generating set of First(a)
 * @author 立秋小豬
 * @time: 2021/10/13
 * @notice: 要求產(chǎn)生體句型不得有空格
 *          左遞歸的產(chǎn)生體中必須有空串(必須能夠終結(jié))
 *          char '#' act as varepsilon 
 * **/

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

using namespace std;

unordered_map<string, vector<string>> P; //產(chǎn)生式P的集合

void scan(){
    //scan函數(shù)實(shí)現(xiàn)從文件掃描文法,將對應(yīng)的產(chǎn)生式加入到映射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; // 產(chǎn)生式的非終結(jié)符

        fs >> input; //跳過推導(dǎo)符號
        if (input != "->" && input != "→"){
            cout << "Error: undefined symbol [" << input << "]" << endl;
            exit(-2);
        }

        fs >> input; //產(chǎn)生體拆開后加入到set集合中,默認(rèn)推導(dǎo)符號后必有一個產(chǎn)生體
        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){
    // 終結(jié)符以及空串情況下, 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;//是否含有空串,是否繼續(xù)讀產(chǎn)生體
        for (int i = 0; i < s.size() && hasBlank; ++i){
            if(s[i] >= 'A' && s[i] <= 'Z'){//是否為終結(jié)符
                unordered_set<char> temp = {};//遞歸的臨時(shí)集
                string next;
                if(i < s.size() - 1 && s[i + 1] == '\''){ // 大寫字母 + ' 的非終結(jié)符
                    next = s.substr(i, 2);
                    ++i;
                }else{ //僅僅是大寫字母的終結(jié)符
                    next = s[i];
                }
                if(next != str){ //避免無限遞歸,默認(rèn)自身是含有空串(hasBlank為True)
                    temp = First(next); //遞歸求解
                    hasBlank = false; //先默認(rèn)temp中沒有空串
                    for(auto &c : temp)
                        if(c == '#')
                            hasBlank = true;//temp中發(fā)現(xiàn)了空串
                        else
                            res.emplace(c);
                }
            }else{
                res.emplace(s[i]);
                hasBlank = false;//默認(rèn)連接的終結(jié)符不為空,故此終結(jié)符后不會再有新元素加入First集
            }
        }
        if(hasBlank) //產(chǎn)生體中所有非終結(jié)符都包含空串,則將空串加入first集中
            res.emplace('#');
    }
    return res;
}

 

int main(){
    // unordered_map<string, vector<char>> First; //First集合
    scan();
    cout << "輸入的產(chǎn)生式如下:\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文件內(nèi)容

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

運(yùn)行結(jié)果

4.2 lan.txt文件內(nèi)容

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

運(yùn)行結(jié)果

到此這篇關(guān)于C++/編譯原理之求解First集合的文章就介紹到這了,更多相關(guān)C++ 求解First集合內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于C++ OpenCV制作電子相冊查看器

    基于C++ OpenCV制作電子相冊查看器

    這篇文章主要介紹了如何使用OpenCV C++ 制作電子相冊查看器。類似于win10系統(tǒng)的“照片”功能。感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-01-01
  • 關(guān)于C++11中限定作用域的枚舉類型的問題

    關(guān)于C++11中限定作用域的枚舉類型的問題

    C++中有兩種類型的枚舉:不限定作用域的枚舉類型和限定作用域的枚舉類型。限定作用域的枚舉類型是C++11標(biāo)準(zhǔn)引入的新類型,對C++11中限定作用域的枚舉類型相關(guān)知識感興趣的朋友一起看看吧
    2022-01-01
  • MFC控件大小隨窗體大小而改變

    MFC控件大小隨窗體大小而改變

    本文給大家分享的是使用VC++根據(jù)對話框大小調(diào)整控件大小的方法和示例代碼,有需要的小伙伴可以參考下。
    2015-06-06
  • 淺談C語言數(shù)組元素下標(biāo)為何從0開始

    淺談C語言數(shù)組元素下標(biāo)為何從0開始

    很多同學(xué)可能在學(xué)習(xí)數(shù)組時(shí)會有這個疑問,下標(biāo)為什么不從1開始呢?本文主要介紹了淺談C語言數(shù)組元素下標(biāo)為何從0開始,感興趣的可以了解一下
    2022-01-01
  • C++中 map的基本操作

    C++中 map的基本操作

    map是一類關(guān)聯(lián)式容器。接下來通過本文給大家分享c++中的map基本操作,需要的朋友參考下
    2017-05-05
  • C++實(shí)現(xiàn)大整數(shù)乘法

    C++實(shí)現(xiàn)大整數(shù)乘法

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)大整數(shù)乘法,使用笛卡爾相乘,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • C++實(shí)現(xiàn)高校教室管理系統(tǒng)

    C++實(shí)現(xiàn)高校教室管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)高校教室管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解

    C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解

    這篇文章主要介紹了C語言中fchdir()函數(shù)和rewinddir()函數(shù)的使用詳解,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • C語言實(shí)現(xiàn)九大排序算法的實(shí)例代碼

    C語言實(shí)現(xiàn)九大排序算法的實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于C語言實(shí)現(xiàn)九大排序算法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • SublimeText編譯C開發(fā)環(huán)境設(shè)置

    SublimeText編譯C開發(fā)環(huán)境設(shè)置

    這篇文章主要介紹了使用SublimeText編譯C代碼的開發(fā)環(huán)境設(shè)置,大家參考使用
    2013-11-11

最新評論