一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C/C++ - C++編譯原理之求解First集合

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

2022-01-25 14:31立秋小豬 C/C++

這篇文章主要介紹的是C++/編譯原理求解First集合,本文將圍繞該話題詳細展開全文,需要的小伙伴可以參考一下

1、上機要求

目的:熟練掌握自上而下的語法分析方法,并能用程序實現。

要求:

例如,使用的文法如下:
編寫First函數,實現其求解過程。

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

提示:

  • 非終結符為 大寫字母;或 后面帶'的大寫字母
  • 終結符為 小寫字母和符號(+、*)
  • 推導符號→為或->
  • 用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)中,若Y1,Y2,???,Yn都有空串,則將空串加入到First(A)中

First(a) = {a}

 

3、一點思路及優化

將輸入格式化(掃描輸入)
將產生式轉換為哈希map:

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

 

4、代碼

/**
* @brief Function for generating set of First(a)
* @author 立秋小豬
* @time: 2021/10/13
* @notice: 要求產生體句型不得有空格
*          左遞歸的產生體中必須有空串(必須能夠終結)
*          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; //產生式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

運行結果

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

4.2 lan.txt文件內容

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

運行結果

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

到此這篇關于C++/編譯原理之求解First集合的文章就介紹到這了,更多相關C++ 求解First集合內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/liqiuxiaozhu/p/15403976.html

延伸 · 閱讀

精彩推薦
  • C/C++C語言中炫酷的文件操作實例詳解

    C語言中炫酷的文件操作實例詳解

    內存中的數據都是暫時的,當程序結束時,它們都將丟失,為了永久性的保存大量的數據,C語言提供了對文件的操作,這篇文章主要給大家介紹了關于C語言中文件...

    針眼_6702022-01-24
  • C/C++C/C++經典實例之模擬計算器示例代碼

    C/C++經典實例之模擬計算器示例代碼

    最近在看到的一個需求,本以為比較簡單,但花了不少時間,所以下面這篇文章主要給大家介紹了關于C/C++經典實例之模擬計算器的相關資料,文中通過示...

    jia150610152021-06-07
  • C/C++c++ 單線程實現同時監聽多個端口

    c++ 單線程實現同時監聽多個端口

    這篇文章主要介紹了c++ 單線程實現同時監聽多個端口的方法,幫助大家更好的理解和學習使用c++,感興趣的朋友可以了解下...

    源之緣11542021-10-27
  • C/C++深入理解goto語句的替代實現方式分析

    深入理解goto語句的替代實現方式分析

    本篇文章是對goto語句的替代實現方式進行了詳細的分析介紹,需要的朋友參考下...

    C語言教程網7342020-12-03
  • C/C++C++之重載 重定義與重寫用法詳解

    C++之重載 重定義與重寫用法詳解

    這篇文章主要介紹了C++之重載 重定義與重寫用法詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下...

    青山的青6062022-01-04
  • C/C++C語言實現電腦關機程序

    C語言實現電腦關機程序

    這篇文章主要為大家詳細介紹了C語言實現電腦關機程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    xiaocaidayong8482021-08-20
  • C/C++學習C++編程的必備軟件

    學習C++編程的必備軟件

    本文給大家分享的是作者在學習使用C++進行編程的時候所用到的一些常用的軟件,這里推薦給大家...

    謝恩銘10102021-05-08
  • C/C++詳解c語言中的 strcpy和strncpy字符串函數使用

    詳解c語言中的 strcpy和strncpy字符串函數使用

    strcpy 和strcnpy函數是字符串復制函數。接下來通過本文給大家介紹c語言中的strcpy和strncpy字符串函數使用,感興趣的朋友跟隨小編要求看看吧...

    spring-go5642021-07-02
主站蜘蛛池模板: 日本色女 | 天天色天天综合 | 亚久久伊人精品青青草原2020 | 国产精品嫩草影院一二三区 | 国产一卡二卡3卡4卡四卡在线 | 国亚洲欧美日韩精品 | 95视频在线观看在线分类h片 | 男人天堂久久 | 成人永久免费 | 免看一级a一片成人123 | 翁息肉小说老扒 | 日本高清中文字幕一区二区三区 | 国产成人免费高清激情明星 | 亚洲 综合 欧美在线 热 | 嘿嘿午夜| 亚洲欧美优优色在线影院 | 岛国不卡 | 国产美女屁股直流白浆视频无遮挡 | 国产香蕉97碰碰在线视频 | 欧美乱子伦xxxx12在线 | 91香蕉视频导航 | 亚洲欧洲日产国码 最新 | 国产成人8x视频一区二区 | 日本大尺度激情做爰叫床 | 亚洲午夜精品久久久久久人妖 | 人人艹在线视频 | 岛国不卡 | 韩国最新理论片奇忧影院 | 五月色天在线视频综合观看 | 亚洲福利在线观看 | 毛片99| 国产精品一区三区 | 亚洲天天做夜夜做天天欢 | 国产麻豆流白浆在线观看 | 日日摸日日碰夜夜爽97纠 | 狠狠色狠狠色综合婷婷tag | 四虎2021地址入口 | 娇喘嗯嗯 轻点啊视频福利 九九九九在线精品免费视频 | 暖暖视频日本 | 色天天综合色天天碰 | 青青青青在线视频 |