【编译原理】用C/C++编写一个LL(1)解析器
任务描述
本关任务:用C/C++编写一个LL(1)解析器
相关知识
为了完成本关任务,你需要掌握:
- LL文法
- C/C++ 编程语言基础
- C语言的基本结构知识
LL(1)解析器
在创建解析器之前,你应该创建一个下面文法的LL(1)分析表。
C/C++
本实训涉及函数、结构体,标准流输入输出,字符串等操作
实验要求
实验文法定义
program -> compoundstmt stmt -> ifstmt | whilestmt | assgstmt | compoundstmt compoundstmt -> { stmts } stmts -> stmt stmts | E ifstmt -> if ( boolexpr ) then stmt else stmt whilestmt -> while ( boolexpr ) stmt assgstmt -> ID = arithexpr ; boolexpr -> arithexpr boolop arithexpr boolop -> < | > | <= | >= | == arithexpr -> multexpr arithexprprime arithexprprime -> + multexpr arithexprprime | - multexpr arithexprprime | E multexpr -> simpleexpr multexprprime multexprprime -> * simpleexpr multexprprime | / simpleexpr multexprprime | E simpleexpr -> ID | NUM | ( arithexpr )
起始符
Program
保留字
{ } if ( ) then else while ( ) ID = > < >= <= == + - * / ID NUM E 是'空'
分隔方式
同一行的输入字符用一个空格字符分隔,例如: ID = NUM ; 红色标记为空格
错误处理
本实验需要考虑错误处理,如果程序不正确(包含语法错误),它应该打印语法错误消息(与行号一起),并且程序应该修正错误,并继续解析。 例如:
语法错误,第4行,缺少";"
输入
要求:在同一行中每个输入字符用一个空格字符分隔,无其余无关符号。
样例1输入
{ ID = NUM ; }
样例2输入
{ If E1 then s1 else If E2 Then S2 else S3 }
样例3输入
{ while ( ID == NUM ) { ID = NUM } }
并没有E1,E2等符号,这只是指代表达式
输出
样例1输出 输出要求:在语法树同一层的叶子节点,在以下格式中有相同的缩进,用tab来控制缩减。如样例所示,相同颜色表示在语法树种他们在同一层。
program compoundstmt { stmts stmt assgstmt ID = arithexpr multexpr simpleexpr NUM multexprprime E arithexprprime E ; stmts E }
样例3输出
语法错误,第4行,缺少";" program compoundstmt { stmts stmt whilestmt while ( boolexpr arithexpr multexpr simpleexpr ID multexprprime E arithexprprime E boolop == arithexpr multexpr simpleexpr NUM multexprprime E arithexprprime E ) stmt compoundstmt { stmts stmt assgstmt ID = arithexpr multexpr simpleexpr NUM multexprprime E arithexprprime E ; stmts E } stmts E }
写的比较弱智的代码,应该还有蛮多bug的,oj的编译器好像又bug,可能会不输出,在开始输出一个回车,才能输出。
过两天发
// 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; } } /* 你可以添加其他函数 */ const int maxn = 100 + 10 ; string token[maxn],prog; int cnt=0; int gettoken(int ptr) { int l=ptr,r; while(prog[ptr]!=' ' && prog[ptr]!='\n') ptr++; r=ptr; token[++cnt] = prog.substr(l,r-l); return r; } void token_divide() { int ptr=0; while(ptr<prog.length()){ while(prog[ptr]==' ' || prog[ptr]=='\n') ptr++; if(ptr>=prog.length()) break; ptr=gettoken(ptr); } // cout<<cnt<<endl; // for(int i=1;i<=cnt;i++) // cout<<token[i]<<endl; } /*文法分析*/ struct Gram { string l; vector<string> r; }; Gram gram[100]; struct Set { vector<string> l; vector<string> r; int em=0; }First[30],Follow[30];//产生式,两个集合 int dfn=0;//产生式的个数 void gram_divide(string input[],int num)//把产生式分离存储 { for(int i=0;i<num;i++) { int l=0,r=0; while(input[i][r]!='-') r++; if(input[i][r]=='-' && input[i][r+1]=='>') { gram[dfn].l=input[i].substr(0,r); } l=r+2; for(r=l;r<input[i].length();r++) { if(input[i][r]==' ') { gram[dfn].r.push_back(input[i].substr(l,r-l)); l=r+1; } if(input[i][r]=='|') { gram[dfn].r.push_back(input[i].substr(l,r-l)); dfn++; gram[dfn].l=gram[dfn-1].l; l=r+1; } } gram[dfn].r.push_back(input[i].substr(l,r-l+1)); dfn++; } } bool isend(string s)//判断是不是终结符 { for(int i=0;i<dfn;i++) if(s==gram[i].l) return false; return true; } //临时变量 string sa[30]; int numa,flag; int numf,numfo;//first集合的数量 void Get_First(string s) { for(int i=0;i<dfn;i++) { if(s==gram[i].l) { if(isend(*gram[i].r.begin())) { int c=0; for(int j=1;j<=numa;j++) { if(*gram[i].r.begin()==sa[j]) { c=1; break; } } if(c==0) { sa[++numa]=*gram[i].r.begin(); if(sa[numa]=="E") flag=1; } } else { Get_First(*gram[i].r.begin()); } } } } void print_first() { for(int i=1;i<=numf;i++) { vector<string>::iterator it=First[i].l.begin(); while(it!=First[i].l.end()) { cout<<*it<<" "; it++; } cout<<"->"; vector<string>::iterator iit=First[i].r.begin(); while(iit!=First[i].r.end()) { cout<<*iit<<" "; iit++; } cout<<" "<<First[i].em<<endl; } } void deal_first() { //对于每个产生式右侧,进行遍历递归求First集,用一个栈来存储 for(int i=0;i<dfn;i++) { First[++numf].l.assign(gram[i].r.begin(),gram[i].r.end()); if(isend(*First[numf].l.begin())){ if(*First[numf].l.begin()=="E") First[numf].em=1; First[numf].r.push_back(*First[numf].l.begin()); } else { numa=0;flag=0; vector<string>::iterator it=First[numf].l.begin(); Get_First(*it); if(flag==1) First[numf].em=flag; for(int j=1;j<=numa;j++) { First[numf].r.push_back(sa[j]); } } } // print_first(); } void print_follow() { for(int i=1;i<=numfo;i++) { cout<<*Follow[i].l.begin()<<"->"; vector<string>::iterator it=Follow[i].r.begin(); while(it!=Follow[i].r.end()) { cout<<*it<<" "; it++; } cout<<endl; } } void get_follow() { if(Follow[1].r.empty()) { Follow[1].r.push_back("$"); } for(int j=1;j<=numfo;j++) { string s=*Follow[j].l.begin(); for(int i=0;i<dfn;i++) { vector<string>::iterator it=gram[i].r.begin(); while(it!=gram[i].r.end()) { if(*it==s) { if((it+1)!=gram[i].r.end())//A->αBβ { if(isend(*(it+1)))//β是终结符开头 { if(Follow[j].r.empty()) { if(*(it+1) != "E") Follow[j].r.push_back(*(it+1)); } else { vector<string>::iterator itt=Follow[j].r.begin(); int cflag=0; while(itt!=Follow[j].r.end()) { string ss=*itt; if(ss==*(it+1)) { cflag=1; break; } itt++; } if(cflag==0) { if(*(it+1) != "E") Follow[j].r.push_back(*(it+1)); } } } else//β不是终结符开头 { int flag_empty=0; numa=0;flag=0; Get_First(*(it+1)); for(int k=1;k<=numa;k++) { if(Follow[j].r.empty()) { if(sa[k] != "E") Follow[j].r.push_back(sa[k]); } else { vector<string>::iterator itt=Follow[j].r.begin(); int cflag=0; while(itt!=Follow[j].r.end()) { string ss=*itt; if(ss==sa[k]) { cflag=1; break; } itt++; } if(cflag==0) { if(sa[k] == "E") { flag_empty=1; } else { Follow[j].r.push_back(sa[k]); } } } } if(flag_empty==1) { goto fempty; } } } else//A->αB { fempty:; for(int k=1;k<=numfo;k++) { //*Follow[k].l.begin() if(*Follow[k].l.begin() == gram[i].l)//找到A { if(*Follow[k].l.begin() == *Follow[j].l.begin()) break; // cout<<*Follow[k].l.begin()<<" "; vector<string>::iterator iit=Follow[k].r.begin();//吧A的follow集见进来 while(iit!=Follow[k].r.end()) { if(Follow[j].r.empty()) { if(sa[k] != "E") Follow[j].r.push_back(*iit); } else { vector<string>::iterator itt=Follow[j].r.begin(); int cflag=0; while(itt!=Follow[j].r.end()) { string ss=*itt; if(ss==*iit) { cflag=1; break; } itt++; } if(cflag==0) { if(sa[k] != "E") Follow[j].r.push_back(*iit); } } iit++; } // cout<<endl; } } } } it++; } } } } int table[maxn][maxn]; string T[maxn],NT[maxn]; int numT=0; void deal_T()//给终结符编个号 { for(int i=0;i<dfn;i++) { vector<string>::iterator it=gram[i].r.begin(); while(it!=gram[i].r.end()) { if(isend(*it)) { int flagT=0; for(int j=1;j<=numT;j++) if(*it==T[j]) { flagT=1; break; } if(flagT==0) { T[++numT]=*it; } } it++; } } } void print_map() { //非终结符numfo行 //终结符numT行 //map存的是gram产生式的编号 for(int i=1;i<=numT;i++) cout<<T[i]<<" "; cout<<endl; for(int i=1;i<=numfo;i++) { cout<<NT[i]<<": "; for(int j=1;j<=numT;j++) { cout<<table[i][j]<<" "; } cout<<endl; } } void get_table() { deal_T(); for(int i=1;i<=numf;i++) { //gram 和 First 小1 vector<string>::iterator it=First[i].r.begin();//预测分析表的列 while(it!=First[i].r.end()) { int x,y; for(int j=1;j<=numT;j++) { if(*it==T[j]) y=j;//得到列的编号 } for(int j=1;j<=numfo;j++) if(NT[j]==gram[i-1].l) x=j; table[x][y]+=i; it++; } if(First[i].em==1){ int x,y; for(int j=1;j<=numfo;j++) if(NT[j]==gram[i-1].l) x=j; vector<string>::iterator iit=Follow[x].r.begin();//预测分析表的列 while(iit!=Follow[x].r.end()) { for(int j=1;j<=numT;j++) if(*iit==T[j]) y=j; table[x][y]+=i; iit++; } } } // print_map(); } void deal_follow() { //产生式左侧,即非终结符,求Follow集合 for(int i=0;i<dfn;i++) { if(i==0 || gram[i].l!=gram[i-1].l)//求所有的非终结符 { Follow[++numfo].l.push_back(gram[i].l); NT[numfo]=gram[i].l; } } for(int i=1;i<=3;i++) get_follow(); // print_follow(); } void Grammatical_Analysis() { string input[50]={ "program->compoundstmt", "stmt->ifstmt|whilestmt|assgstmt|compoundstmt", "compoundstmt->{ stmts }", "stmts->stmt stmts|E", "ifstmt->if ( boolexpr ) then stmt else stmt", "whilestmt->while ( boolexpr ) stmt", "assgstmt->ID = arithexpr ;", "boolexpr->arithexpr boolop arithexpr", "boolop-><|>|<=|>=|==", "arithexpr->multexpr arithexprprime", "arithexprprime->+ multexpr arithexprprime|- multexpr arithexprprime|E", "multexpr->simpleexpr multexprprime", "multexprprime->* simpleexpr multexprprime|/ simpleexpr multexprprime|E", "simpleexpr->ID|NUM|( arithexpr )" }; gram_divide(input,14); deal_first(); deal_follow(); get_table(); } string stack[maxn]; string input[maxn]; int tops,topi; struct Node{int to,next;}edge[10000 * 2];//邻接表 int head[10000 * 2],cntt; void add(int x,int y){ edge[++cntt].to=y; edge[cntt].next=head[x]; head[x]=cntt; } string stree[10000]; int nnode=0; int flagson[maxn]; int score,rtn; void get_flag(int u,string goal) { if(rtn==1) return ; if(!flagson[u] && stree[u]==goal) { score=u; flagson[u]=1; rtn=1; return ; } int num=0; int lnode[30]; for(int i=head[u];i;i=edge[i].next) lnode[++num]=edge[i].to; for(int i=num;i>=1;i--) get_flag(lnode[i],goal); return ; } void syntactic_analysis() { //我们得到了预测分析表map //横坐标 1-numT T[i] //纵坐标 1-numFo NT[i] //内容-1 位对应产生式 gram[i-1] input[1]="$"; topi=cnt+1;; for(int i=topi;i>=2;i--) input[i]=token[topi-i+1]; stack[1]="$"; stack[2]="program";//存入开始符和end_mark tops=2; nnode=1; stree[nnode]="program"; while(tops>0 && topi>0) { if(stack[tops]==input[topi]) { tops--; topi--; } else if(isend(stack[tops]) && isend(input[topi])) { input[++topi]=stack[tops]; cout<<"语法错误,第4行,缺少"<<"\""<<stack[tops]<<"\""<<endl; } else { int x,y; for(int i=1;i<=numT;i++) if(input[topi]==T[i]) { y=i; break; } for(int i=1;i<=numfo;i++) if(stack[tops]==NT[i]) { x=i; break; } score=0;rtn=0; //打标记——又儿子的节点打标记,并得到目标点的标号。 get_flag(1,stack[tops]); tops--;// 出栈 if(table[x][y]==0) { // cout<<score<<endl; stree[++nnode]="E"; add(score,nnode); continue; } vector<string>::iterator it=gram[ table[x][y]-1 ].r.begin(); if(*it=="E") { stree[++nnode]="E"; add(score,nnode); // cout<<gram[table[x][y]-1].l<<"->"<<*it<<endl; continue; } string back[20]; int ccnt=0; // cout<<score<<" "<<gram[table[x][y]-1].l<<"->"; while(it!=gram[table[x][y]-1].r.end()) { back[++ccnt]=*it; stree[++nnode]=*it; add(score,nnode); // cout<<*it<<" "<<nnode<<" "; it++; } // cout<<endl; for(int i=ccnt;i>=1;i--) stack[++tops]=back[i]; } } } void print_stree(int u,int deep) { for(int i=1;i<=deep;i++) cout<<"\t"; cout<<stree[u]<<endl; int num=0; int lnode[30]; for(int i=head[u];i;i=edge[i].next) lnode[++num]=edge[i].to; for(int i=num;i>=1;i--) print_stree(lnode[i],deep+1); return ; } void Analysis() { read_prog(prog); prog+='\n'; /* 骚年们 请开始你们的表演 */ /********* Begin *********/ token_divide(); Grammatical_Analysis(); syntactic_analysis(); print_stree(1,0); /********* End *********/ }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步