编译原理----词法分析器实现(C)

关于编译原理和词法分析程序的介绍了要求我这里不再进行介绍。

如需了解编译原理和词法分析器的实现原理请参考我转载的一篇博客:点击打开链接

下面介绍一下我完成的词法分析器的实验要求

实验一:

目的:掌握对设计一种简单程序设计语言的完整词法分析器所必需具备的方法与技巧。

基本要求:

1)设计一个简单程序语言的单词标识及其相应种属编码,设计该语言单词的状态转换图并建立该语言的关键字表;

2)在程序中完成对该语言中标识符及整型数字的定义;

3)熟练掌握从外部文件扫描正文并读入正文符号继而组合单词的技巧,以及掌握正确识别和处理回车和换行等ASC控制码的方法,并能够对源程序进行原样列表显示;

4) 建立二元式文件,其中整型数字以二进制串形式表示;

一. 扫描器:

用C语言或PASCAL语言设计一个简单高级语言的词法分析器,该语言的所有单词种类以及被该扫描器所识别的源程序如下所示:

⑴ 单词种类(关键字30个,外加数字和标识符两类,共32类)

  1. PROGRAM          2.  VAR        3.  PROCEDURE

   4. BEGIN            5.  END        6.  IF

   7.  THEN             8.  ELSE       9.  REPEAT

10. UNTIL             11. READ        12.  WRITE

13. WRITELN          14.  FOR       15.  DO

16. 数字           17. 标识符      18.  +

19. —                 20.  *         21. /

22.  (                 23.  )         24. =

25.  ,            26.          27. < >

28.  <                 29.  >          30.  ;   

31. :=                32.  newline (凡遇到回车和换行符即Enter键时,就输出一个值为该串的二元式)

⑵ 其它符号的产生式定义:

字母→a|b|c|d|e|…|z|A|B|C|D|…|Z

数字→0|1|2|3|4|5|6|7|8|9


待识别源程序:

PROGRAM  mm;
       VAR a,b;
       PROCEDURE  next(var b);
         VAR c;
           BEGIN
             REPEAT
                b:=b+1*(b-3)/4;c:=128;
                REPEAT
                  IF c*c<>b THEN c:=bELSE c:=c+1;
                UNTIL (b/c)*c=b;        
UNTIL (c=b);
           END;
       BEGIN
           READ (a);
           WRITELN(a);IF a=1 THEN WRITE(a);
           IF a<0 THEN BEGIN
 b:=-1;WRITE(b);a:=-a;
END;
           b:=2;
           IF a<>0 THEN REPEAT
                          IF(a/b)*b=a THEN
                            REPEAT
                               BEGIN
                                WRITE(b);a:=-(a/b);
                               END;
                            UNTIL(a/b)*b<>a;
                          next(b);
                       UNTIL (b*b)>a ;
          IF a<>1 THEN WRITE(a);
       END。
设计吃法分析器首先要对要识别的字符进行分类:

我是将上述要求中:

1.所有的关键字每一个设为一类;种属编号是1-15.

2.+ 16,- 17,* 18,/ 19,(   20,)    21, =   22,     ,    23,。24,;25,:=   26,:27,>=  28,>   29,<>30,<=  31,<  32,数字    33,标示符    34.

3.其中我将关于换行的newline没有实现在程序上给予了忽略。

4.对与关键字“。”我在程序中改为了英文的点号。

下面为程序的实现代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream.h>
void writing(char ch);
void reading(char* prog);
char prog[800],token[80];
char ch;
int syn,p,m=0,n,row,sum=0;
//关键字存储
char *rwtab[15]={
				"PROGRAM","VAR","PROCEDURE","BEGIN","END","IF",
				"THEN","ELSE","REPEAT","UNTIL","READ","WRITE",
				"WRITELN","FOR","DO"
				};
 
