编译原理实验报告2-词法分析程序的设计

更新时间:2023-11-27 17:36:01 阅读量: 教育文库 文档下载

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

实验2 词法分析程序的设计

一、实验目的

掌握计算机语言的词法分析程序的开发方法。

二、实验内容

编制一个能够分析三种整数、标识符、主要运算符和主要关键字的词法分析程序。

三、实验要求

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) 以二元式形式输出单词<单词种类,单词属性>

其中单词种类用整数表示: 0:标识符 1:十进制整数 2:八进制整数 3:十六进制整数

运算符和界符,关键字采用一字一符,不编码 其中单词属性表示如下:

标识符,整数由于采用一类一符,属性用单词表示 运算符和界符,关键字采用一字一符,属性为空

3、编写测试程序,反复调用函数scan( ),输出单词种别和属性。

四、实验环境

PC微机

DOS操作系统或 Windows 操作系统

Turbo C 程序集成环境或 Visual C++ 程序集成环境

五、实验步骤

1、 根据正规式,画出状态转换图;

空白 字母 0 1 字母或数字 非字母与数字 2 * 0~9 1~9 3 0 5 x 非数字 4 * 非1~7与x 1~7 6 0~7 非0~7 0~9或a~f 0~9或a~f 8 9 * 7 * 10 非0~9与a~f + 或—或* 或/ 或< 或> 或= 或 (或 ) 或 ; 11 if then else while do 12 2、 根据状态图,设计词法分析算法;

观察状态图,其中状态2、4、7、10(右上角打了星号)需要回调一个字符。 声明一些变量和函数:

ch: 字符变量,存放最新读进的源程序字符。 strToken: 字符串变量,存放构成单词符号的字符串。 GetChar():

子函数,将下一输入字符读到ch中,搜索指示器前移一字符位置。

GetBC(): 子函数,检查ch中的字符是否为空白。若是,则调用GetChar()直至ch中进入一个非空白字符。

Concat(): 子函数,将ch中的字符连接到strToken之后。 IsLetter(): 布尔函数,判断ch中的字符是否为字母。 IsDigit(): 布尔函数,判断ch中的字符是否为数字。 Reserve(): SearchOp():

整型函数,对strToken中的字符串查找保留字表,若它是一个保留字整型函数,对ch查找运算符和界符,若它是一个运算符或界符,则

则返回它的编码,否则返回0。 返回它的编码,否则返回0。

Retract(): 子函数,将搜索指示器回调一个字符位置,将ch置为空白字符。 ProError():

关键字保存在字符数组中,定义编码为相对数组首地址的位置 + 1。保留子表顺序如下:{ if ,then ,else ,while, do } ,则相应编码为:1,2,3,4,5。

运算符和界符保存在字符数组中,编码定义与关键字相同,顺序如下:{ + ,- , * , / , > , < , = , ( , ) , ;},编码为:1~10。

错误处理函数。

二元表

单词 标识符 十进制整数 八进制整数 十六进制整数 运算符和界符 关键字

算法如下: ch=? ? ; GetBC(); if(IsLetter()) {

while(IsLetter() || IsDigit()) { Concat(); GetChar(); }

Retract();

If(Reserve()) printf(\, strToken); else printf(\, strToken); }

else if(?1? < =ch && ch <=?9?) {

while(IsDigit())

{ Concat(); GetChar(); } Retract();

printf(\, strToken) ;

}

GetChar();

if(ch >= ?1? && ch <= ?7?) { }

else if(ch==?x?) {

GetChar();

while(IsDigit() || ch>= ?a? && ch<=?f?)

{ Concat(); GetChar(); } Retract();

printf(\, strToken);

} else {

while(ch >= ?0? && ch <= ?7?)

{ Concat(); GetChar(); } Retract();

printf(\, strToken) ;

else if(ch==?0?) {

strToken=” ”;

单词种类 0 1 2 3 单词自身 单词自身 属性 单词自身 单词自身 单词自身 单词自身 - -

Retract(); printf(“<1,0> “) ; } }

else if(SearchOp()) printf(\, ch); else ProError();

3、 采用C或C++语言,设计函数scan( ),实现该算法;

char GetChar(FILE* fp) { //读取文件中的一个字符 char ch; ch = fgetc(fp); return ch;

}

char GetBC(FILE* fp) {

char ch; do {

ch = GetChar(fp);

} while (ch == ' ' || ch == '\\t' || ch == '\\n'); return ch;

}

void Concat(char ch ,char strToken[]) { char str[2]; str[0] = ch; str[1] = '\\0'; strcat(strToken,str); }

int IsLetter(char ch) {

回1,否则返回0 int flag = 0;

if (ch >= 'a' && ch <= 'z')

flag = 1; return flag;

}

int IsDigit(char ch) {

回1,否则返回0 int flag = 0;

if (ch >= '0' && ch <= '9')

flag = 1; return flag;

}

//读取文件的字符直至ch不是空白

