LL(1)语法分析器 //c++实现
#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++实现的更多相关文章
- 编译原理简单语法分析器(first,follow,分析表)源码下载
编译原理(简单语法分析器下载) http://files.cnblogs.com/files/hujunzheng/%E5%8A%A0%E5%85%A5%E5%90%8C%E6%AD%A5%E7%AC ...
- Tiny语法分析器(递归下降分析法实现)
递归规约规则是这样的 program→stmt-sequence stmt-sequence→stmt-sequence;statement|statement statement→if-stmt|r ...
- 有没有好用的开源sql语法分析器? - 匿名用户的回答 - 知乎
有没有好用的开源sql语法分析器? - 匿名用户的回答 - 知乎 presto,hive,drill,calcite,sparksq
- 开源语法分析器--ANTLR
序言 有的时候,我还真是怀疑过上本科时候学的那些原理课究竟是不是在浪费时间.比方学完操作系统原理之后我们并不能自己动手实现一个操作系统:学完数据库原理我们也不能弄出个像样的DBMS出来:相同,学完 ...
- SQLite Lemon 语法分析器学习与使用
本文是浙江大学出版社的<LEMON语法分析生成器(LALR 1类型)源代码情景分析>学习笔记. 用到的Windows下的编译器介绍MinGW(http://www.mingw.org/): ...
- [Swift]LeetCode385. 迷你语法分析器 | Mini Parser
Given a nested list of integers represented as a string, implement a parser to deserialize it. Each ...
- 语法分析器初步学习——LISP语法分析
语法分析器初步学习——LISP语法分析 本文参考自vczh的<如何手写语法分析器>. LISP的表达式是按照前缀的形式写的,比如(1+2)*(3+4)在LISP中会写成(*(+ 1 2)( ...
- org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 语法分析器在此文档中遇到多个 "64,000" 实体扩展; 这是应用程序施加的限制
使用SAX解析XML文件.XML文件有1.5G,程序抛出了这个问题: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 1; 语法 ...
- LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)
本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说 ...
- LR(1)语法分析器生成器(生成Action表和Goto表)java实现(一)
序言 : 在看过<自己实现编译器链接器>源码之后,最近在看<编译器设计>,但感觉伪代码还是有点太浮空.没有掌握的感觉,也因为内网几乎没有LR(1)语法分析器生成器的内容,于是我 ...
随机推荐
- oracle数据比对工具
上半年的工作重心主要是机房搬迁,免不了要经常的数据比对,保证主备库数据一致,为了节约工作时间,提高工作效率,开发了这个数据比对小工具.用起来还可以.有需要的QQ私聊(1603039990),方便大家, ...
- 如何用node命令和webpack命令传递参数
1. 比如在项目中我们的publicPath需要根据服务器环境的变化而变化,这时我们会写一个配置文件,在webpack.config.js中读取,可以 如何才能 取到变量呢? 这里介绍一种方法: 如果 ...
- 数据库-SQL语法:LEFT JOIN
LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行.(补充:left join是一对多的关系,表里所有符合条件的记 ...
- shell脚本,一个经典题目。
[root@localhost wyb]# cat zhuijiu.sh #!/bin/bash #.写一个脚本执行后,输入名字,产生随机数01-99之间的数字. #.如果相同的名字重复输入,抓到的数 ...
- MAC的睡眠模式介绍
因为之前用的是网上流传的土法来禁止生成 sleepimage,尝到了苦头,而且2次! 大家知道 OSX 有几种睡眠模式,其中 hibernatemode 可以是 0 (传统睡眠方式,不生成 sleep ...
- 牛客网NOIP赛前集训营-普及组(第二场)和 牛客网NOIP赛前集训营-提高组(第二场)解题报告
目录 牛客网NOIP赛前集训营-普及组(第二场) A 你好诶加币 B 最后一次 C 选择颜色 D 合法括号序列 牛客网NOIP赛前集训营-提高组(第二场) A 方差 B 分糖果 C 集合划分 牛客网N ...
- (24)zabbix触发器表达式详解
概述 触发器中的表达式使用很灵活,我们可以创建一个复杂的逻辑测试监控,触发器表达式形式如下: 1 {<server>:<key>.<function>(< ...
- 条款40:明智而审慎地使用多重继承(use multiple inheritance judiciously)
NOTE: 1.多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. 2.virtual 继承会增加大小 速度 初始化(及赋值)复杂度等等成本.如果virtual base ...
- perl学习之:理解贪婪匹配和最小匹配之间的区别
正则表达式的新手经常将贪婪匹配和最小匹配理解错误.默认情况下,Perl 的正则表达式是“贪婪地”,也就是说它们将尽可能多地匹配字符. 下面的脚本打印出“matched defgabcdef”,因为它尽 ...
- spring,spring mvc,mybatis 常用注解
文章来源:https://www.cnblogs.com/hello-tl/p/9209063.html 0.在spring,soring mvc, mybistis 中的常用注解有一下 <! ...