编译原理:求非终结符的FOLLOW集合
来源:互联网 发布:淘宝怎么发微淘 编辑:程序博客网 时间:2024/06/05 16:34
还是先把代码给贴出来,回头再找时间写篇文章总结一下,分析一下数据结构和算法
#pragma once#include <iostream>#include <algorithm>#include <fstream>#include <map>#include <set>#include <string>#include <stack>using namespace std;/*----------------------------------------全局变量存放终结符和非终结符---------------------------------------------------*/set<string> non_terminal; //存放非终结符set<string> productions; //存放产生式std::map<string, string> match_map; //存放非终结符和其对应的产生式的文法的键值对std::map<string, set<string>> first; //string:非终结符;set<string>:非终结符所对应的first集合std::map<string, set<string>> follow; //string:非终结符;set<string>:非终结符所对应的follow集合bool is_not_changing = false;void divide_words(string grammar, map<string, string>& match_map) { for (int i = 0; i < (int)grammar.length(); ++i) { if (grammar[i] == '-' && grammar[i + 1] == '>') { /* code */ string left = grammar.substr(0, i); //一句文法的左边即非终结符 string right = grammar.substr(i + 2, grammar.length() - 1); //一句文法的右边即非终结符对应的产生式 non_terminal.insert(left); //插入非终结符集合里 productions.insert(right); //插入产生式集合里 match_map.insert(make_pair(left, right)); //将一句文法里的非终结符和其对应的产生式作为键值对插入到匹配map里 break; } }}/*将被'|'隔开的产生式拆分成对应多个的单词*/void divide_right(string grammar_right, set<string>& small_right) { /*或许可以用grammar.find_first_of一个一个找|,然后用substr分开子串,最后再insert到small_right中去*/ size_t found = grammar_right.find('|'); if (found != string::npos) { int i = 0; string temp = "\0"; while ((size_t)i < grammar_right.length()) { if (grammar_right[i] != '|') { temp += grammar_right[i]; i = i + 1; } else { i = i + 1; small_right.insert(temp); temp = "\0"; } if (i == grammar_right.length()) { small_right.insert(temp); temp = "\0"; } } } else { small_right.insert(grammar_right); }}/*对每个非终结符non_term寻找它的非终结符集合first*/void find_first(string non_term, set<string>& first) { set<string> or_words; //存放产生式中被'|'隔开的单词 auto search = match_map.find(non_term); if (search != match_map.end()) { divide_right(search->second, or_words); //匹配非终结符是否在or_words的开头 for (set<string>::iterator i = or_words.begin(); i != or_words.end(); i++) { for (set<string>::iterator j = non_terminal.begin(); j != non_terminal.end(); j++) { if ((*i).find(*j) == 0) { //在or_words[i]的开头找到了一个非终结符 //递归寻找非终结符j的first集合 find_first((*j), first); } else { //在or_words[i]的开头如果没有找到非终结符,即终结符 if ((*i)[0] >= 'a' && (*i)[0] <= 'z') { first.insert(*i); } switch ((*i)[0]) { case '(': first.insert(string("(")); break; case ')': first.insert(string(")")); break; case '+': first.insert(string("+")); break; case '*': first.insert(string("*")); break; case '#': first.insert(string("#")); break; default: //如果没有匹配到符号的话就把这个单词插入到first集合中 //first.insert(*i); break; } continue; //找到之后跳出循环,避免进行多余的遍历浪费时间 } } } }}//对非终结符的follow集进行初始化,开始符号的follow集初始化成{$},其余的初始化成空集void initial_follow() { for (set<string>::iterator i = non_terminal.begin(); i != non_terminal.end(); i++) { if (i == non_terminal.begin()) { set<string> startFollow; startFollow.insert("$"); auto pair = make_pair(*i, startFollow); follow.insert(pair); } set<string> temp_follow; auto pair = make_pair(*i, temp_follow); follow.insert(pair); }}//判断一个非终结符的first集合中是不是含有空串#bool first_contains_null(set<string> &first) { auto find = first.find("#"); if (find != first.end()) { return true; } return false;}//判断一个字符串str是否是非终结符,如果是返回true,否则返回falsebool is_non_terminal(string str) { auto find = non_terminal.find(str); if (find != non_terminal.end()) { return true; } return false;}bool is_letter(char a) { //是否是小写字母 if (a >= 'a' && a <= 'z') { return true; } return false;}bool is_cap_letter(char a) { return (a >= 'A' && a <= 'Z') ? true : false;}//返回一个产生式的右部str的最后一个终结符或者非终结符string find_last(string &str) { if ("\0" == str) { return "\0"; } if ('\'' == str.at(str.size() - 1)) { string s = str.substr(str.size() - 2, 2); str = str.substr(0, str.size() - 2); return s; } else if (is_letter( str.at(str.size() - 1) ) && is_letter( str.at( str.size() - 2) ) ) { string s = str.substr(str.size() - 2, 2); str = str.substr(0, str.size() - 2); return s; } else { string s = str.substr(str.size() - 1, 1); str = str.substr(0, str.size() - 1); return s; }}int cal_follow_total_size() { //计算所有follow集合的总size int total_size = 0; for (map<string, set<string>>::iterator i = follow.begin(); i != follow.end(); i++) { total_size += i->second.size(); } return total_size;}void find_follow(std::map<string, set<string>>& Follow) { while (!is_not_changing) { int fomer_size = cal_follow_total_size(); for (std::map<string, string>::iterator i = match_map.begin(); i != match_map.end(); i++) {//对每一个产生式进行遍历 set<string> or_words; string left = (*i).first; //左边的非终结符A string right = (*i).second; //右边的产生式A->b1b2b3B... divide_right(right, or_words); for (set<string>::iterator j = or_words.begin(); j != or_words.end(); j++) { set<string> temp = Follow.find(left)->second; string str; string word = *j; for (; word != "\0"; ) { str = find_last(word); if (!is_non_terminal(str)) { //是终结符 temp.clear(); temp.insert(str); } else { for (set<string>::iterator k = temp.begin(); k != temp.end(); k++) { if ("#" != (*k)) { (Follow.find(str)->second).insert(*k); } } if (!first_contains_null(first.find(str)->second)) { temp = first.find(str)->second; } else { for (set<string>::iterator m = first.find(str)->second.begin(); m != first.find(str)->second.end(); m++) { temp.insert(*m); } } } } } } //判断是否发生变化 int latter_size = cal_follow_total_size(); is_not_changing = fomer_size == latter_size ? true : false; }}int main() { /*读取文法文件*/ const char* filename = "wenfa.txt"; ifstream inFile(filename); if (!inFile) { cout << "\nFiled to open file " << filename; return -1; } string st = "\0"; char buf[100]; while (!inFile.eof()) { inFile.getline(buf, 20); st = buf; if (strlen(buf) == 0 || st == "end") { break; } divide_words(st, match_map); //对每一行文法进行分析找出非终结符和对应的产生式 } inFile.close(); /*遍历非终结符集合,为每个非终结符寻找first集合*/ for (set<string>::iterator i = non_terminal.begin(); i != non_terminal.end(); ++i) { set<string> the_first; //当前非终结符的first集合 find_first(*i, the_first); first.insert(make_pair(*i, the_first)); } cout << "非终结符" << "\t" << "First集合" << endl; for (map<string, set<string>>::iterator i = first.begin(); i != first.end(); i++) { cout << "-------------------------" << endl; cout << i->first << "\t|\t"; cout << "{ "; //倒序输出first集合中的元素与文法中出现的顺序保持一致 for (set<string>::reverse_iterator j = (i->second).rbegin(); j != (i->second).rend(); j++) { cout << *j << ", "; } cout << "\b\b }"; cout << endl; } cout << endl; initial_follow(); find_follow(follow); cout << "非终结符" << "\t" << "Follow集合" << endl; for (map<string, set<string>>::iterator i = follow.begin(); i != follow.end(); i++) { cout << "------------------------------" << endl; cout << i->first << "\t|\t"; cout << "{ "; //倒序输出first集合中的元素与文法中出现的顺序保持一致 for (set<string>::reverse_iterator j = (i->second).rbegin(); j != (i->second).rend(); j++) { cout << *j << ", "; } cout << "\b\b }"; cout << endl; } return 0;}
阅读全文
1 0
- 编译原理:求非终结符的FOLLOW集合
- 如何求非终结符的FIRST集合FOLLOW集
- 编译原理:求非终结符的First集合
- 编译原理-First集合和Follow集合的求法
- 编译原理-First集合和Follow集合的求法
- 编译原理中FIRST集合与FOLLOW集合的算法
- 编译原理first集合和follow集合
- 编译原理:求First集与Follow集的方法
- 编译原理:求First集与Follow集的方法
- 编译原理FIRST集合FOLLOW集的求法
- first、follow集合求解 (编译原理)
- 编译原理:first集合和follow集合的求法及LL(1)文法判定
- 编译原理学习(二)--终结符和非终结符
- 编译原理中LL(1)文法求FIRST集和FOLLOW集的方法
- 怎么求编译原理自顶向下分析的first集follow集和select
- 编译原理的FOLLOW和FIRST
- 编译原理中Follow集的求法
- 编译原理:求First集和Follow集
- markdown-test
- ConcurrentHashMap的实现原理
- 找工作知识储备(3)---从头说12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用
- Spark集群搭建
- 数据结构(郝斌老师)
- 编译原理:求非终结符的FOLLOW集合
- netstat命令-查看端口被占用情况,并杀死进程
- java中的字节流
- C# 串口介绍以及简单串口通信程序设计实现
- UIWebView设置为可编辑模式
- 数据结构(郝斌老师)
- JavaScript继承
- jdbc使用流程
- Kotlin练习-堆排序