实验1 词法分析

更新时间:2024-05-07 10:11:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

河南工业大学实验报告

课程名称 编译原理 _ 实验项目 实验一 词法分析 院 系____信息科学与工程学院____ 专业班级 计科F1402班 姓 名 苏朋辉 学 号 201416010211 指导老师 侯惠芳 日 期 2017.4.20 批改日期 成 绩

一.实验目的

1. 深入理解有限自动机及其应用

2. 掌握根据语言的词法规则构造识别其单词的有限自动机的方法 3.基本掌握词法分析程序的开发。

二.实验内容及要求

(题一)

编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)(具体参照实验指导中的要求) (题二)

根据给出能够识别某语言中各类单词的DFA:识别的单词种类可以有:标识符、数字串、单分界符、双分界符等。 构造识别单词的自动机

根据构成规则对程序语言的单词按类构造出相应的状态转换图 对各类单词的状态转换图合并,构成一个能识别语言所有单词的状态转换图。合并步骤为:

(1) 将各类单词的状态转换图的初始状态合并为一个唯一的初态; (2) 化简调整状态冲突和对冲突状态重新编号; (3) 如有必要,增加出错状态。

用数据中心法实现有限自动机,生成词法分析程序。

注:状态转换表法又称数据中心法,是把状态转换图看作一种数据结构(状态转换表),由控制程序控制字符在其上运行,从而完成词法分析。用转换表的优点是程序短,但占存储空间多,直接转向法的优缺点正好与此相反。 (题三)

根据给出能够识别某语言中各类单词的DFA:根据给出能够识别某语言中各类单词的DFA:识别的单词种类可以有:标识符、数字串、单分界符、双分界符等。 构造识别单词的自动机

根据构成规则对程序语言的单词按类构造出相应的状态转换图 对各类单词的状态转换图合并,构成一个能识别语言所有单词的状态转换图。合并步骤为:

(1) 将各类单词的状态转换图的初始状态合并为一个唯一的初态; (2) 化简调整状态冲突和对冲突状态重新编号; (3) 如有必要,增加出错状态。

用直接转向法实现有限自动机,生成词法分析程序

注:直接转向法又称程序中心法,是把状态转换图看成一个流程图,从状态转换图的初态开始,对它的每一个状态结点都编一段相应的程序。

(题四)

编制一个能够分析三种整数、标识符和主要关键字的词法分析器。 实验要求

1根据以下的正规式,编制正规文法,画出状态图 标识符 <字母>(<字母>|<数字字符>)* 十进制整数 0 | (1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* 八进制整数 0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)* 十六进制整数 0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)* 关键字 if then else while do

2根据状态图,设计词法分析函数int scan( ),完成以下功能: 1) 从键盘读入数据,分析出一个单词。 2) 返回单词种别(用整数表示),

3) 返回单词属性(不同的属性可以放在不同的全局变量中)。 3编写测试程序,反复调用函数scan( ),输出单词种别和属性。

三.实验过程

3.1 词法分析器的功能和输出格式

词法分析器的功能是输入源程序,输出单词符号。词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。本实验中,采用的是一类符号一种别码的方式。

如源程序为C语言。输入如下一段: main() {

int a,b,c=2; a = 10; b = a + 20; c = a + b/c; }#

3.2 单词的BNF表示

<标识符>-> <字母><字母数字串>

<字母数字串>-><字母><字母数字串>|<数字><字母数字串>| <下划线><字母数字串>|ε

<无符号整数>-> <数字><数字串> <数字串>-> <数字><数字串> |ε <加法运算符>-> + <减法运算符>-> -

<大于关系运算符>-> >

<大于等于关系运算符>-> >= 由此可知,需将单词分为五种: 关键字1 printf main int if then else return …. 标识符2 a b c student sum k m …. 常数3 0 1 2 3 4 5 6 7 8 9 运算符4 + _ * / = > < >= <= != 分隔符5 , ; ( ) { } …. 3.3 “超前搜索”方法

词法分析时,常常会用到超前搜索方法。如当前待分析字符串为“a>+”,当前字符为’>’,此时,分析器倒底是将其分析为大于关系运算符还是大于等于关系运算符呢?显然,只有知道下一个字符是什么才能下结论。于是分析器读入下一个字符’+’,这时可知应将’>’解释为大于运算符。但此时,超前读了一个字符’+’,所以要回退一个字符,词法分析器才能正常运行。在分析标识符,无符号整数等时也有类似情况。

3.4部分函数说明

1. int lookup(char *TOKEN) 关键字匹配函数,查询所述程序中的关键字 2. void out(int c,char *TOKEN) 输出函数

3. void scanner(FILE *fp) 扫描函数,扫描程序中的字符串并调用lookup函数检查是否是关键字,再调用out函数输出二元组

4.fseek(fp,-1,1) 回退一个字符

5.zimu(ch) 字母判断函数,若ch指的是字母,返回非0,否则返回0 6.shuzi(ch) 数字判断函数,若ch指的是数字,返回非0,否则返回0 7.fgetc(fp) 从数据流中区下一个字符

8.fopen 文件打开函数,返回指向文件第一个字符的指针 3.5源代码如下:

#include #include #include #include //定义关键字

char *table[7]={\ bool zimu(char ch)//判断是否为字母 { if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z') return true; else

return false; }

//判断是否为数字 bool shuzi(char ch) { if(ch>='0'&&ch<='9') return true; else return false; }

int lookup(char *TOKEN) //关键字匹配函数,查询所述程序中的关键字 { int m,i; for(i=0;i<6;i++) { if((m=strcmp(TOKEN,table[i]))==0) return 1; } return 0; }

void out(int c,char *TOKEN) //输出函数 { printf(\ void scanner(FILE *fp) //扫描函数 {

char TOKEN[20]={'\\0'}; char ch; int i; ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符 if(zimu(ch)) //判断该字符是否是字母,若ch指的是字母,返回非0,否则返回0 { TOKEN[0]=ch; ch=fgetc(fp); //fgetc(fp)从数据流中区下一个字符 i=1; while(shuzi(ch)|| zimu(ch)) //判断该字符是否是字母或数字 { TOKEN[i]=ch; ch=fgetc(fp); i++; } fseek(fp,-1,1); if(lookup(TOKEN)) //判断是关键字还是普通的标识符 out(1,TOKEN); else

out(2,TOKEN); } else if(shuzi(ch)) { TOKEN[0]=ch; ch=fgetc(fp); //fgetc(fp)从数据流中区下一个字符 i=1; while(shuzi(ch)) //判断该字符是否是字母或数字 { TOKEN[i]=ch; ch=fgetc(fp); i++; }

fseek(fp,-1,1); out(3,TOKEN); }

//判断运算符并输出 else if(ch=='+'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='-'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='*'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='/'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='='){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='>'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='<'){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='>='){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='<='){ TOKEN[0]=ch; out(4,TOKEN); } else if(ch=='!='){ TOKEN[0]=ch; out(4,TOKEN); } //判断分隔符并输出 else if(ch==','){ TOKEN[0]=ch; out(5,TOKEN); } else if(ch==';'){ TOKEN[0]=ch; out(5,TOKEN); } else if(ch=='{'){ TOKEN[0]=ch; out(5,TOKEN); } else if(ch=='}'){ TOKEN[0]=ch; out(5,TOKEN); } else if(ch=='('){ TOKEN[0]=ch; out(5,TOKEN); } else if(ch==')'){ TOKEN[0]=ch; out(5,TOKEN); } }

main() { FILE *fp;//读取文件内容,并返回文件指针,该指针指向文件的第一个字符 if((fp=fopen(\ { fprintf(stderr,\ exit(1); } do

{ ch=fgetc(fp); if(ch=='#') //文件以#结尾,作为扫描结束条件 break; if(ch==' ') //如果是空格,自动跳到下个字符 scanner(fp); else { fseek(fp,-1,1); //如果不是空格,则回退一个字符并扫描 scanner(fp); } }while(ch!='#'); return 0; }

D:\\\\su\\\\one.txt中示例代码如下: main() {

int a,b,c=2; a = 10;

b = a + 20; c = a + b/c; }#

3.6实验结果如下图:

四.实验总结(心得)

通过此次实验,使我意识到在做实验之前一定要认真复习课本内容和老师的要求以此来确定该实验要我们实现的是什么,怎么实现,每一步的步骤都要按照流程图认真的去完成,做实验不能有半点马虎。此外,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;实验核心的部分在于如何识别初各个单词的所属类别,实验前可先规划一下试验流程,这样编写起来比较方便容易。

这次的实验使我熟悉了构造词法分析程序的手工方式的相关原理,也锻炼了自己编写算法以及C语言的能力,虽然在试验过程中存在着很多的不足,但经过老师以及同学的指点再加上自己的努力都一一克服了,今后我也会经常通过自己编写此类的代码来提高自己的能力。

本文来源:https://www.bwwdw.com/article/yzxg.html

Top