void scaner()
{
    /*
        共分为三大块,分别是标示符、数字、符号,对应下面的 if   else if  和 else 
        
    
    */ 
    for(n=0;n<8;n++) token[n]=NULL;
	//过滤空格
    ch=prog[p++];
    while(ch==' ')
    {
        ch=prog[p];
        p++;
    }

    if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))  //可能是标示符或者变量名 
    {
        m=0;             //整形变量int
        while((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
        {
            token[m++]=ch;
            ch=prog[p++];
        }
		//识别出一个标示符
        token[m++]='\0';
		//回退一位
        p--;
        syn=34;//单纯的标示符
        for(n=0;n<15;n++)  //将识别出来的字符和已定义的标示符作比较, 
            if(strcmp(token,rwtab[n])==0)
            {	//字符串类别
                syn=n+1;
                break;
            }
    }
    else if((ch>='0'&&ch<='9'))  //数字 
    {
        {
            sum=0;
            while((ch>='0'&&ch<='9'))
            {
                sum=sum*10+ch-'0';
				//读取下一个字符
                ch=prog[p++];
            }
        }
		//回退一下
        p--;
        syn=33;//33标示数值类型
		//限制数组的大小范围
        if(sum>999999999)
            syn=-1;
    }
    else switch(ch)   //其他字符 
    {
        case'<':
			m=0;
			token[m++]=ch;
			//读取下一个字符
            ch=prog[p++];
            if(ch=='>')
            {
                syn=30;
                token[m++]=ch;
            }
            else if(ch=='=')
            {
                syn=31;
                token[m++]=ch;
            }
            else
            {
                syn=32;
                p--;
            }
            break;
        case'>':
			m=0;
			token[m++]=ch;
			//读取下一个字符
            ch=prog[p++];
            if(ch=='=')
            {
                syn=28;
                token[m++]=ch;
            }
            else
            {
                syn=29;
                p--;
            }
            break;
        case':':m=0;token[m++]=ch;
            ch=prog[p++];
            if(ch=='=')
            {
                syn=26;
                token[m++]=ch;
            }
            else
            {
                syn=27;
                p--;
            }
            break;

		case'+':syn=16;token[0]=ch;break;
        case'-':syn=17;token[0]=ch;break;
        case'*':syn=18;token[0]=ch;break;
        case'/':syn=19;token[0]=ch;break;

        case'(':syn=20;token[0]=ch;break;
        case')':syn=21;token[0]=ch;break;
		case'=':syn=22;token[0]=ch;break;
		case',':syn=23;token[0]=ch;break;
		case'.':syn=24;token[0]=ch;break;
        case';':syn=25;token[0]=ch;break;
		

        case'#':syn=0;token[0]=ch;break;
        case'\n':syn=-2;break;
        default: syn=-1;break;
    }
}

int main()
{
    p=0;
    row=1;
    cout<<"Please input string:"<<endl;
	//读取原程序逐个字符读取当读到“#”时停止读取
    //do
    //{
    //    cin.get(ch);
   //     prog[p++]=ch;
   // }
  //  while(ch!='#');
	reading(prog);
    p=0;
    do
    {
        scaner();
        switch(syn)
        {
        case 33: cout<<"("<<syn<<","<<sum<<")"<<endl; break;  //输出的是数值
        case -1: cout<<"Error in row "<<row<<"!"<<endl; break;//输出的是错误信息
        case -2: row=row++;break;
        default: cout<<"("<<syn<<","<<token<<")"<<endl;break;//输出的是标示符
        }
    }
    while (syn!=0);//结束符号时停止执行
	return 0;
}


void writing(char ch){
FILE * out;
if((out=fopen("D:/b.txt","w"))==NULL)
{
	printf("写入文件打开失败!!!!");
	exit(0);
}
fputc(ch,out);

}

void reading(char * prog)
{
		FILE * in;
	printf("请输入文件路径:\n");
	char path[100],ch;
scanf("%s",&path);
printf("%s\n",path);
if((in = fopen(path,"r"))==NULL){
	printf("文件无法打开!!!");
	exit(0);
}
int i=0;
while(!feof(in)){
	ch = fgetc(in);
	putchar(ch);
	prog[i]=ch;
	i++;
}
prog[--i]='#';
fclose(in);
}
程序的远行结果:


以上是程序的执行结果;但是程序在分析样例程序时出现了一个错误我还没有解决。希望哪位大神指出。

本程序是在我上边连接博客的一个扩展。

注:

如果需要将十进制转化为二进制可以采取下列方法进行转换:

int binary(int number){
	bool a[1000];
	int i=0;
	while(1) {
		a[i]=number%2;
		number=number/2;
		if(number==0)break;
		i++;
	 } for(int j=i; j>=0; j--)
		 printf("%d",a[j]);
	 return 0;

}


 

  • 1
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
[说明] 本文件所在目录应该包含如下文件: icrEdit\ - 目录,icrEdit编辑器的源码 演示例程\ - 目录,演示CSynEditView使用方法的例程 语法编辑类\ - 目录,CSynEditView的头文件和实现文件 使用说明.txt - 本文件,说明书 riched20.dll - CSynEditView必须的支持文件,请留意其版本号5.30.23.1209,文件大小:431888 (如果看不到文件riched20.dll,请在文件夹选项对话框的查看TAB中将隐藏文件和文件夹选为 显示文件和文件夹) [简介] CSynEditView一个支持语法编辑的类,你只要简单的将该类引入你的工程,便可轻松的获得如VC++和VB编程环境中的语法编辑能力。 [使用方法] 1、新建一个工程,在第六步将视类的基类改为CRichEditView。 2、在VC环境中选 Project->Add to Project->Files,将SynEditView.h和SynEditView.cpp引入工程。 3、将你的视类中的CRichEditView字符串全部改为CSynEditView,在你的视类头文件中用#include引入SynEditView.h文件。 4、按F7编译该工程,然后将riched20.dll复制到可执行文件的同一目录下。也就是说,如果你用Debug模式编译,将riched20.dll复制到Debug\目录下,如果你用Release模式编译,将riched20.dll复制到Release\目录下。 5、按F6执行。 [注意] 1、为了使程序能正常执行,必须保证riched20.dll同执行文件在同一目录。 2、CSynEditViw暂不支持中文,如果文本中含有中文字符,可能会引起乱码,请自行更改代码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值