实验之 词法分析

一、实验目的

(1) 学会针对DFA转换图实现相应的高级语言源程序。
(2) 深刻领会状态转换图的含义,逐步理解有限自动机。
(3) 加深对词法分析原理的理解。
(4) 理解词法分析和语法分析的接口方式。

二、实验内容

编写TPL语言的词法分析程序,它从左到右逐个字符地对源程序进行扫描,分离出一个个单词,存放到数组或链表等存储结构中,作为语法分析的输入,如图1所示。
在这里插入图片描述

三、实验要求

要求实现编译器的以下功能:
(1) 能对任何TPL语言源程序进行分析。
(2) 按规则拼单词,识别出各个具有独立意义的单词,即保留字、运算符、标识符、常数、其他界符,并将识别出的单词存放到数组或链表中。
(3) 删除空白符(空格、回车符和制表符)。
(4) 列表打印源程序,打印出每个单词。
(5) 若源程序有错误,则定位错误,并指出错误原因。

四、实验原理

首先分析出TPL语言的单词种类,共五类,如表1所示,然后构造出每类单词的DFA,如图2所示,然后将所有的DFA连接在一起,构成一个整体DFA,如图6所示,根据这个整体DFA状态转换图,我们就可以用C语言直接编写出识别该语言所有单词的词法分析程序。在下面的图中,状态0为初态, 凡带双圈者均为终态,表示已识别出一个单词。代表任一字母,d 代表任一数字。状态22是识别不出单词符号的出错情况。
在这里插入图片描述
图2   TPL语言单词集的状态转换图
图2 TPL语言单词集的状态转换图

五、数据结构和函数说明

(一)数据结构

char Keyword[][7]数组,存放关键字的数组

(二)所有函数说明

int reserve(char str[])函数,测试检测出的单词是不是关键字,如果是,该函数返回该关键字的种别编码,如果不是返回-1。
void getsym(FILE *fp)函数,词法分析器的主要函数,该函数接受一个文件指针,功能为对接受的文件进行词法分析,输出单词及其种别编码。

六、实现与测试

(一)被测试的源程序1

if a>b then
    s:=a+b
else
    s:=a*b

(二)源程序1的词法分析结果

在这里插入图片描述

(三)被测试的源程序2

begin
if today <> 7 then
begin
		today:=today+1
		for i:=1 step 1 until 10 do
			jc=jc*i
end
else
begin
			today:=0
			for i:=1  step  5  until 100 do
				jc=jc*i
end
end

(四)源程序2的词法分析结果

在这里插入图片描述
在这里插入图片描述

七、词法分析程序源码

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
/*各单词种别编码如下:
*关键字:1-15  +16 -17 *18 /19 :=20 =21 <>22 >23 >=24 <25 <=26 整数27 (28 )29 标识符30
*/
#define path "C:\\Users\\86166\\Desktop\\text.txt"     //文件绝对路径
#define MAXWORD 50            //能够分析出的最长单词
#define MAXFILEWORD 500        //用于指定存放文件内容数组的最大容量
char Keyword[][7] = { "begin","end","if","then","else","not","and","or","true","false","while","do","for","step","until"
}; 
int reserve(char str[])
{
	for (int i = 0; i<15; i++)
	{
		if (strcmp(str, Keyword[i]) == 0)
		{
			return (i + 1);	//关键字的种别码为i+1 的值 
		}
	}
	return -1;                //不是关键字
}

void getsym(FILE *fp)
{
	char ch[MAXFILEWORD];
	int n = 0;
	while ((ch[n++] = fgetc(fp)) != EOF)
		;
	ch[--n] = '\0';    //如果是n的话会把EOF读进来

	int line = 1;       //记录错误行号
	int p = 0;
	while (ch[p] != '\0')
	{
		if (ch[p] == '\n')
			line++;
		while ((ch[p] == ' ') || (ch[p] == '\n') || (ch[p] == '\t'))
			p++;
		int i = 0;
		char str[MAXWORD] = {};
		int addr = 0;

		if (isalpha(ch[p]))
		{
			do {
				str[i++] = ch[p++];

			} while (isalpha(ch[p]) || isdigit(ch[p]));
			str[i] = '\0';
			addr = reserve(str);
			if (addr == -1)
				addr = 30;
			printf("%s\t%d\n", str, addr);
		}
		else if (isdigit(ch[p]))
		{
			do {
				str[i++] = ch[p++];
			} while (isdigit(ch[p]));   //出循环时,ch[p]已不是数字
			str[i] = '\0';
			addr = 27;
			printf("%s\t%d\n", str, addr);
		}
		else if (ch[p] == '<')
		{
			if (ch[p + 1] == '=') {
				str[0] = ch[p];
				str[1] = ch[p + 1];
				str[2] = '\0';
				addr = 26;
				printf("%s\t%d\n", str, addr);
				p = p + 2;
			}
			else if (ch[p + 1] == '>')
			{
				str[0] = ch[p];
				str[1] = ch[p + 1];
				str[2] = '\0';
				addr = 22;
				printf("%s\t%d\n", str, addr);
				p = p + 2;
			}
			else
			{
				str[0] = ch[p];
				str[1] = '\0';
				addr = 25;
				printf("%s\t%d\n", str, addr);
				p++;
			}
		}
		else if (ch[p] == '>')
		{
			if (ch[p + 1] == '=') {
				str[0] = ch[p];
				str[1] = ch[p + 1];
				str[2] = '\0';
				addr = 24;
				printf("%s\t%d\n", str, addr);
				p = p + 2;
			}
			else
			{
				str[0] = ch[p];
				str[1] = '\0';
				addr = 23;
				printf("%s\t%d\n", str, addr);
				p++;
			}
		}
		else if (ch[p] == ':')
		{
			if (ch[p + 1] == '=') {
				str[0] = ch[p];
				str[1] = ch[p + 1];
				str[2] = '\0';
				addr = 20;
				printf("%s\t%d\n", str, addr);
				p = p + 2;
			}
			else
			{
				printf("程序有错误,在第%d行!!,“%c”is Error。\n", line,ch[p]);
				break;
			}
		}
		else if (ch[p] == '+')
		{
			addr = 16; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == '-')
		{
			addr = 17; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == '*')
		{
			addr = 18; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == '/')
		{
			addr = 19; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == '=')
		{
			addr = 21; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == '(')
		{
			addr = 28; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else if (ch[p] == ')')
		{
			addr = 29; str[0] = ch[p]; str[1] = '\0';
			printf("%s\t%d\n", str, addr);
			p++;
		}
		else
		{
			printf("程序有错误,在第%d行!!,“%c”is Error。\n", line,ch[p]);
			break;
		}
			
		
	}
}


int main()
{
	FILE *fp = fopen(path, "r");
	if (fp == NULL)
		return 0;
	printf("路径%s下的文件经词法分析器分析后如下:\n",path);
	printf("单词    种别编码\n");
	getsym(fp);
	fclose(fp);
	return 0;
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