【编译原理】用C/C++编写一个LL(1)解析器

任务描述

本关任务:用C/C++编写一个LL(1)解析器

相关知识

为了完成本关任务,你需要掌握:

  1. LL文法
  2. C/C++ 编程语言基础
  3. 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 *********/
}

 

posted @ 2023-12-09 14:42  寒方  阅读(160)  评论(0编辑  收藏  举报