//将ch中的字符连接到strToken之后 //布尔函数,判断ch中的字符是否为字母,是返

//布尔函数,判断ch中的字符是否为数字,是返

int Reserve(char strToken[]) { //整型函数,对strToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回0 }

int SearchOP(char ch) { }

char Retract(FILE* fp,char ch) { 空白字符 }

void ProError( ) { }

return;

//错误处理函数

printf(\输入错误!\\n\); ch = ' '; fseek(fp, -1L, 1); return ch;

//子函数,将搜索指示器回调一个字符位置,将ch置为

int code = 0, i;

char OP[11] = { '+', '-', '*', '/', '<', '>', '=', '(', ')', ';' }; for (i = 0; i < 10; i++) { }

return code;

if (ch == OP[i]) { }

code = i + 1; break;

//整型函数,对strToken中的字符串查找运算符和界符,若它是一

个运算符或界符,则返回它的编码,否则返回0

int code = 0,i;

char keyWord[6][6] = { \, \, \, \, \ }; for (i = 0; i < 5; i++) { }

return code;

if (strcmp(strToken, keyWord[i]) == 0) { }

code = i + 1; break;

FILE* scan(FILE* fp) {

char ch;

char strToken[10]; strToken[0] = '\\0';

//置strToken为空串

//判断文件尾,是则返回调用程序

ch = GetBC(fp);

//先读取一个非空白的字符

//输出单个二元式

if (feof(fp)) return fp;

if (IsLetter(ch)) { }

}

//判断标识符

while (IsLetter(ch) || IsDigit(ch)) {

Concat(ch, strToken); ch = GetChar(fp);

ch = Retract(fp,ch); if (Reserve(strToken)) { } else

printf(\, strToken);

//判断十进制整数

//判断关键字

printf(\, strToken);

else if (ch >= '1' && ch <= '9') { }

else if (ch == '0') { }

ch = GetChar(fp);

if (ch >= '1' && ch <= '7') { }

else if (ch == 'x') { } else { }

}

ch = Retract(fp, ch); while (IsDigit(ch)) { }

ch = Retract(fp, ch); printf(\, strToken);

Concat(ch, strToken); ch = GetChar(fp);

//判断八进制整数

while (ch >= '0' && ch <= '7') {

Concat(ch, strToken); ch = GetChar(fp);

printf(\, strToken);

//判断十六进制整数

ch = GetChar(fp);

while (IsDigit(ch) || ch >= 'a' && ch <= 'f') { }

ch = Retract(fp, ch); printf(\, strToken);

//判断十进制的0

Concat(ch, strToken); ch = GetChar(fp);

ch = Retract(fp, ch); printf(\);

}

else if (SearchOP(ch)) { } else { } return fp;

//判断运算符和界符

printf(\, ch);

//出错

ProError();

4、 编制测试程序(主函数main);

#include using namespace std; #define NULL 0 int main( ) {

FILE* fp;

if ((fp = fopen(\, \)) == NULL) { //以只 }

printf(\词法分析结果如下:\\n\); while (!feof(fp)) { }

fclose(fp); //关闭文件 fp = NULL; }

//避免指向非法内存

//若不是文件尾则执行循环

fp = scan(fp);

//输出单词种类、属性的二元式

printf(\); exit(0);

读方式打开文件,失败则退出程序

5、调试程序:读入文本文件,检查输出结果。

六、测试数据

输入数据:

编辑一个文本文件program.txt,在文件中输入如下内容:

if data+92>0x3f then data=data+01; else data=data-01; <0 , data> <+ , -> <1 , 92> <> , -> <3 , 3f> <0 , data> <= , > <0 , data> <+ , -> <2 , 1> <; ,-> <0 , data> <= , -> <0 , data> <- , -> <2 , -> <; , -> 正确结果:

七、实验报告要求

实验报告应包括以下几个部分: 1、词法的正规式描述; 2、变换后的 状态图;

3、词法分析程序的数据结构与算法。

八、思考题

1、 词法分析能否采用空格来区分单词?

答:不能,因为程序的语法里有包括:’;’,‘{’,‘}‘ ,‘(‘,‘)‘等界符或连接符号存在,这些符号符与单词的连接无空格,用空格区分单词将无法保证程序语法的正确。

2、 程序设计中哪些环节影响词法分析的效率?如何提高效率?

答:本程序在判断关键字时,是在完成对标志符的识别后,判断该标识符是否是保留字,若是则判断为关键字,这种情况下,导致每次识别完一个标识符,都要查询保留字表,会影响效率,可在识别标识符的程序段中添加对关键字的识别,如首字母的特别判断或遇到数字跳过关键字的判断等。另外,程序的实现是通过在主函数中循环调用scan()函数来输出二元式,一次调用就输出一个二元式,可以考虑使用堆栈,先将读来的数据压栈,再进行识别,这样比重复调用函数效率更高,而且也不必使用文件指针来回调字节,用堆栈会更方便更安全准确,省去不少程序段。

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

Top