编译原理实验——词法分析器

编译原理实验——词法分析器


开发工具:Dev-C++5.11

  1. 实验说明
    1.实验题目:词法分析器的设计与实现
    2.实验目的:加深对词法分析基本理论的理解,锻炼实现词法分析器程序的实践能力
  2. 实验内容及要求
    1.相关的正规定义式如下:
    〈int〉→ digit〈int_left〉
    〈int_left〉→ ε | digit〈int_left〉
    〈id〉→ letter〈id_left〉
    〈id_left〉→ ε | letter〈id_left〉| digit〈id_left〉
    <op> → + | - | * | / | ( | )
    letter → a | b | … | z | A | B | … | Z
    digit → 0 | 1 | … | 9
    2.实验过程
    (1)按照给定的表达式的词法要求,构造分 DFA;
    (2)整合各分 DFA,构造总 DFA;
    (3)设计词法分析器算法;
    (4)根据 DFA 实现单词识别程序;
    (5)保存词法分析结果到文件。
    输入:
    (1) 输入为数学表达式,其中可能含有空格;
    (2) 运算符包括+,-,*,/,(,)。
    (3) 运算数包括自然数和变量;
    (4) 变量以字母开头,其后可以跟字母或数字。
    输出:
    输出到文本文件。每个单词输出为二元组(单词类别,单词值)。单词类别编码见下表:
编码类别说明
0算符
1常量(自然数)
2变量
  1. DFA图
    1.自然数DFA
    在这里插入图片描述
    2.标识符DFA
    在这里插入图片描述
    3.算符DFA
    在这里插入图片描述
    4.合DFA
    在这里插入图片描述
  2. 程序说明
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAX_DATA_LEN 256  //数据缓冲区长度 
#define WT_OPERATOR 0  //操作符 (算符) 
#define WT_UINT 1  //非负整数 (常量,自然数) 
#define WT_VARIABLE 2  //变量 (标识符) 

struct WORDNODE {
	unsigned short byType;  //单词类别 
	char Value[MAX_DATA_LEN];  //单词值 
	WORDNODE *pNext; //下一结点 
};


void trim(char *string) {  //清除传入字符串中的空字符 
	for (int i = 0; i < strlen(string); i ++) {
		if (string[i] == ' ') {  //发现空字符就将空字符后的字符向前填充该空字符 
			for (int j = i; j < strlen(string); j ++) {
				string[j] = string[j + 1];
			}
		}
	}
}

WORDNODE *AddNode(char c[], int nBegin, int nEnd, unsigned short byType, WORDNODE *pTail){  //添加单词结点 
	struct WORDNODE *pNode = (struct WORDNODE *)malloc(sizeof(struct WORDNODE));  //申请一个新结点 
	pNode->byType = byType;  //把单词类别添加到结点中 
	int i = 0; //这里的i暂时储存单词的长度 
	for (; nBegin <= nEnd; nBegin ++) {  //把单词添加到结点中 
		pNode->Value[i ++] = c[nBegin];  //单词长度增加 
	}
	pNode->Value[i] = '\0';  //让该单词以\0结尾 
	pNode->pNext = NULL;
	pTail->pNext = pNode;  //把结点添加到单词链表中 
	return pNode;
}

void Clear(WORDNODE *pHead) {  //清空单词链表 
	while (pHead->pNext != NULL) {
		struct WORDNODE *p = pHead->pNext;
		pHead->pNext = pHead->pNext->pNext;
		free(p);
	}
	free(pHead);  //头结点也一起释放 
}

bool IsEnglishCharOr_(char c) {  //判断是否为英文字母或下划线 
	if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
		return true;
	} 
	return false;
}

bool IsNumChar(char c) {  //判断是否为0-9整型数字 
	if (c >= '0' && c <= '9') {
		return true;
	}
	return false;
}

bool IsOperator(char c) {  //判断是否为运算符 
	if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')') {
		return true;
	}
	return false;
}

