词法分析器的设计与实现 编译原理实验报告

时间:2024.4.21

中北大学软件学院

实 验 报 告

     专    业       软件工程       

     课程名称       编译原理     

     学    号                     

     姓    名                     

辅导教师     张静         成绩           


第二篇:编译原理实验报告——词法分析器(内含源代码)


编译原理实验(一)

——词法分析器

一.  实验描述

运行环境:vc++2008

对某特定语言A ,构造其词法规则。

该语言的单词符号包括:

1该程序能识别的单词符号及类别说明表

2状态转换图

3程序流程:

词法分析作成一个子程序,由另一个主程序调用,每次调用返回一个单词对应的二元组,输出标识符表、常数表由主程序来完成。

二.  实验目的

通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。同时增强编写和调试程序的能力。

三.  实验任务

     编制程序实现要求的功能,并能完成对测试样例程序的分析。

四.  实验原理

char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符

char sign[50][10],constant[50][10];//存储标识符和常量

定义了一个Analyzer类

class  Analyzer{

public:

Analyzer(); //构造函数     ~Analyzer(); //析构函数                  

int  IsLetter(char ch); //判断是否是字母,是则返回 1,否则返回 0。     

int  IsDigit(char ch); //判断是否为数字,是则返回 1,否则返回 0。

void  GetChar(char *ch); //将下一个输入字符读到ch中。

void  GetBC(char *ch); //检查ch中的字符是否为空白,

若是,则调用GetChar直至ch进入一个非空白字符。

void  Concat(char *strTaken, char *ch); //将ch中的字符连接到strToken之后。

int  Reserve(char *strTaken); //对strTaken中的字符串查找保留字表,若是一个保留字返回它的数码,否则返回0。

void  Retract(char *ch) ; //将搜索指针器回调一个字符位置,将ch置为空白字符。

void  input();//向存放输入结果的字符数组输入一句语句。

void  display();//输出一些程序结束字符显示样式

int  analyzerSubFun();//词法分析器子程序,为了实现词法分析的主要功能。

五.  代码实现

 // cifa.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include "stdio.h"

#include "string.h"

#include "iostream"

using namespace std;

char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符

char sign[50][10],constant[50][10];//存储标识符和常量

//int Words[500][10];

char ch;//当前读入字符

int sr,to=0;//数组str, strtaken 的指针

int st=0,dcount=0;

int id=0;

static int line=1;

int h,l;

typedef struct Words   /*放置二元组*/

{

     int num;

     char letters[20];

}DS;

