【编译原理实验】词法分析器程序设计

1.  实验内容

设计、编制并调试一个简单语言CP(Compiler Principle)的词法分析程序,加深对词法分析原理的理解。

CP语言的词法:

(1) 关键词: begin  end  if   then  else   for  while  do  and  or  not

注意:所有关键词都是小写的。

(2) 标识符ID,与标准C语言一致,即:以下划线或字母开头的字母数字下划线组成的符号串。

(3)无符号整数NUM:数字串

(4)运算符和分界符: +-*/><=:=>=<=<>++--(); #

注意::=表示赋值运算符、#表示注释开始的部分,;表示语句结束,<>表示不等关系

(5)空白符包括空格、制表符和换行符,用于分割IDNUM、运算符、分界符和关键词,词法分析阶段要忽略空白符。

 

2.  实验要求

(1) 给出各类单词符号的分类编码。

(2) 词法分析程序应该能发现输入串中的错误。

(3) 词法分析作为单独一遍,将词法分析程序输出的二元式序列保存为中间文件形式。

 

3.  设计思路

先给各类单词符号编码(见下图),以文档的形式输入将要识别的符号串,并将其存放在一个数组中,从前往后,每次根据识别到的第一个字符X做出如下操作:

(1)X为空白符:跳过X继续往下判断。

(2)X为注释符:识别注释符#,跳过其后的字符直到跳过换行符结束。

(3)X为数字符:记录此字符及其后面的字符直到遇到一个非数字符,若该非数字符为空白符、运算符或分界符,则将记录的这一段识别为数字串;否则,继续往后记录直到遇到空白符、运算符或分界符,并将记录的这一段识别为错误单词。

(4)X为运算符:判断X和其后的一个字符是否能组成运算符,若能则将X和其后的字符组合识别成运算符,否则直接识别X为运算符。

(5)X为字母符或下划线:记录此字符及其后面的字符直到遇到空白符、运算符或分界符,若记录的符号串能匹配到关键词,则将其识别为关键词,否则将其识别为标识符。

(6)X为其他符:识别为错误输入。

重复上述操作直到识别完整个输入串。


4. 
程序结构 

(1)主要数据结构:

字符数组:用于记录输入串。

map容器:记录各类单词符号及其编码,方便后续查找。

string类型变量:用于记录中间单词,方便处理。

 

(2)函数定义:

void map_init():初始化map容器,存入各类单词及其编码。

int check_num(char a):检测字符a是否是数字符。

int check_letter(char a):检测字符a是否是字母符或下划线。

int check_devide(char a):检测字符a是否是空白符、运算符、分节符或注释符。

int main():主体程序。

 

(3)算法流程:

5.  实验代码 

#include<bits/stdc++.h>
using namespace std;
char ch[200];
map<string,int> mp;
               
void map_init()//放入所有单词及编号 
{
    mp["begin"]=0;mp["end"]=1;mp["if"]=2;
    mp["then"]=3;mp["else"]=4;mp["for"]=5;
    mp["while"]=6;mp["do"]=7;mp["and"]=8;
    mp["or"]=9;mp["not"]=10;mp["+"]=11;
    mp["-"]=12;mp["*"]=13;mp["/"]=14;
    mp[">"]=15;mp["<"]=16;mp["="]=17;
    mp[":="]=18;mp[">="]=19;mp["<="]=20;
    mp["<>"]=21;mp["++"]=22;mp["--"]=23;
    mp["("]=24;mp[")"]=25;mp[";"]=26;
    mp["#"]=27;
}

int check_num(char a)//检查是否是数字 
{
    if(a>='0'&&a<='9') return 1;
    else return 0;
}

int check_letter(char a)//检查是否是字母 
{
    if((a>='a'&&a<='z')||(a>='A'&&a<='Z')||(a=='_')) return 1;
    else return 0;
}

int check_devide(char a)//检测是否是运算符或分隔符 
{
    if(a=='\n'||a=='\t'||a==' '||a=='+'||a=='-'||a=='*'||
       a=='/'||a=='>'||a=='<'||a=='='||a==':'||a=='('||
       a==')'||a==';'||a=='#')
    {
        return 1;
    }
    else return 0;
}

int main()
{
    FILE *fp;
    fp=fopen("test8.txt","r");
    if(fp==NULL)
    {
        cout<<"Open Error";
        exit(1);
    }
    ofstream ofs;
    ofs.open("result8.txt",ios::out);
    int len=0;
    while(fscanf(fp,"%c",&ch[len])!=EOF) len++;
    fclose(fp);
    string temp="";
    map_init();
    
    for(int i=0;i<len;i++)
    {
        temp="";
        if(ch[i]=='\n'||ch[i]=='\t'||ch[i]==' ') continue;   //跳过换行符、制表符和空格 
        else if(ch[i]=='#')  //跳过注释 
        {
            cout<<"<#,27>"<<endl;
            ofs<<"<#,27>"<<endl;
            while(ch[i]!='\n') i++;
        }
        else if(check_num(ch[i]))        //检测数字串 
        {
            while(check_num(ch[i]))
            {
                temp+=ch[i];
                i++;
            }
            if(check_devide(ch[i])||i>=len)//处理到分隔符或结尾 
            {
                cout<<'<'<<temp<<','<<"29"<<'>'<<endl;
                ofs<<'<'<<temp<<','<<"29"<<'>'<<endl;
                i--;//不跳过当前字符 
            }
            else
            {
                while(!check_devide(ch[i]))//跳到下一个开始位置 
                {
                    temp+=ch[i];
                    i++;
                }
                cout<<"Error:"<<temp<<endl; 
                ofs<<"Error:"<<temp<<endl; 
                i--;
            }
        }
        else if(check_devide(ch[i]))//检测运算符 
        {
            temp+=ch[i];
            map<string,int>::iterator iter=mp.find(temp);
            if(check_devide(ch[i+1]))
            {
                string temp1=temp+ch[i+1];
                map<string,int>::iterator iter1=mp.find(temp1);
                if(iter1!=mp.end())
                {
                    cout<<'<'<<temp1<<','<<iter1->second<<'>'<<endl;
                    ofs<<'<'<<temp1<<','<<iter1->second<<'>'<<endl;
                    i++;
                }
                else
                {
                    cout<<'<'<<temp<<','<<iter->second<<'>'<<endl;
                    ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl;
                }
            }
            else
            {
               ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl;
               cout<<'<'<<temp<<','<<iter->second<<'>'<<endl;
            }
        }
        else if(check_letter(ch[i]))//检测标识符或关键字 
        {
            while(!check_devide(ch[i])&&i<len)
            {
                temp+=ch[i];
                i++;
            }
            i--;
            map<string,int>::iterator iter=mp.find(temp);
            if(iter!=mp.end())
            {
                cout<<'<'<<temp<<','<<iter->second<<'>'<<endl;
                ofs<<'<'<<temp<<','<<iter->second<<'>'<<endl;
            }
            else
            {
                cout<<'<'<<temp<<','<<"28"<<'>'<<endl;
                ofs<<'<'<<temp<<','<<"28"<<'>'<<endl;
            }
        }
        else
        {
            cout<<"Error:undefined"<<endl;
            ofs<<"Error:undefined"<<endl;
        }
    }
    ofs.close();
    return 0;
}

 

posted @ 2020-11-05 11:43  雪下牧原  阅读(989)  评论(0)    收藏  举报