⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bianyi1.cpp

📁 编译原理的第一个实验
💻 CPP
字号:
//编写一个词法分析程序,对给出的程序段进行词法分析,
//要求输出以文件形式存放的TOKEN串和符号表
#include<stdlib.h>
#include<stdio.h>
#include<string.h>

#define FILENAMELEN     20

void scanner(FILE* fp);
void intdeal(char *buffer);
void errordeal(char error,int lineno);
int search(char *buf,int type,int command);
int searchID(char* buffer);

int main(void)
{
    FILE* rdfp;
    FILE* wrfp;
    int i;
    char fileName[FILENAMELEN];
    char *key[]={"", "do", "else", "if", "and", "int", "then", "while"}; //关键字
	char *limit[]={" ", "(", ")", ":", ";", "{", "}", ">", "=", "<", "+"};//运算、限界符

    wrfp = fopen("keyword.txt", "w");
    for (i = 0; i < 8; i++)
        fprintf(wrfp, "%s\n", key[i]);
	fclose(wrfp);
	wrfp = fopen("limit.txt", "w");
	for (i = 0; i < 11; i++)
		fprintf(wrfp, "%s\n", limit[i]);
	fclose(wrfp);

	printf("请输入文件名:\n");
	scanf("%s", fileName);
	rdfp = fopen(fileName, "r");
	scanner(rdfp);

	return 0;
}


void scanner(FILE* fp)
{
	int i;
	char array[30];
	int line = 0;      //记录行数
	int errorno = 0;
	int result;            //搜索结果
	int count;
	char ch;
	char* word;
	char filename[FILENAMELEN];
	FILE* outputfp = fopen("token.txt", "w");          //输出的文件的文件指针,初始化一下
	fclose(outputfp);
	FILE* outputfp1 = fopen("identifier.txt", "w");          //输出的文件的文件指针,初始化一下
	fclose(outputfp1);

	while (!fp){
		printf("不能打开指定的文件,请确认输入的文件名正确!\n");
		putchar('\n');
		printf("请重新输入文件名:");
		scanf("%s", filename);
		fp = fopen(filename, "r");
	}

	ch = (unsigned char)fgetc(fp);
	while (ch != EOF) {
		//按字符依次扫描源程序,直至结束
		i=0;

		//以字母和下划线开头
		if (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '_')){
			while(((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '_') || ((ch >= '0') && (ch <= '9'))){
				array[i++]=ch;
				ch = fgetc(fp);
			}
			word=(char*)malloc((i + 1) * sizeof(char));
			memcpy(word, array, i);
			word[i] = '\0';
			intdeal(word);
			if (ch != EOF){
				fseek(fp, -1, SEEK_CUR);
			}
		}

		//以数字开头
		else if ((ch >= '0') && (ch <= '9')){
			while ((ch >= '0') && (ch <= '9')){
				array[i++]=ch;
				ch = fgetc(fp);
			}
			word=(char*)malloc((i + 1) * sizeof(char));
			memcpy(word, array, i);
			word[i] = '\0';
			intdeal(word);
			if (ch != EOF){
				fseek(fp, -1, SEEK_CUR);                  //to do
			}
		}

		//消除空格和制表符
		else if((ch == ' ') || (ch == '\t'))
			;

		//消除回车并记录行数
		else if(ch == '\n')
			line++;

		//消除注释
		else if (ch == '/'){
			ch = fgetc(fp);
			if (ch == '='){     //判断是否为‘/=’号
				outputfp = fopen("token.txt", "a");
				fprintf(outputfp, "/=\t4\t\t\t13\n");
				fclose(outputfp);
			}
			else if (ch != '*'){ //若为除号,写入输出文件
				outputfp = fopen("token.txt", "a");
				fprintf(outputfp, "/\t4\t\t\t13\n");
				fclose(outputfp);
				fseek(fp, -1, SEEK_CUR);
			}
			else if (ch == '*'){   //若为注释的开始,则忽略注释内容
				count=0;
				ch = fgetc(fp);
				while(count!=2){      //当扫描到‘*’且紧接着下一个字符为‘/’才是注释的结束
					count=0;
					while(ch != '*')
						ch = fgetc(fp);
					count++;
					ch = fgetc(fp);
					if(ch=='/')
						count++;
					else
						ch = fgetc(fp);
				}
			}
		}

		//消除包含在双引号中的字符串常量
		else if (ch == '"'){
			outputfp = fopen("token.txt", "a");
			fprintf(outputfp, "%c\n", ch);
			fclose(outputfp);
			while (ch != '"')
				ch = fgetc(fp);
			fprintf(outputfp, "%c\n", ch);
			fclose(outputfp);
		}

		//首字符为其它字符,即运算限界符或非法字符
		else {
			errorno = 0;

			array[0] = ch;
			ch = fgetc(fp);              //再读入下一个字符,判断是否为双字符运算、限界符
			if (ch != EOF){
				array[1]=ch;
				word = (char*)malloc(3 * sizeof(char));
				memcpy(word, array, 2);
				word[2] = '\0';
				//先检索是否为双字符运算、限界符
				result = search(word, 2, 1);
				if (result == 0){       //若不是
					word = (char*)malloc(2 * sizeof(char));
					memcpy(word, array, 1);
					word[1] = '\0';
					result = search(word, 2, 1);         //检索是否为单字符运算、限界符
					if (result == 0){       //若还不是,则为非法字符
						errordeal(array[0], line);        
						errorno++;
						fseek(fp, -1, SEEK_CUR);
					}
					else {        //若为单字符运算、限界符,写入输出文件并将扫描文件指针回退一个字符
						outputfp = fopen("token.txt", "a");
						fprintf(outputfp, "%d\n", result);
						fclose(outputfp);
						fseek(fp, -1, SEEK_CUR);
					}
				}
				else {      //若为双字符运算、限界符,写入输出文件
					outputfp = fopen("token.txt", "a");
					fprintf(outputfp, "%d\n", result);
					fclose(outputfp);
				}
			}
			else {          //若读入的下一个字符为文件结束符
				word = (char*)malloc(2 * sizeof(char));
				memcpy(word, array, 1);
				word[1] = '\0';
				result = search(word, 2, 1);          //只考虑是否为单字符运算、限界符
				if (result == 0)   //若不是,转出错处理
					errordeal(array[0], line);
				else {             //若是,写输出文件
					outputfp = fopen("token.txt", "a");
					fprintf(outputfp, "%d\n", result);
					fclose(outputfp);
				}
			}
		}
		ch = fgetc(fp);
		}

		fclose(fp);
}

