编译原理DFA,Lexical Analysis,LL1 c++实现
虽然这门科我挂了,但是实验还是勉强算可以的,不想捂着发霉,贴上来分享分享,不是很专业也不怎么完善,毕竟是本菜鸡纯手工写的,而且我挂了。
DFA识别字符串
任务描述
本关任务:编程实现DFA识别字符串的过程
相关知识
为了完成本关任务,你需要考虑:
(1)DFA的输入与DFA的存储:确定DFA的数据结构以及存储格式
(2)DFA的正确性检查:DFA的五元组是否正确,即对于每一个状态和每一个输入字符,它的下一个状态是否是唯一的
(3)DFA的规则字符串判定:输入(或用字符集随机生成)一个字符串,模拟DFA识别字符串的过程判定该字符串是否是规则字符串(属于DFA的语言集)。
在右侧编辑器补充代码,输出识别情况。
测试说明
平台会对你编写的代码进行测试:
DFA的开始状态固定为:X,字母表:{0,1}
测试输入:DFA五元组内容(字母表,状态集,开始状态,结束状态集,转换矩阵),多个测试字符串,Q表示DFA输入结束。
例如:输入样例
0 1
X A Y
X
Y
X 0 Y
X 1 X
Y 0 X
Y 1 Y
Q
1010
10010
预期输出:
DFA
No
Yes
前4行分别表示字母表、状态集、开始状态、结束状态集,从第5行开始为转换函数,Q输入结束,X 0 Y表示f(X,0)=Y
输出:第一行为DFA正确性判定结果:是DFA则输出“DFA”,并进行字符串识别,否则输出“Not DFA”,停止输出。
#include<iostream>
using namespace std;
string chars,stateSet,endcs;
char trans[100][100]={{}},startc;
float ISDFN=true;
void init(){
getline(cin,chars);getline(cin,stateSet);
cin>>startc;
getline(cin,endcs);getline(cin,endcs);
char a,b,c;
while(true){
cin>>a;
if(a=='Q') break;
cin>>b>>c;
if( trans[a][b]!='\0'||stateSet.find(a)==stateSet.npos||stateSet.find(c)==stateSet.npos||chars.find(b)==stateSet.npos){
ISDFN=false;
while(cin>>a) if(a=='Q') return;
return;
}
trans[a][b]=c;
}
}
int main(){
string str;char nowchar;//检测用
init();
cout<<(ISDFN? "DFA" : "Not DFA")<<endl;
if(!ISDFN) return 0;//不是DFA就结束运行
while (cin>>str){
nowchar = startc;
for(char c:str) nowchar = trans[nowchar][c];
cout<<((endcs.find(nowchar)==endcs.npos)? "No":"Yes")<<endl;
}
}
Lexical Analysis 语法分析器程序
任务描述
本关任务:用 C/C++ 编写一个 C 语言的语法分析器程序。
相关知识
为了完成本关任务,你需要掌握:1.DFA NFA,2.C/C++ 编程语言基础。3. C 语言的基本结构知识
自动机
在编译原理课堂上已经教授了大家相关知识。在完成本实训前,一定要先设计相关自动机,再开始相关功能的实现。切勿,想到哪里,就编程到哪里,以至于代码一团糟,可维护性与可读性都很差。
C/C++
本实训涉及函数、结构体,标准流输入输出,字符串等操作
C语言基本结构
C 语言子集。
第一类:标识符
第二类:常数
第三类:保留字(32)
auto break case char const continue
default do double else enum extern
float for goto if int long
register return short signed sizeof static
struct switch typedef union unsigned void
volatile while
第四类:界符 /*、//、 ()、 { }、[ ]、" " 、 ' 等
第五类:运算符 <、<=、>、>=、=、+、-、*、/、^等
所有语言元素集合在 c_keys.txt **文件中。
**注意,C_key.txt中缺少“//注释”的情况,请也映射到编号79!
编程要求
请仔细阅读该部分
输入
样例输入放在prog.txt文件中
样例1输入
int main()
{
printf("HelloWorld");
return 0;
}
输出
输出要满足以下要求
计数: <符号名,符号标号>
注意,冒号后边有一个空格
样例1输出
1: <int,17>
2: <main,81>
3: <(,44>
4: <),45>
5: <{,59>
6: <printf,81>
7: <(,44>
8: <",78>
9: <HelloWorld,81>
10: <",78>
11: <),45>
12: <;,53>
13: <return,20>
14: <0,80>
15: <;,53>
16: <},63>
注意,输出不能有多余的空格,回车等符号。请注意样例输出最后一行后是没有回车的!输出的符号都是英文的半角符号。
ERROR
本实训不考虑错误处理,我保证输入的所有代码块是合法的 C 语言代码。
// C语言词法分析器
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
using namespace std;
/* 不要修改这个标准输入函数 */
void read_prog(string& prog)
{
char c;
while(scanf("%c",&c)!=EOF){
prog += c;
}
}
/* 你可以添加其他函数 */
string keys[33]={ "",
"auto", "break","case", "char","const","continue",
"default","do" ,"double","else","enum" ,"extern",
"float", "for" ,"goto" ,"if" ,"int" ,"long","register",
"return", "short","signed","sizeof","static","struct"," switch"
,"typedef","union","unsigned","void","volatile","while"
};
string others[46]={
"-","--","-=","->","!","!=","%","%=","&","&&","&=","(",
")","*","*=",",",".","/","/=",":",";","?","[","]",
"^","^=","{","|","||","|=","}","~","+","++","+=","<",
"<<","<<=","<=","=","==",">",">=",">>",">>=","\""
};
int constnum=80,labelnum=81;
int getKey(string &word){
for(int i=1;i<33;i++) if(keys[i]==word) return i;
return 0;
}
int out_cnt;
void printOut(string &str,int key){
cout<<(++out_cnt)<<": <"<<str<<","<<key<<">"<<endl;
}
int main()
{
string prog;
read_prog(prog);
/* 骚年们 请开始你们的表演 */
/********* Begin *********/
int len=prog.length();
string word="";
for(int i=0;i<len;){
// cout<<"----------->"<<prog[i]<<endl;
if(prog[i]=='\t'||prog[i]=='\n'||prog[i]==' '){ i++; continue;}
if(isalpha(prog[i])){//是单词
int j=i+1;
while(isalpha(prog[j])||isdigit(prog[j])||prog[i]=='_') j++;
word=prog.substr(i,j-i); i=j;
int key=getKey(word);
printOut(word,key>0? key:labelnum);
}else if(isdigit(prog[i])){//是常量
int j=i+1;
while(isdigit(prog[j])||isalpha(prog[j])||prog[i]=='.') j++;
word=prog.substr(i,j-i); i=j;
printOut(word,constnum);
}else {
int key=0,is_cnt[46]={0};
if(prog[i]=='/'&&(prog[i+1]=='/'||prog[i+1]=='*')){
int j=i+2; key=79;
if(prog[i+1]=='/'){// //注释
while(true){
if(prog[j]=='\n'||prog[j]=='\0') break;
j++;
}
}else {
while(true){
if(prog[j]=='*'&&prog[j+1]=='/') break;
j++;
}
j+=2;
}
word=prog.substr(i,j-i); i=j;
printOut(word,key);
}else if(prog[i]=='%'&&(isalpha(prog[i+1]))){//%d...
int j=i+2;
while(isalpha(prog[j])||isdigit(prog[j])) j++;
word=prog.substr(i,j-i); i=j;
printOut(word,labelnum);
}else{//其它
for(int j=0;j<3;j++)
for(int k=0;k<46;k++)
if(others[k][j]!='\0'&&others[k][j]==prog[i+j]) is_cnt[k]++;
int max=0;
for(int k=0;k<46;k++) if(is_cnt[k]>max){
max=is_cnt[k];key=k;
}
if(key){
word=prog.substr(i,max);
printOut(word,key+33); i=i+max;
}else{
word=prog.substr(i,1); i++;
printOut(word,labelnum);
}
}
}
/* code */
}
/********* End *********/
}
LL1 求FIRST与FOLLOW集
任务描述
本关任务:编写程序输出文法符号的FIRST与FOLLOW集合。
相关知识
为了完成本关任务,你需要掌握:
1.计算FIRST集合
FIRST(α)={a|α, aβ,a∈T,β∈(V∪T)* }。
2.计算FOLLOW集合
FOLLOW(A)={a|S ,αAaβ, a∈T, α,β∈(V∪T)* }
编程要求
在右侧编辑器补充代码。
测试说明
平台会对你编写的代码进行测试:
用 @ 符号代替空字符ε,Q表示文法规则输入结束。
测试输入:
S:=aA|bS
A:=bA|@
Q
预期输出:
A {b,@} {#}
S {a,b} {#}
输入中,不包括多余空格,输出结果中{}内无空格,非终结符、FIRST、FOLLOW集合三个部分间只一个空格隔开。除特殊的“@,#”外,其他字符输出顺序以ASCII码从小到大顺序输出,而@,#都是作为集合的最后一个元素。
#include<iostream>
#include<string>
using namespace std;
const int MAX_MEM = 10;
string mem[130][MAX_MEM];//直接存字符
string first[30],follow[30];//字符-'A'
int cnt[130];//直接存字符
void inPut(){//输入
string str,*p_mem;
int *p_cnt;
while(cin>>str){
if(str=="Q") return;
for(int i=3;i<str.length();){
int p=str.find('|',i);
if(p==str.npos){
mem[str[0]][cnt[str[0]]++]=str.substr(i,str.length()-i);
break;
}else{
mem[str[0]][cnt[str[0]]++]=str.substr(i,p-i);
i=p+1;
}
}
}
}
bool getFirst(char c,string &out,bool *done){//递归获取first
if(done[c])return false;
bool flag=false;
done[c]=true;//标记
for(int i=0;i<cnt[c];++i){
for(int j=0;j<mem[c][i].length();++j){
if(isupper(mem[c][i][j])){
if(done[ mem[c][i][j] ]) continue;//找过了,不再找
else if(getFirst(mem[c][i][j],out,done)){
break;//找到了,找下一个
}
}else if(mem[c][i][j]!='@') {//找到了,添加,排除#空
out+=mem[c][i][j];
flag=true;
break;
}else flag=false;
}
}
return flag;
}
void getFollow(char c,string &out,bool *done){//递归获取follow
for(int i='A';i<='Z';++i){
if(mem[i][0].length()==0) continue;
if(done[i])continue;
for(int j=0;j<cnt[i];j++){
int p=mem[i][j].find(c);
if(p==mem[i][j].npos) continue;
else{
done[i]=true;//避免死循环
if(mem[i][j][p+1]=='\0'){
if(i!=c){
getFollow(i,out,done);
}else continue;//B->xA,
}else if(isupper(mem[i][j][p+1])){//B->xAC
string fst=first[mem[i][j][p+1]-'A'];
if(fst.length()>0){
int sp=fst.find('@');
if(sp!=fst.npos){
out+=fst.substr(0,sp);
getFollow(i,out,done);
} else out+=fst.substr(0);
}
}else{//找到
if(mem[i][j][p+1]!='@')
out+=mem[i][j][p+1];
}
}
}
}
}
void init(){
//first
for(int i='A';i<='Z';++i){
if(mem[i][0].length()==0) continue;
string out;bool done[133]={false};
done[i]=true;
for(int j=0;j<cnt[i];j++){
for(int k=0;k<mem[i][j].length();++k){
if(isupper(mem[i][j][k])){
if(getFirst(mem[i][j][k],out,done)) break;
}else{
out+=mem[i][j][k];
break;
}
}
}
first[i-'A']=out;
}
//follow
for(int i='A';i<='Z';++i){
if(mem[i][0].length()==0) continue;
string out;bool done[133]={false};
getFollow(i,out,done);
follow[i-'A']=out;
}
follow['S'-'A']+='#';
for(int i=0;i<cnt['S'];++i){
char c=*(mem['S'][i].end()-1);
if(isupper(c)) follow[c-'A']+='#';
}
}
void printOut(string &str){
string out;
bool alp[27]={false};
for(char c:str)
if(isalpha(c)) alp[c-'a']=true;
for(char i='a';i<='z';++i)
if(alp[i-'a']){ out+=i;out+=',';}
if(str.find('@')!=str.npos) out+='@';
if(str.find('#')!=str.npos) out+='#';
if((*(out.end()-1)==',')) out=out.substr(0,out.length()-1);
cout<<"{"<<out<<"}";
}
int main(){
inPut();
init();
for(int i='A';i<='Z';++i){
if(mem[i][0].length()==0) continue;
//M {c,@} {b}
cout<<((char)i)<<" ";
printOut(first[i-'A']);
cout<<" ";
printOut(follow[i-'A']);
cout<<endl;
}
}