  DS Words[500];

typedef struct words

{

  char word[20];

  int  type;

}WORDS;

WORDS words[]={

                       {"program",0},

                      {"not",1},

                      {"begin",2},

                      {"end",3},

                      {"if",4},

                      {"then",5},

                      {"var",6},

                      {"else",7},

                      {"int",8},

                      {"while",9},

                      {"and",10},

                      {"do",11},

                      {"or",12},

                        

                         {"+",15},

                         {"-",16},

                         {"(",17},

                         {")",18},

                         {",",19},

                         {";",20},

                         {"=",21},

                         {"<",22},

                         {">",23},

                         {"*",24},

                         {"**",25},

                         {">=",26},

                         {"<=",27},

                         {"!=",28}

                      };

typedef struct keytable    /*放置关键字*/

{

    char name[20];

    int  kind;

}KEYTABLE;

KEYTABLE keyword[]={      /*设置关键字*/

                      {"program",0},

                      {"not",1},

                      {"begin",2},

                      {"end",3},

                      {"if",4},

                      {"then",5},

                      {"var",6},

                      {"else",7},

                      {"int",8},

                      {"while",9},

                      {"and",10},

                      {"do",11},

                      {"or",12},

                    };

void openfile()   /*打开文件*/

{

  cout<<"____________________________________________________"<<endl;

     cout<<"               词法分析器                   "<<endl;

     cout<<"____________________________________________________"<<endl;

     cout<<"请在本程序根目录下寻找以.txt”为结尾的文件作为词法分析对象,输入文件名"<<endl;

      FILE *fp;

  char a,filename[10];

  int n=0;

  gets(filename);

  if((fp=fopen(filename,"r"))==NULL)

    {

      printf("cannot open file.\n");

      //exit(0);

    }

  else

      while(!feof(fp))  /*文件不结束,则循环*/

       {

         a=getc(fp);    /*getc函数带回一个字符,赋给a*/

         set[n]=a;      /*文件的每一个字符都放入set[]数组中*/

         n++;

       }

  fclose(fp);            /*关闭文件*/

  set[n-1]='\0';

}

void reflesh()  /*清空strtaken数组*/

{

   to=0;   /*全局变量to是strtaken的指示器*/

   strcpy(strtaken," ");

}

void pre1()  /*预处理程序*/

{

    int i,a,b,n=0;

    do

    {

        if(set[n]=='/' && set[n+1]=='*')

          {

             a=n;     /*记录第一个注释符的位置*/

             while(!(set[n]=='*' && set[n+1]=='/'))

               { 

                    if(set[n]=='\n')

                        line++;

                    n++;

        

               }

             b=n+1;    /*记录第二个注释符的位置*/

             for(i=a;i<=b;i++)   /**/

             set[i]=' ';   /*把注释的内容换成空格,等待第二步预处理*/

          }

  

            

          

            else if(set[n]=='/' && set[n+1]=='/')

               {

              a=n;     /*记录第一个注释符的位置*/

              while(!set[n]=='\n')

                 n++;

              b=n+1;    /*记录第二个注释符的位置*/

              for(i=a;i<=b;i++)   /**/

              set[i]=' ';   /*把注释的内容换成空格,等待第二步预处理*/

             }

          n++;

    }while(set[n]!='\0');

}

void pre2()   /*预处理程序*/

{

    int j=0;

    sr=0;    /*全局变量sr是str[]的指示器*/

    do

    {

    if(set[j]==' '|| set[j]=='\n')

        {

           while(set[j]==' ' || set[j]=='\n') /*扫描到有连续的空格或换行符*/

            {   if(set[j]=='\n') line++;

                 j++;

            }

           str[sr]=' ';    /*用一个空格代替扫描到的连续空格和换行符放入str[]*/

           sr++;

        }

    else

       {

         str[sr]=set[j];  /*若当前字符不为空格或换行符就直接放入str[]*/

         sr++;

         j++;

       }

    }while(set[j]!='\0');

    str[sr]='\0';

}

char GetChar()    /*把字符读入全局变量ch中,指示器sr前移*/

{

   ch=str[sr];

   sr++;

   return(str[sr-1]);

}

void GetBC()    /*开始读入符号,直至第一个不为空格*/

{

   while(ch==' ')

     {

        ch=GetChar();

     }

}

void Concat()    /*把ch中的字符放入strtaken[]*/

{

   strtaken[to]=ch;

   to++;            /*全局变量to是strtaken的指示器*/

   strtaken[to]='\0';

}

int IsLetter()       /*判断是否为字母*/

{

   if((ch>='a' && ch<='z')||(ch>='A' && ch<='Z'))

     return(1);

   else return(0);

}

int IsDigit()      /*判断是否为数字*/

{

   if(ch>='0' && ch<='9')

      return(1);

   else return(0);

}

int Reserve()  /*对strtaken中的字符串查找保留字表,若是则返回它的编码,否则返回-*/

{

   int i,k=0;

   for(i=0;i<=12;i++)

     {

       if(stricmp(strtaken,keyword[i].name)==0)

         { k=1;

        Words[dcount].num=keyword[i].kind;

       strcpy(Words[dcount].letters,"-");

            dcount++;

           return(keyword[i].kind);

         }

     }

   if(k!=1)

      return(-1);

}

void Retract()  /*指示器sr回调一个字符位置,把ch置为空*/

{

   sr--;

   ch=' ';

}

int InsertId()

{

   int i,k;  

   for(i=0;i<id;i++)

       {

          k=strcmp(strtaken,sign[i]);

          if(k==0)

             return(i);

       }

   strcpy(sign[id],strtaken); /*插入标识符*/

   Words[dcount].num=13;

   strcpy(Words[dcount].letters,strtaken);

   id++;dcount++;

   return(id-1);

}

int InsertConst()

{

     int i,k;

     for(i=0;i<st;i++)

       {

          k=strcmp(strtaken,constant[i]);

          if(k==0)

             return(i);

       }

     strcpy(constant[st],strtaken);/*插入常数*/

      Words[dcount].num=14;

      strcpy(Words[dcount].letters,strtaken);

     st++;dcount++;

     return(st-1);

}

void analysis()

{

    int value;

    reflesh();              /*清空strtaken数组*/

    pre1();          /*预处理,使注释内容换成单个空格,放回set[]中*/

    pre2();          /*预处理,使set[]中连续的空格置换成单个空格,并把set[]的内容放到str[]中*/

    sr=0;

    GetChar();           /*把字符读入全局变量ch中,指示器sr前移*/

    GetBC();            /*读取第一个字符*/

    while(ch!='\0')      /*当不等于结束符,继续执行*/

    {

       

           if(IsLetter())//标识符和关键字判定

          {

            while(IsLetter() || IsDigit())  /*若第一个是字符,继续读取,直到出现空格*/ 

            {

                Concat();

                GetChar();       /*把字符读入全局变量ch中,指示器sr前移*/

            }

            Retract();            /*指示器sr回调一个字符位置,把ch置为空*/           

            value=Reserve();      /*对strtaken中的字符串查找保留字表,若是则返回它的编码,否则返回-*/

                     if(value==-1)        /*如果返回值是-,那就是标识符,把它输出*/

                    {

                        InsertId();       /*插入标识符*/

                    

                      }  

                    

                     reflesh();

        }

        

           else if(IsDigit())       

          {

            while(IsDigit())      /*否则,若第一个是数字,继续读取,直到出现空格*/

            {

                Concat();         /*把ch中的字符放入strtaken[]*/

                GetChar();

            }

            Retract();                /*指示器sr回调一个字符位置,把ch置为空*/

            InsertConst();            /*插入常数,返回类型为int*/

            //printf(" %s",strtaken);

            //getchar();

            reflesh();

        }

        else

           switch(ch)              /*否则,若是下面的符号*/

        {

            case'+':

            case'-':

            case'(':

            case')':

            case',':

            case';':

            case'=':

           case'<':

            case'>':

                 Concat();

                for(int c0=15;c0<=23;c0++)

                {

                     if(stricmp(strtaken,words[c0].word)==0)

                    {

                            Words[dcount].num=words[c0].type;

                      dcount++;

                      }

                   }      

                                reflesh();

                                break;

                        default:if(ch=='*')  /*如果是"*"符号,继续读取下一个*/

                                {

                                   Concat();                              /*判断是否为"**"的情况*/

                                   GetChar();

                                   if(ch==strtaken[0])

                                      Concat();

                                   else

                                      Retract();

                                           for(int c1=24;c1<=25;c1++)

                                    {

                                        if(stricmp(strtaken,words[c1].word)==0)

                                      {

                                                 Words[dcount].num=words[c1].type;

                                        dcount++;

                                       }

                                            }

                                   //printf(" %s",strtaken);

                                   //getchar();

                                   reflesh();

                                   break;

                                }

                                     else if(ch=='<' || ch=='>' || ch=='!') 

                                {

                                   Concat();                            /*判断是否为<=,>=,!=的情况*/

                                   GetChar();

                                   if(ch=='=')

                                     Concat();

                                   else

                                      Retract();

                                        for(int c2=26;c2<=28;c2++)

                                    {

                                        if(stricmp(strtaken,words[c2].word)==0)

                                      {

                                                 Words[dcount].num=words[c2].type;

                                        dcount++;

                                       }

                                            }

                                   reflesh();

                                   break;

                                }

                                else

                                { h=ch/line;

                                       l=ch%line;

                                  cout<<"Error in "<<h<<"行"<<l<<"列"<<endl;

                                  //getchar();

                                  break;

                                }

        }

                GetChar();

                GetBC();

    }

        cout<<"输出二元组:"<<endl;

        for(int d_i=0;d_i<dcount;d_i++)

            cout<<Words[d_i].num<<" "<<Words[d_i].letters<<endl;

         cout<<endl;

       cout<<"输出标识符:"<<endl;

       for(int sign_i=0;sign_i<id;sign_i++)

         cout<<sign_i<<" "<<sign[sign_i]<<endl;

         cout<<endl;

        cout<<"输出常量:"<<endl;

         for(int const_i=0;const_i<st;const_i++)

         cout<<const_i<<" "<<constant[const_i]<<endl;

         cout<<endl;

        

}

int _tmain(int argc, _TCHAR* argv[])

{

  openfile();

  analysis();

  printf("Analysis is finished!");

  getchar();

  return 0;

}

测试结果

测试语句为:Program  example ;