void intdeal(char *buffer)
{
    FILE* fp1;
	FILE* fp2;
    int result;
    result = search(buffer, 1, 1);        //先查关键字表
    fp1 = fopen("token.txt", "a");
	fp2 = fopen("identifier.txt", "a");
    if (result != 0)         //找到了,是关键字
        fprintf(fp1, "%d\n", result);
    else{    //若找不到,则非关键字
		if ((buffer[0] >= '0') && (buffer[0] <= '9'))
			fprintf(fp1, "%d\t%d\n", result + 1, buffer);
		else
			fprintf(fp1, "%d\t%d\n", result, buffer);
		//以下代码建立符号表
		if((((buffer[0] >= 'A') && (buffer[0] <= 'Z')) || ((buffer[0] >= 'a') && (buffer[0] <= 'z')) || (buffer[0] == '_')) && (searchID(buffer) != 0) )
			fprintf(fp2, "%s\t%d\n", buffer, result);
    }
    fclose(fp1);
	fclose(fp2);

}


void errordeal(char error,int lineno)
{
    printf("\nerror: %c, line: %d", error, lineno);
}

int search(char *buf,int type,int command)
{
    int number = 0;
    FILE* fp;
    char ch;
    char temp[30];
    int i = 0;

    switch (type){
	case 1:          //打开关键字表供查阅
        fp = fopen("keyword.txt", "r");
        break;
	case 2:          //打开限界符、运算符表供查阅
        fp = fopen("limit.txt", "r");
        break;
    }
    ch = fgetc(fp);
    while (ch != EOF){
        while (ch != '\n'){
            temp[i++] = ch;
            ch = fgetc(fp);
        }
        temp[i] = '\0';
        i = 0;
        number++;
        if (strcmp(temp, buf) == 0){
            fclose(fp);
            return number;     //若找到,返回在相应表中的序号
        }
        else
            ch = fgetc(fp);
    }        //外层while循环
    if (command == 1){
        fclose(fp);
        return 0;           //找不到
    }
    switch (type){
	case 1:
        fp = fopen("keyword.txt", "r");
        break;
	case 2:
        fp = fopen("limit.txt", "r");
        break;
    }

    fclose(fp);
    return (number + 1);
}

int searchID(char* buffer)             //搜索符号表看标识符是否已经存在
{
	int i;
	char id[20] = {'\0'};
	char temp[20] = {'\0'};
	FILE* fp = fopen("identifier.txt", "r");

	strcpy(temp, buffer);
	while(fscanf(fp, "%s %d", id, &i) != EOF){
		if (strcmp(id, temp) == 0)
			return 0;                         //find
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -