编译原理:源程序的预处理及词法分析程序的设计与实现(含代码)

源程序的预处理及词法分析程序的设计与实现

写在最前面:代码按着自己的想法写的,与这个博客讲的方法有不一样的地方。
另:我的代码是从文档中读取需要处理的代码,处理完之后打印在另两个个文档,直接复制可能无法运行,需要自己创建三个文档:文档一(源代码);文档二(预处理之后的源代码);文档三(二元组)。记得检查文件位置和名字是否正确。

一、实验目的

设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。

二、 实验要求

1、实现预处理功能

源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);
然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;
把多个空白符合并为一个;
去掉注释。

2、实现词法分析功能

输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中,syn为单词种别码。Token为存放的单词自身字符串。Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。

3、待分析的C语言子集的词法(可以自行扩充,也可以按照C语言的词法定义)

1)关键字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof do
所有的关键字都是小写。

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

3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…

4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。

4、各种单词符号对应的种别码

表1 各种单词符号的种别码

单词符号种别码单词符号种别码
main1;41
if2(42
then3)43
while4int7
do5double8
static6struct9
ID25break10
NUM26else11
+27long12
-28switch13
*29case14
/30typedef15
:31char16
:=32return17
<33const18
<>34float19
<=35short20
>36continue21
>=37for22
=38void23
default39sizeof24
do40#0

5、 词法分析程序的主要算法思想

算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号。

1.主程序示意图
在这里插入图片描述

其中初值包括如下两方面:

(1) 关键字表初值
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关
键字表为一个字符串数组,其描述如下:
char *rwtab[27]={“main”,”if”,”then”,”while”,”do”,” static”,”int”,” double”,”struct”,”break”,”else”,”long”,”switch”,”case”,”typedef”,”char”,”return”,”const”,”float”,”short”,”continue”,”for”,”void”,”default”,”sizeof”,”do”};

(2) 程序中需要用到的主要变量:syn,token和sum。

2.扫描子程序的算法思想

首先设置三个变量:
token用来存放构成单词符号的字符串;
sum用来存放整型单词;
syn用来存放单词符号的种别编码。
扫描子程序主要部分流程如图2所示。
在这里插入图片描述

三、实验代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char key[26][20] = {"main","if","then","while","do"," static","int"," double","struct","break","else","long","switch","case","typedef","char",
"return","const","float","short","continue","for","void","sizeof","default","do"};
//da yin
void p(char* str)
{
	printf("%s\n",str);
}
//shan chu kong ge
void deblank(char *str)
{
	char s[10000];
	char s1[10000]={NULL};
	int i=0,j=0,next=0;
	strcpy(s,str);
	while(s[j]!=EOF)
	{
		s1[i]=s[j];
		i++;
		j++;
		if(s[j-1]==' ')
		{
			next=j;
			while(s[next]==' ')next++;
			j=next;
		}
//		if(s[j]!=' ')
//		{
//			str[i]=s[j];
//			i++;
//			j++;
//		}
//		else
//		{
//			str[i]=s[j];
//			i++;
//			j++;
//			next=j;
//			while(s[next]==' ')next++;
//			j=next;
//		}
	}
//	while(str[i++]!='\0')str[i-1]='\0';
	// p(s1);
	strcpy(str,s1);
}
//shan chu zhu shi
void zhushi(char *str)
{
	int i,j;
	char s[10000];
	strcpy(s,str);
	for(i=0,j=0;s[i]!=EOF;i++,j++)
	{
		if(s[i]=='/'&&s[i+1]=='/')
		{
			str[j]=' ';
			while(s[i]!='\n')i++;
		}
		else
		{
			str[j]=s[i];
		}
	}
	strcpy(s,str);
	for(i=0,j=0;s[i]!=EOF;i++,j++)
	{
		if(s[i]=='/'&&s[i+1]=='*')
		{
			str[j]=' ';
			while(s[i]!='*'||s[i+1]!='/')
			{
				i++;
				if(s[i]==EOF)
				{
					printf("注释有误。\n");
					system("pause");
					exit(0);
				}
			}
			i=i+1;
		}
		else
		{
			str[j]=s[i];
		}
	}
	deblank(str);
//	p(str);
}
//shan chu hui che haun hang
void enter(char *str)
{
	int i,j=0;
	char s[10000];
	strcpy(s,str);
	for(i=0;s[i]!=EOF;i++,j++)
	{
		if(s[i]=='\n'||s[i]=='\r'||s[i]=='\t')
		{
			s[i]=' ';
			str[j]=s[i];
		}
		else
		{
			str[j]=s[i];
		}
	}
	// p(str);
}
int zm(char a)
{
	if(a>='a'&&a<='z'||a>='A'&&a<='Z')
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
int sz(char a)
{
	if(a>='0'&&a<='9')
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void xr(char *a,int b)
{
	FILE *fp;
	fp=fopen("D:\\app\\vscode\\codes\\compilation\\exp1-3.txt","a");
	if(fp==NULL)
	{
		printf("fail to open the file!\n");
		system("pause");
		exit(0);
	}
	if(b>=0)
	{
		fprintf(fp, "<%s,%d>\n", a, b);
	}
	else
	{
		fprintf(fp, "无法识别\"%c\"\n",a[0]);
	}
	fclose(fp);
}
void id(char *a)
{
	int i,b;
	for(i = 0; i<26;i++)
	{
		if(strcmp(a,key[i]) == 0)
		{
			if(i<24) 
			{
				b=i+1;
			}
			else
			{
				if(i==24) b=39;
				if(i==25) b=40;
			} 
			xr(key[i],b);
			return;
		}
	}
	xr(a,25);
}
void cffx()
{
	FILE *fp;
	char ch;
	char str[10000];
	char word[50];
	char numb[50];
	int i,j,k;
	fp=fopen("D:\\app\\vscode\\codes\\compilation\\exp1-2.txt","r");
	if(fp==NULL)
	{
		printf("fail to open the file!\n");
		exit(0);
	}
	i=0;
	while((ch=fgetc(fp))!=EOF)
	{
		str[i]=ch;
		i++;
	}
	for(i=0,j=0,k=0;str[i]!=NULL;i++)
	{
		int a,b;
		a=zm(str[i]);
		if(a==1)
		{
			word[j]=str[i];
			j++;
			for(;;)
			{
				i++;
				a=zm(str[i]);
				b=sz(str[i]);
				if(a==1||b==1)
				{
					word[j]=str[i];
					j++;
				}
				else
				{
					id(word);
					memset(word,0,sizeof(word));
					j=0;
					break;
				}
			}
			i--;
			continue;
		}
		a=sz(str[i]);
		if(a==1)
		{
			numb[k]=str[i];
			k++;
			for(;;)
			{
				i++;
				a=sz(str[i]);
				if(a==1||str[i]=='e'||str[i]=='E'||str[i]=='.')
				{
					if(str[i]=='.'&&sz(str[i+1])==0)
					{
						printf("小数点错误。\n");
						system("pause");
						exit(0);
					}
					numb[k]=str[i];
					k++;
				}
				else
				{
					xr(numb,26);
					memset(numb,0,sizeof(numb));
					k=0;
					break;
				}
			}
			i--;
			continue;
		}
		if(str[i]==' ')
		{
			continue;
		}
		switch(str[i])
		{
			case '+': xr((char*)"+",27);break;
			case '-': xr((char*)"-",28);break;
			case '*': xr((char*)"*",29);break;
			case '/': xr((char*)"/",29);break;
			case '=': xr((char*)"=",38);break;
			case ';': xr((char*)";",41);break;
			case '(': xr((char*)"(",42);break;
			case ')': xr((char*)")",43);break;
			case '#': xr((char*)"#",0);break;
			case '.': xr((char*)".",-1);break;
			case '{': xr((char*)"{",-1);break;
			case '}': xr((char*)"}",-1);break;
			case '%': xr((char*)"%",-1);break;
			case '\"': xr((char*)"\"",-1);break;
			case '\\': xr((char*)"\\",-1);break;
			case ',': xr((char*)",",-1);break;
			case '|': 
					if(str[i+1] == '|')
					{
						i++;
						xr((char*)"||",-1);
					}
					else
					{
						xr((char*)"|",-1);
					}
					break;
			case '&': 
					if(str[i+1] == '&')
					{
						i++;
						xr((char*)"&&",-1);
					}
					else
					{
						xr((char*)"&",-1);
					}
					break;
			case ':': 
					if(str[i+1] == '=')
					{
						i++;
						xr((char*)":=",32);
					}
					else
					{
						xr((char*)":",31);
					}
					break;
			case '<':
					if(str[i+1] == '>')
					{
						i++;
						xr((char*)"<>",34);
					}
					else if(str[i+1] == '=')
					{
						i++;
						xr((char*)"<=",35);
					}
					else
					{
						xr((char*)"<",33);
					}
					break;
			case '>': 
					if(str[i+1] == '=')
					{
						i++;
						xr((char*)">=",37);
					}
					else
					{
						xr((char*)">",36);
					}
					break;
			// default : xr(&str[i],-1);break;
		}	
	}
}

int main()
{
	FILE *fp;
	char ch;
	char str[10000];
	int i=0; 
	fp=fopen("D:\\app\\vscode\\codes\\compilation\\exp1-1.txt","r");
	if(fp==NULL)
	{
		printf("fail to open the file!\n");
		exit(0);
	}
	else
	{
		// printf("The file is open!\n");
		while((ch=fgetc(fp))!=EOF)
		{
			str[i]=ch;
			i++;
//			putchar(ch);
		}
		// printf("%s\n",str);
		
//		读取文件内容:
//      1. 
//		while((ch=fgetc(fp))!=EOF)putchar(ch);
//		2. 
//		ch=fgetc(fp);
//		while(ch!=EOF)
//		{
//			putchar(ch);
//			ch=fgetc(fp);
//		}
//		3. 
//		while(!feof(fp))printf("%c",fgetc(fp));
        
//	    while((ch=getchar())!='#')
//        {
//        	fputc(ch,fp);
//		}

        
        zhushi(str);
        enter(str);
		deblank(str);
//		fclose(fp);
	}
	FILE *fpp;
	fpp=fopen("D:\\app\\vscode\\codes\\compilation\\exp1-2.txt","w");
	if(fpp==NULL)
	{
		printf("fail to open the file!\n");
		exit(0);
	}
	else
	{
		// printf("The file is open!\n");
		fputs(str,fpp);
		fclose(fpp);
		fclose(fp);
	}
	FILE *file;
	file = fopen("D:\\app\\vscode\\codes\\compilation\\exp1-3.txt","w");
	fclose(file);
	cffx();
	printf("处理完成\n");
	system("pause");
	return 0;
} 

运行结果:
例子:
/main/
if(a>3)
{
a–;//a>3
}
控制台:
在这里插入图片描述
文档一(源代码):
在这里插入图片描述
文档二(预处理之后的代码):
在这里插入图片描述
文档三(二元组):
在这里插入图片描述
好了,结束,如果不需要中间结果文档二,可以直接注释掉。

  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip实验一 源程序预处理词法分析程序设计等.zip
以下是一个简单的基于Pascal子集的词法分析程序: ```pascal program Lexer; const MAXLEN = 100; type TokenType = (ID, NUM, PLUS, MINUS, MULT, DIV, LPAREN, RPAREN, ASSIGN, SEMI, ERROR, EOF); // 定义Token类型 var TokenString: string; Token: TokenType; Line: string; LineIndex: integer; function GetChar: char; begin if LineIndex <= Length(Line) then begin GetChar := Line[LineIndex]; LineIndex := LineIndex + 1; end else GetChar := #0; end; procedure GetToken; var Ch: char; begin TokenString := ''; Token := ERROR; while (Token = ERROR) and (LineIndex <= Length(Line)) do begin Ch := GetChar; if Ch in ['a'..'z', 'A'..'Z'] then begin Token := ID; while Ch in ['a'..'z', 'A'..'Z', '0'..'9'] do begin TokenString := TokenString + Ch; Ch := GetChar; end; LineIndex := LineIndex - 1; end else if Ch in ['0'..'9'] then begin Token := NUM; while Ch in ['0'..'9'] do begin TokenString := TokenString + Ch; Ch := GetChar; end; LineIndex := LineIndex - 1; end else if Ch = '+' then Token := PLUS else if Ch = '-' then Token := MINUS else if Ch = '*' then Token := MULT else if Ch = '/' then Token := DIV else if Ch = '(' then Token := LPAREN else if Ch = ')' then Token := RPAREN else if Ch = '=' then Token := ASSIGN else if Ch = ';' then Token := SEMI; end; end; begin Line := 'a := 2 + 3;'; LineIndex := 1; repeat GetToken; writeln(TokenString); until Token = EOF; end. ``` 以上代码实现一个简单的词法分析程序,可以识别出变量名、数字、加减乘除、括号、赋值符号和分号。你可以根据需要修改 `Line` 的值来测试不同的输入。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

俊夫小瞳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值