博客已经迁移到 https://leerw.github.io,欢迎来访,共同交流进步
题目
目的:熟练掌握自上而下的语法分析方法,并能用程序实现。
要求:
例如. 使用的文法如下:
E->TE'
E'->+TE'|#
T->FT'
T'->*FT'|#
F->(E)|id
编写First函数,实现其求解过程。
提示:
1, 非终结符为大写字母;或后面带'的大写字母
2, 终结符为 小写字母和符号(+、*)(#代表空串)
3, 推导符号为->
4, 用end结束文法。
5, 不针对特定文法,编写求first函数。
思路
从文件中读取文法,对每一行将其拆分成两个部分:箭头左边的非终结符和箭头右边的对应产生式;再将产生式按其中的'|'分隔符拆分成若干个对应单词;对每个单词进行考察,若首字母为非终结符则递归寻找First集合,若为终结符,则加入到此非终结符对应的First集合中去。
代码
#include <iostream>
#include <algorithm>
#include <fstream>
#include <map>
#include <set>
#include <string>
using namespace std;
set<string> non_terminal;
set<string> productions;
std::
map<string, string> match_map;
std::
map<string, set<string>> first;
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] ==
'>') {
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));
break;
}
}
}
void divide_right(
string grammar_right,
set<string>& 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);
}
}
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);
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) {
find_first((*j), first);
}
else {
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:
break;
}
continue;
}
}
}
}
}
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,
100);
st = buf;
if (
strlen(buf) ==
0 || st ==
"end") {
break;
}
divide_words(st, match_map);
}
inFile.close();
for (
set<string>::iterator i = non_terminal.begin(); i != non_terminal.end(); ++i) {
set<string> the_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 <<
"{";
for (
set<string>::reverse_iterator j = (i->second).rbegin(); j != (i->second).rend(); j++) {
cout << *j <<
",";
}
cout <<
'\b';
cout <<
"}";
cout << endl;
}
cout << endl << endl;
return 0;
}
wenfa.txt 运行结果: