词法分析器 【编译原理】C++实现}

一、实验内容:

【问题描述】

请根据给定的文法设计并实现词法分析程序,从源程序中识别出单词,记录其单词类别和单词值,输入输出及处理要求如下:

   (1)数据结构和与语法分析程序的接口请自行定义;类别码需按下表格式统一定义;

   (2)为了方便进行自动评测,输入的被编译源文件统一命名为testfile.txt;输出的结果文件统一命名为output.txt,结果文件中每行按如下方式组织:

单词类别码 单词的字符/字符串形式(中间仅用一个空格间隔)

单词的类别码请统一按如下形式定义:

单词名称

类别码

单词名称

类别码

单词名称

类别码

单词名称

类别码

标识符

IDENFR

if

IFTK

-

MINU

ASSIGN

整型常量

INTCON

else

ELSETK

*

MULT

;

SEMICN

字符常量

CHARCON

do

DOTK

/

DIV

,

COMMA

字符串

STRCON

while

WHILETK

LSS

(

LPARENT

const

CONSTTK

for

FORTK

<=

LEQ

)

RPARENT

int

INTTK

scanf

SCANFTK

GRE

[

LBRACK

char

CHARTK

printf

PRINTFTK

>=

GEQ

]

RBRACK

void

VOIDTK

return

RETURNTK

== 

EQL

{

LBRACE

main

MAINTK

+

PLUS

!= 

NEQ

}

RBRACE

【输入形式】testfile.txt中的符合文法要求的测试程序。
【输出形式】要求将词法分析结果输出至output.txt中。
【样例输入】

const int const1 = 1, const2 = -100;

const char const3 = '_';

int change1;

char change3;

int gets1(int var1,int var2){

    change1 = var1 + var2;

    return (change1);

}

void main(){

    printf("Hello World");

    printf(gets1(10, 20));

}

【样例输出】

CONSTTK const

INTTK int

IDENFR const1

ASSIGN =

INTCON 1

COMMA ,

IDENFR const2

ASSIGN =

MINU -

INTCON 100

SEMICN ;

CONSTTK const

CHARTK char

IDENFR const3

ASSIGN =

CHARCON _

SEMICN ;

INTTK int

IDENFR change1

SEMICN ;

CHARTK char

IDENFR change3

SEMICN ;

INTTK int

IDENFR gets1

LPARENT (

INTTK int

IDENFR var1

COMMA ,

INTTK int

IDENFR var2

RPARENT )

LBRACE {

IDENFR change1

ASSIGN =

IDENFR var1

PLUS +

IDENFR var2

SEMICN ;

RETURNTK return

LPARENT (

IDENFR change1

RPARENT )

SEMICN ;

RBRACE }

VOIDTK void

MAINTK main

LPARENT (

RPARENT )

LBRACE {

PRINTFTK printf

LPARENT (

STRCON Hello World

RPARENT )

SEMICN ;

PRINTFTK printf

LPARENT (

IDENFR gets1

LPARENT (

INTCON 10

COMMA ,

INTCON 20

RPARENT )

RPARENT )

SEMICN ;

RBRACE }

【评分标准】 按与预期结果不一致的项数(每一行单词信息算一项)扣分,每项扣5%。

二、实验过程

1、根据DFA构造词法分析程序

直接编程的词法分析程序

(1)、适合词法比较简单的、手工实现、比较精简,分析速度快

(2)、与要识别的语言单词密切相关,一旦词法规则发生变化,则要重新编写程序

(3)、通过程序的控制流转移来完成对输入字符的响应,程序中的每一条语句都要与识别的单词符号有关

 2、表驱动的词法分析程序

(1)、一种典型的数据与操作的分离的工作模式,控制程序不变;不同的词法分        析器实质上是构造不同的分析表

(2)、为词法分析程序的自动生成提供了极大的方便

(3)、程序比较复杂,分析速度慢一些

3、实验步骤

1、输入:源文件字符序列testfile.txt

   任务:识别单词符号;滤过空格、注释等

   依据:TEST语言的词法规则

   输出:字符流(单词)

2、本实验我设计的词法分析器:

能够识别出保留字、标识符、单分符、双分符、常量

利用表驱动法识别注释并且滤过注释

三 实验代码

#include<string.h>
#include<string>
#include<stdio.h>
#include<fstream>
#define   MAX 22             
#define   RES_MAX   13        
#define   MAXBUF 255         

char   ch =' ';             
int Line_NO;                

struct keywords    
{
char lexptr[MAXBUF];
int token;
};
struct keywords symtable[MAX];
char  in[MAX] [10]= { "const","int","main","void","char","if","else","do","while","for","scanf","printf","return" };
char out[MAX] [10] =  { "CONSTTK","INTTK","MAINTK","VOIDTK","CHARTK","IFTK","ELSETK","DOTK","WHILETK","FORTK","SCANFTK","PRINTFTK","RETURNTK" };

void init() 
{           
	int j;
	for(j=0; j<MAX; j++)
	{
	   strcpy(symtable[j].lexptr,in[j]);
	   symtable[j].token=j;   
	}
}

int Iskeyword(char * is_res){
   int i;
   for(i=0;i<MAX;i++){
     if((strcmp(symtable[i].lexptr,is_res))==0) break;
   }
   if(i<MAX) return   symtable[i].token;
   else return 0;
}

