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)语法分析器生成器的内容,于是我 ...
随机推荐
- 屏蔽Alt+F4关闭窗体
实现效果: 知识运用: KeyEventArgs类的Alt,Handled属性 public virtual bool Alt {get;} //获取一个值 该值指示是否曾按下Alt键 public ...
- DS博客作业08--课程总结
DS博客作业08--课程总结 1.当初你是如何做出选择计算机专业的决定的? 1.1 经过一年学习,你的看法改变了么,为什么? 1.2 你觉得计算机是你喜欢的领域吗,它是你擅长的领域吗? 为什么? 1. ...
- Javascript根据指定下标或对象删除数组元素
删除数组元素在工作中经常会用到,本文讲解一下Javascript根据下标删除数组元素的方法,需要了解的朋友可以参考下 将一下代码放在全局js文件中: Js代码 /** *删除数组指定下标或指定对象 * ...
- [HDU5360]:Gorgeous Sequence(小清新线段树)
题目传送门 题目描述: (原题英文) 操作0:输入l,r,t,线段树区间与t取min. 操作1:输入l,r,区间取最大值. 操作2:输入l,r,区间求和. 输入格式: 第一行一个整数T,表示数据组数: ...
- vue引用文件
1)css引入在vue页面中<style scoped> @import url("../assets/css/home.css");</style>2)j ...
- Shell脚本调用Oralce数据库SQL文生产日志
#!/bin/shexport LANG="zh.CN.GBK" echo -n "******************************************* ...
- HDU-1312-Black and Red
这题其实和POJ的1979是同一道题,当时POJ使用cin写的,所以读入的时候,就很正确. 这次用scanf读入的时候,就出现了问题,我们在读完宽高之后,要用getchar吸收掉回车,然后每行末尾的回 ...
- Git学习——创建与合并分支
分支概念 当前我们所在的分支是master(主分支),可以通过创建分支: git branch <branch_name> 创建完成后,可以查看当前的分支状态: git branch 当前 ...
- UNIX环境C语言进程控制
一.进程ID 进程ID即是进程标识,每一个进程都会有一个唯一的非负整数来作为它的进程ID. ID为0的进程通常是调度进程,也可称为交换进程,该进程是内核的一部分,不执行硬盘上的程序,因此也被称为系统进 ...
- CSS3的背景background
CSS3中的Background属性 background: background-image || background-position/background-size || background ...