编译原理实验——词法分析器
开发工具:Dev-C++5.11
- 实验说明
1.实验题目:词法分析器的设计与实现
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 | 变量 |
- DFA图
1.自然数DFA
2.标识符DFA
3.算符DFA
4.合DFA
- 程序说明
#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文件!");
}
}
- 程序执行与反馈