int IsLetter(char c)
{
   if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))|| (ch == '_')) return 1;
    else return 0;
}

int IsDigit(char c){
   if(c>='0'&&c<='9') return 1;
   else return 0;
}

void analyse(FILE *fpin,FILE *fpout){
    char arr[MAXBUF];	
    int j=0;
    while((ch=fgetc(fpin))!=EOF)
	{
    if(ch==' '||ch=='\t'){}
    else if(ch=='\n')
	{Line_NO++;}
   else if(IsLetter(ch)){
       while(IsLetter(ch)||IsDigit(ch)){
            arr[j]=ch;
            j++;
            ch=fgetc(fpin);
        }
        fseek(fpin,-1L,SEEK_CUR);
        arr[j]='\0';
        j=0;
       if (Iskeyword(arr))
	   {   
	      int a;
	      a=Iskeyword(arr);
	      fprintf(fpout,"%s %s\n",out[a],arr);
			 
        }
        else if(!strcmp(arr,"const"))
        fprintf(fpout,"CONSTTK %s\n",arr);
        
		else
			fprintf(fpout,"IDENFR %s\n",arr);     
   }
   else if(int(ch)==34||int(ch)==39)
	  {
			ch=fgetc(fpin);
			char ar[MAXBUF];int i,j=0; 
            while(int(ch)!=34&&int(ch)!=39)
			{
                 ar[j]=ch;
                j++;
                ch=fgetc(fpin);
           }
            int length = strlen(ar);
            
            if(length ==1)
			{
			    fprintf(fpout,"CHARCON %s\n",ar);
            }
            else{
            	fprintf(fpout,"STRCON %s\n",ar);
            }
            for(i=0;i<length;i++)
            ar[i]='\0';
            
    }
   
   else if(IsDigit(ch)){
	int s=0;
      while(IsDigit(ch)||IsLetter(ch)){
		if(IsLetter(ch)){
            arr[j]=ch;
            j++;
            ch=fgetc(fpin);
			s=1;
		}
	 	else if(IsDigit(ch)){
			arr[j]=ch;
            j++;
            ch=fgetc(fpin);
		}		  
    }
        fseek(fpin,-1L,SEEK_CUR);
        arr[j]='\0';
        j=0;
	if(s==0)
		fprintf(fpout,"INTCON %s\n",arr) ; 
	else if(s==1)
		fprintf(fpout,"INTTK %s\n",arr) ; 
      }
	  else switch(ch)
	  {           
            case'+' :fprintf(fpout,"PLUS %s\n","+");break;
            case'-' :fprintf(fpout,"MINU %s\n","-");break;
            case'*' :fprintf(fpout,"MULT %s\n","*");break;
            case'(' :fprintf(fpout,"LPARENT %s\n","(");break;
            case')' :fprintf(fpout,"RPARENT %s\n",")");break;
            case'[' :fprintf(fpout,"LBRACK %s\n","[");break;
            case']' :fprintf(fpout,"RBRACK %s\n","]");break;                      
            case';' :fprintf(fpout,"SEMICN %s\n",";");break;
            case'/' :fprintf(fpout,"DIV %s\n","/");break;
            case',' :fprintf(fpout,"COMMA %s\n",",");break;
			case' ' :fprintf(fpout,"NEQ %s\n"," ");break; 
			case'{' :fprintf(fpout,"LBRACE %s\n","{");break;
			case'}' :fprintf(fpout,"RBRACE %s\n","}");break; 
			case'=' :{
				ch=fgetc(fpin);
				if(ch=='=')
				fprintf(fpout,"EQL %s\n","==");
				else{
					fprintf(fpout,"ASSIGN %s\n","=");
					fseek(fpin,-1L,SEEK_CUR);
				}
				
			}break;
			case'!':{
				
				ch=fgetc(fpin);
				if(ch=='=')
				fprintf(fpout,"NEQ %s\n","!=");
			}break;
				
            case'>' :{
				ch=fgetc(fpin);
		        if(ch=='=') 
				 	fprintf(fpout,"GEQ %s\n",">=");
		        else {
					fprintf(fpout,"GRE %s\n",">");
					fseek(fpin,-1L,SEEK_CUR);
				}
    		}break;

            case'<' :{
				ch=fgetc(fpin);
		        if(ch=='=') 
				 	fprintf(fpout,"LEQ %s\n","<=");
		        else
				{
				 	fprintf(fpout,"LSS %s\n","<");
				 	fseek(fpin,-1L,SEEK_CUR);}
            }break;                         
               default :break;
        }
    }}
int main()
{
   char in_fn[25],out_fn[25];
   FILE * fpin,* fpout; 
   fpin=fopen("testfile.txt","r");
   fpout=fopen("output.txt","w");
   init();
   analyse(fpin,fpout);
   fclose(fpin);
   fclose(fpout);
   printf(".....程序已分析完成分析并保存至目标文件\n");
   return 0;
}



四、运行举例

 

 testfile.txt文件:

output.txt文件:(没截全)

说明:这个是我学校实验平台的题目,代码没有写注释,看不懂的地方可以留言,有时间会把注释 加上 (如果是同学看到的话,希望不要借鉴,平台有查重)

  • 8
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值