WORDNODE *IdentifyOneWord(char c[], int &nCur, WORDNODE *pTail) {  //核心函数 ,DFA 
	if (IsEnglishCharOr_(c[nCur]) || IsNumChar(c[nCur]) || IsOperator(c[nCur])) {  //输入如果不是英文字母或下划线或整型数字或运算符则算识别失败,返回NULL 
		int flag1;  //flag1代表单词的首字符类别 ,单词首字符确定后才能确定单词种别码 
		int flag2 = 0;  //flag2用来区分是常量自然数单词还是带数字的变量标识符单词 
		int start = nCur;
		if (IsEnglishCharOr_(c[nCur])) {  //打头字符为字母或下划线,表明该单词种别为变量标识符 
			flag1 = WT_VARIABLE;
			flag2 = 1;  //变量标识符可以包含数字 
		}
		if (IsNumChar(c[nCur])) {  //打头字符为数字,表明该单词种别为常量自然数 
			flag1 = WT_UINT;
		}
		if (IsOperator(c[nCur])) {  //打头字符为操作符,表明该单词种别为操作符,直接识别出,添加到单词结点中 
			flag1 = WT_OPERATOR;
			return AddNode(c, start, nCur ++, flag1, pTail);  
		}
		while (c[nCur ++] != '\0') {  //继续识别 
			if (IsEnglishCharOr_(c[nCur]) && IsNumChar(c[nCur]) && IsOperator(c[nCur])) {  //如果下一字符识别失败,则出错,直接返回NULL 
				return NULL;
			} else {
				if (IsEnglishCharOr_(c[nCur])) {   //如果确定要识别变量标识符,则下一字符满足条件后继续识别,直到下一字符不是字母、数字和下划线 
					if (flag1 == WT_VARIABLE) {
						continue;
					}
				}
				if (IsNumChar(c[nCur])) {  //如果确定要识别常量自然数,则下一字符满足条件后继续识别,直到下一字符不是数字
					if (flag2) {  //flag2=1表明当前需要识别变量标识符,这时不光要识别字母和下划线,数字也要识别进去 
						continue;
					} else {
						if (flag1 == WT_UINT) {  //flag=0表明当前只需要识别常量自然数,只识别数字即可 
							continue;
						}	
					}
				}
				break;
			}	
		}
		return AddNode(c, start, nCur - 1, flag1, pTail);	
	}
	return NULL;
} 

WORDNODE *WordAnalysis(char c[]) {  //中央调度函数 
	struct WORDNODE *pHead = (struct WORDNODE *)malloc(sizeof(struct WORDNODE));  //新建一个头结点 
	pHead->pNext = NULL;
	struct WORDNODE *pTail = pHead;
	int nCur = 0;  //nCur在IdentifyOneWord函数中使用地址作为输入,可以跨作用域自加 
	while (c[nCur] != '\0') {  
		struct WORDNODE *pNode = IdentifyOneWord(c, nCur, pTail);  //识别单词 
		if (pNode == NULL) {  //只要返回空,则说明识别失败,释放所有资源后退出 
			Clear(pHead);
			return NULL;
		}
		pTail->pNext = pNode;  //识别成功则按照数据结构添加结点 
		pTail = pNode;
	}
	return pHead;
}

int main() {
	char input[MAX_DATA_LEN];
	FILE *fp;  //建立一个文件操作指针 
	fp = fopen("result.txt","w");  //以追加的方式建立或打开result.txt,默认位置在你程序的目录下面 
	printf("请输入待分析的表达式:");
	trim(gets(input));  //清除输入字符串中的空字符 
	printf("\n");
	struct WORDNODE *pHead = WordAnalysis(input);  //中央调度函数 
	if (pHead == NULL) {
		printf("输入有误!无法识别!");
	} else {
		struct WORDNODE *p = pHead->pNext;
		while (p != NULL) {
//			printf("%d,%s\n", p->byType, p->Value);
			fprintf(fp,"%d, %s\n", p->byType, p->Value); //同输出printf一样,以格式方式输出到文本中
			p = p->pNext;
		}	
		fclose(fp); //关闭流
		printf("分析成功!详见result.txt文件!");
	}
}
  1. 程序执行与反馈
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值