#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<set>
#include<cstring>
using namespace std;
map<char,int>getnum;
char getchar[100]; //获得对应字符
vector<string>proce;
int table[100][100]; //预测分析表
int num=0;int numvt=0; //numvt是终结符集合,0是‘#’,numvt表空字
string first[100];
string follow[200];
void readin()
{
memset(table,-1,sizeof(table));
getnum['#']=0;
getchar[0]='#';
cout<<"请输入终结符集:"<<endl;
char x;
do
{
cin>>x;
getnum[x]=++num;
getchar[num]=x;
}while(cin.peek()!='\n');
numvt=++num;
getnum['@']=numvt; //kong zi
getchar[num]=('@');
cout<<"请输入非终结符集:"<<endl;
do
{
cin>>x;
getnum[x]=++num;
getchar[num]=x;
}while(cin.peek()!='\n');
cout<<"输入所有产生式(空字用‘@’表示),以‘end’结束:"<<endl;
string pro;
while(cin>>pro&&pro!="end")
{
string ss;
ss+=pro[0];
for(int i=3;i<pro.size();i++)
{
if(pro[i]=='|')
{
proce.push_back(ss);
ss.clear();ss+=pro[0];
}
else
{
ss+=pro[i];
}
}
proce.push_back(ss);
}
}
void jiaoji(string &a,string b) //a=a or b 取a,b交集赋值给a
{
set<char>se;
for(int i=0;i<a.size();i++)
se.insert(a[i]);
for(int i=0;i<b.size();i++)
se.insert(b[i]);
string ans;
set<char>::iterator it;
for(it=se.begin();it!=se.end();it++)
ans+=*it;
a=ans;
}
string get_f(int vn,int & has_0) //dfs:vn能推出的不含空字的vt集合,并且判断vn能否推出空字
{
if(vn==numvt)has_0=1;
if(vn<numvt)return first[vn];
string ans;
for(int i=0;i<proce.size();i++)
{
if(getnum[proce[i][0]]==vn)
ans+=get_f(getnum[proce[i][1]],has_0);
}
return ans;
}
void getfirst()
{
for(int i=1;i<=numvt;i++) //终结符,first集是其本身。
{
first[i]+=('0'+i);
}
for(int j=0;j<proce.size();j++) //扫描所有产生式
{
int k=0;int has_0=0; //k扫瞄该产生式
do{
has_0=0;
k++;
if(k==proce[j].size()) //推到最后一个了,则附加空字
{
first[getnum[proce[j][0]]]+=('0'+numvt);
break;
} //合并之
jiaoji(first[getnum[proce[j][0]]],get_f(getnum[proce[j][k]],has_0));
}
while(has_0); //到无法推出空字为止
}
}
void print_first()
{
cout<<"first集如下:"<<endl;
for(int i=1;i<=num;i++)
{
cout<<"first ["<<getchar[i]<<"]: ";
for(int j=0;j<first[i].size();j++)
cout<<getchar[first[i][j]-'0']<<" ";
cout<<endl;
}
cout<<endl;
}
void getfollow()
{
jiaoji(follow[getnum[proce[0][0]]],"0"); //先添加‘#’;
for(int j=0;j<proce.size();j++) //扫所有产生式
{
for(int jj=1;jj<proce[j].size();jj++) //每个非终结符的follow集
{
if(getnum[proce[j][jj]]<=numvt)continue; //vt无follow集
int k=jj; int has_0;
do
{
has_0=0;
k++;
if(k==proce[j].size()) //都能推出空字,follow集=产生式左边的vn,
{
jiaoji(follow[getnum[proce[j][jj]]],follow[getnum[proce[j][0]]]);
break;
}
jiaoji(follow[getnum[proce[j][jj]]],get_f(getnum[proce[j][k]],has_0));
}while(has_0);
}
}
}
void gettable() //得预测分析表
{
for(int i=0;i<proce.size();i++) //扫所有产生式
{
if(proce[i][1]=='@') //直接推出空字的,特判下(follow集=产生式左边的vn中元素填)
{
string flw=follow[getnum[proce[i][0]]];
for(int k=0;k<flw.size();k++)
{
table[getnum[proce[i][0]]][flw[k]-'0']=i;
}
}
string temps=first[getnum[proce[i][1]]];
for(int j=0;j<temps.size();j++) //考察first集
{ if(temps[j]!=('0'+numvt))
{
table[getnum[proce[i][0]]][temps[j]-'0']=i;
}
else //有空字的,考察follw集
{
string flw=follow[getnum[proce[i][1]]];
for(int k=0;k<flw.size();k++)
{
table[getnum[proce[i][0]]][flw[k]-'0']=i;
}
}
}
}
}
string get_proce(int i) //由对应下标获得对应产生式。
{
if(i<0)return " "; //无该产生式
string ans;
ans+=proce[i][0];
ans+="->";
//ans+=(proce[i][0]+"->"); 注意这样不行!思之即可。
for(int j=1;j<proce[i].size();j++)
ans+=proce[i][j];
return ans;
}
void print_table()
{
cout<<"预测分析表如下:"<<endl;
for(int i=0;i<numvt;i++)
cout<<'\t'<<getchar[i];
cout<<endl;
for(int i=numvt+1;i<=num;i++)
{
cout<<getchar[i];
for(int j=0;j<numvt;j++)
{
cout<<'\t'<<get_proce(table[i][j]);
}
cout<<endl;
}
cout<<endl;
}
void print_follow()
{
cout<<"follow集如下:"<<endl;
for(int i=numvt+1;i<=num;i++)
{
cout<<"follow ["<<getchar[i]<<"]: ";
for(int j=0;j<follow[i].size();j++)
cout<<getchar[follow[i][j]-'0']<<" ";
cout<<endl;
}
cout<<endl;
}
string word;
bool analyze() //总控,分析字word的合法性,若合法,输出所有产生式。
{
stack<char>sta;
sta.push('#');sta.push(proce[0][0]);
int i=0;
while(!sta.empty())
{
int cur=sta.top();
sta.pop();
if(cur==word[i]) //是终结符,推进
{
i++;
}
else if(cur=='#') //成功,结束
{
return 1;
}
else if(table[getnum[cur]][getnum[word[i]]]!=-1) //查表
{ int k=table[getnum[cur]][getnum[word[i]]];
cout<<proce[k][0]<<"->";
for(int j=1;j<proce[k].size();j++)
cout<<proce[k][j];
cout<<endl;
for(int j=proce[k].size()-1;j>0;j--) //逆序入栈
{ if(proce[k][j]!='@')
sta.push(proce[k][j]);
}
}
else //失败!
{
return 0;
}
}
return 1;
}
int main()
{
readin();
getfirst();
getfollow();
getfollow();
gettable();
print_first();
print_follow();
print_table();
cout<<"请输入字:"<<endl;
cin>>word;
if(analyze())
cout<<"succeed!该字有效,所用产生式如上。"<<endl;
else cout<<"error!"<<endl;
return 0;
}


/*测试:
( ) i + *
E A T B F
E->TA
A->+TA|@
T->FB
B->*FB|@
F->(E)|i
end
i*i+i a b c d
S A B
S->BA
A->BS|d
B->aA|bS|c
end
adccd + - * / ( ) i
E G T F S 
E->TG
G->+TG|-TG
G->@
T->FS
S->*FS|/FS
S->@
F->(E)
F->i
end
i+i*i
*/

LL(1)语法分析器 //c++实现的更多相关文章

  1. 编译原理简单语法分析器(first,follow,分析表)源码下载

    编译原理(简单语法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E5%8A%A0%E5%85%A5%E5%90%8C%E6%AD%A5%E7%AC ...

  2. Tiny语法分析器(递归下降分析法实现)

    递归规约规则是这样的 program→stmt-sequence stmt-sequence→stmt-sequence;statement|statement statement→if-stmt|r ...

  3. 有没有好用的开源sql语法分析器? - 匿名用户的回答 - 知乎

    有没有好用的开源sql语法分析器? - 匿名用户的回答 - 知乎 presto,hive,drill,calcite,sparksq

  4. 开源语法分析器--ANTLR

      序言 有的时候,我还真是怀疑过上本科时候学的那些原理课究竟是不是在浪费时间.比方学完操作系统原理之后我们并不能自己动手实现一个操作系统:学完数据库原理我们也不能弄出个像样的DBMS出来:相同,学完 ...

  5. SQLite Lemon 语法分析器学习与使用

    本文是浙江大学出版社的<LEMON语法分析生成器(LALR 1类型)源代码情景分析>学习笔记. 用到的Windows下的编译器介绍MinGW(http://www.mingw.org/): ...

  6. [Swift]LeetCode385. 迷你语法分析器 | Mini Parser

    Given a nested list of integers represented as a string, implement a parser to deserialize it. Each ...

  7. 语法分析器初步学习——LISP语法分析

    语法分析器初步学习——LISP语法分析 本文参考自vczh的<如何手写语法分析器>. LISP的表达式是按照前缀的形式写的,比如(1+2)*(3+4)在LISP中会写成(*(+ 1 2)( ...

  8. org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 语法分析器在此文档中遇到多个 "64,000" 实体扩展; 这是应用程序施加的限制

    使用SAX解析XML文件.XML文件有1.5G,程序抛出了这个问题: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 语法 ...

  9. LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)

    本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说 ...

  10. LR(1)语法分析器生成器(生成Action表和Goto表)java实现(一)

    序言 : 在看过<自己实现编译器链接器>源码之后,最近在看<编译器设计>,但感觉伪代码还是有点太浮空.没有掌握的感觉,也因为内网几乎没有LR(1)语法分析器生成器的内容,于是我 ...

随机推荐

  1. 爬虫_python3_requests

    Requests 网络资源(URLs)撷取套件 改善Urllib2的缺点,让使用者以最简单的方式获取网络资源 可以使用REST操作(POST,PUT,GET,DELETE)存取网络资源 import ...

  2. Codeforces Round #273 (Div. 2)-A. Initial Bet

    http://codeforces.com/contest/478/problem/A A. Initial Bet time limit per test 1 second memory limit ...

  3. GYM 101604 || 20181010

    看着前面咕咕咕的国庆集训 难受 十月十日要萌一天哇www A.字符串 题意:给定一个字符串 问能否交换两个字符或者不交换字符,使其成为回文串 之前写的太丑 重写一遍加一堆 if 竟然过了w 思路:求出 ...

  4. Linux 标准 I/O 库

    为什么要设计标准 I/O 库? 直接使用 API 进行文件访问时,需要考虑许多细节问题,例如:read . write 时,缓冲区的大小该如何确定,才能使效率最优 read 和 write 等底层系统 ...

  5. 美可能排除中国大陆制造/生产的所有5G产品

    https://www.wsj.com/articles/u-s-considers-requiring-5g-equipment-for-domestic-use-be-made-outside-c ...

  6. iOS 面试集锦2

    4.写一个setter方法用于完成@property (nonatomic,retain)NSString *name,写一个setter方法用于完成@property(nonatomic,copy) ...

  7. javascript 写一个随机范围整数的思路

    const {random} = Math; //返回 [min,max] 的随机值 //[0,1) * (max - min + 1) => [0,max-min+1) //[0,max-mi ...

  8. VUE +element el-table运用sortable 拖拽table排序,实现行排序,列排序

    Sortable.js是一款轻量级的拖放排序列表的js插件(虽然体积小,但是功能很强大) 项目需求是要求能对element中 的table进行拖拽行排序 这里用到了sorttable Sortable ...

  9. 学c++有感

    第一次学习这么课程的时候,感觉课堂和教材的内容基本上都能接受和理解,但真正实际动手编写程序又觉得一片空白无从下手,可谓是“欲起平之恨无力.”一开始编写程序时,总是出现错误,从而产生了恐惧感,认为自己不 ...

  10. 【动态规划】bzoj2298: [HAOI2011]problem a

    建模超级妙…… Description 一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) Input 第一行一个整数n,接 ...