   var  int  j,m,n;

     Begin   /*there is * a

                     / comment*/ i:=2;

          j:=6;

          m:=3;  //there is a comment

          n:=j+m;

          If  n>=3  and  n<5

              then   j:=j-1;

     end .

结果截图:

六.  总结

我在这次词法分析器的设计过程中学到了很多东西,其中最大的收获是对于编译原理中的词法分析这一过程理解的更加清楚明了。其次,是在使用c++编程的能力有所提高。当然,在该词法分析器设计中也有一些不足的地方,比如能识别的关键字有限,并不能识别所有的关键字,识别不出字符常量等。分析结果输出方式为:用一个存放结果的字符串数组,并用指针指向它,输出结果正确,但是输出结果比较乱。不过总的来说,这次实验达到了其初衷,实现了规定的功能。

八.致谢词:

感谢xxx老师对我们的悉心教导以及提供我们这样一个学以致用的机会。通过这一阶段对编译原理课程的学习,特别是通过这次对于词法分析器的编程实践,我对于编译原理中的词法分析这一过程理解的更加清楚明了,收获很大。

更多相关推荐:
编译原理实验报告词法分析

编译原理实验报告词法分析器学院计算机科学与技术时间20xx69一问题描述选择计算机高级程序语言之一C语言运用恰当的词法分析技术线路设计和实现其对应的词法分析器提示技术线路选择如下两种之一正则式NFADFAmin...

编译原理词法分析器实验报告

曲阜师范大学实验报告计算机系20xx年级软件工程一班组日期20xx年10月17日星期日姓名陈金金同组者姓名课程编译原理成绩实验名称教师签章词法分析器一实验目的1掌握词法分析的原理2熟悉保留字表等相关的数据结构与...

编译原理词法分析实验报告1

实验1词法分析实验报告一实验目的调试并完成一个词法分析程序加深对词法分析原理的理解二实验要求1待分析的简单语言的词法beginifthenwhiledoend所有关键字都是小写2运算符和界符ltltltgtgt...

编译原理_词法分析器_实验报告

词法分析器实验报告实验目的设计编制调试一个词法分析子程序识别单词加深对词法分析原理的理解功能描述该程序要实现的是一个读单词过程从输入的源程序中识别出各个具有独立意义的单词即基本保留字标识符常数运算符分隔符五大类...

编译原理实验-词法分析器的设计

集美大学计算机工程学院实验报告一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。二、实验内容编写一个词法分…

编译原理词法分析器实验报告

塔里木大学信息工程学院编译原理实验编译原理结课论文题目词法分析器学号作者班级电话Email教师递交日期年月日塔里木大学信息工程学院编译原理实验目录摘要3涉及知识点31输入预处理32单词符号的识别状态转换图33利...

编译原理词法分析器实验报告

编译原理实验报告词法分析器院系班级姓名学号词法分析器实验报告一实验目的设计一个词法分析程序理解词法分析器实现的原理掌握程序设计语言中的各类单词的词法分析方法加深对词法分析原理的理解二实验原理词法分析是从左向右扫...

编译原理课程(词法分析器及语法分析器)

编译原理实验报告词法分析器与语法分析器I问题描述设计编制并调试一个词法分析子程序完成识别语言单词的任务设计编制调试一个语法分析程序并用它对词法分析程序所提供的单词序列进行语法检查和结构分析ii设计简要描述界面需...

编译原理词法语法分析等实验1

实验一熟悉C语言的运行环境1实验目的11熟悉利用VisualC60编辑运行C程序的方法和步骤12运行调试简单的C语言程序2实验方法及步骤21熟悉利用VisualC60编辑运行C程序的方法和步骤1打开Visual...

编译原理词法分析器和语法分析器(急急急!!!)

编译原理实验报告词法分析器实验目的1熟练掌握词法分析程序的基本原理2掌握词法分析程序的设计和实现实验内容1针对一个简化的C语言子集完成对它的词法分析程序的设计与实现2C语言子集的单词符号挤内码值程序代码incl...

实验1-3 《编译原理》词法分析程序设计方案

实验13词法分析器实验实验14编译原理S语言词法分析程序设计方案一实验目的了解词法分析程序的两种设计方法1根据状态转换图直接编程的方式2利用DFA编写通用的词法分析程序二实验内容1根据状态转换图直接编程编写一个...

C_minus语言词法分析器实验报告--宁剑

编译原理实验报告题目:C_minus语言词法分析器学院计算机科学与技术专业学号姓名指导教师20xx年xx月xx日C_minus语言词法分析器一、实验目的1.理解词法分析器的设计方法:利用DFA编写相应的程序。2…

编译原理词法分析器实验报告(32篇)