词法分析程序的构造

通达学院

日II 词法分析程序的构造 业 生 姓 名 级 学 号 导 教 师 导 单 位 计算机学院计算机科学与技术系 期 专业课程设计目:

词法分析程序的构造

一、 课题内容和要求

通过状态转换图构造C或者PASCAL语言子集的词法分析程序。

原理解析:选取语言,例如选取了C语言,选取其中一个子集,例如包含了部分关

键字main、float、if、for等等,特殊符号( 、

的标识符变量以及部分常量等,采用《编译原理》词法分析中有穷自动

机的思想构建出该语言子集的状态转换图,并编码实现。

基本要求:(1)将选取的语言子集编写一个简单程序,放在一个文本文件中;

(2)要将一个个单词区分清楚并归类(例如for属于关键字)。

二、需求和思路分析

本课题是用C++语言设计,选取的是C语言子集。编写对简单语言进行词法分

析的词法分析程序。

1、识别子集中的关键字、标识符、常数、运算符和分界符等。

2、对子集中的字符类型进行归类

三、概要设计

(1)状态转换图:

(2)核心代码:

1)定义:

char cbuffer;

char*keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void

","main","const","printf"}; //关键字

char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符

char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符

char *relation[7]={"" , ">=" , "==" ,"!="};

char *lableconst[80];

2)函数调用: search(char searchchar[],int wordtype)//查找类型

alphaprocess(char buffer) //字符处理过程

digitprocess(char buffer) //数字处理过程

otherprocess(char buffer) //分隔符、运算符、逻辑运算符等

main()//主函数

3) 状态类型:

状态转换图的形式:

■每个状态对应一个带标号的case语句 ■转向边对应goto语句

switch (wordtype)

{

case 1:

{ for (i=0;i

{

if (strcmp(keyword[i],searchchar)==0)

return(i+1);

}

return(0);}

case 2:

{

for (i=0;i

{

if (strcmp(border[i],searchchar)==0)

return(i+1);

}

return(0);

//关系运算符 //标识符

}

case 3:

{

for (i=0;i

{

if (strcmp(arithmetic[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 4:

{

for (i=0;i

{

if (strcmp(relation[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 5:

{

for (t=40;t

{

if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过

return(t+1);

}

lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存

空间

strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst

指针数组名

constnum++; //常数个数自加

return(t);

}

case 6:

{

for (i=0;i

{

if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过

return(i+1);

}

lableconst[i-1]=(char *)malloc(sizeof(searchchar));

strcpy(lableconst[i-1],searchchar);

lableconstnum++; //标识符个数自加

return(i);

}

5) 单字符判断

if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成

{

cout

fp.get(buffer);

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

"

goto out;

}

四、详细设计

实验环境:visual C++6.0 win7系统

源程序代码:

#include

#include

#include

#include

#include

using namespace std;

ifstream fp("09002801.txt",ios::in);

char cbuffer;

char *keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void"

,"main","const","printf"}; //关键字

char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符

char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符

char *relation[7]={"" , ">=" , "==" ,"!="}; //关系运算符 char *lableconst[80]; //标识符

int constnum=40;

int lableconstnum=0; //统计常数和标识符数量

int row=1;

int search(char searchchar[],int wordtype)

{

int i=0,t=0;

switch (wordtype)

{

case 1:

{ for (i=0;i

{

if (strcmp(keyword[i],searchchar)==0)

return(i+1);

}

return(0);}

case 2:

{

for (i=0;i

{

if (strcmp(border[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 3:

{

for (i=0;i

{

if (strcmp(arithmetic[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 4:

{

for (i=0;i

{

if (strcmp(relation[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 5:

{

for (t=40;t

{

if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过

return(t+1);

}

lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存空间

strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst指针数组名 constnum++; //常数个数自加

return(t);

}

case 6:

{

for (i=0;i

{

if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过

return(i+1);

}

lableconst[i-1]=(char *)malloc(sizeof(searchchar));

strcpy(lableconst[i-1],searchchar);

lableconstnum++; //标识符个数自加

return(i);

}

default:cout

}

}

char alphaprocess(char buffer) //字符处理过程

{

int atype;

int i=-1;

char alphatp[20];

while ((isalpha(buffer))||(isdigit(buffer)))

//这两个函数分别是判字符和判数字函数位于ctype.h中 {

alphatp[++i]=buffer;

fp.get(buffer);

}

alphatp[i+1]='\0';//在末尾添加字符串结束标志

if (atype=search(alphatp,1))

cout

else

{

atype=search(alphatp,6); //标识符

cout

}

return(buffer);

}

char digitprocess(char buffer) //数字处理过程

{

int i=-1;

char digittp[20];

int dtype;

while ((isdigit(buffer)))

{

digittp[++i]=buffer;

fp.get(buffer);

}

digittp[i+1]='\0';

dtype=search(digittp,5);

cout

return(buffer);

}

char otherprocess(char buffer) //分隔符、运算符、逻辑运算符等

{

int i=-1;

char othertp[20];

int otype,otypetp;

othertp[0]=buffer;

othertp[1]='\0';

if (otype=search(othertp,3))

{

fp.get(buffer);

othertp[1]=buffer;

othertp[2]='\0';

if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成的 {

cout

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

}

}

if (otype=search(othertp,4)) //关系运算符

{

fp.get(buffer);

othertp[1]=buffer;

othertp[2]='\0';

if (otypetp=search(othertp,4)) //判断该关系运算符是否是由连续的两个字符组成的 {

cout

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

}

}

if (buffer=='!') //"=="的判断

{

fp.get(buffer);

if (buffer=='=')

//cout

fp.get(buffer);

goto out;

else

{

if (otype=search(othertp,2)) //分界符

{

cout

fp.get(buffer);

goto out;

}

}

if ((buffer!='\n')&&(buffer!=' '))

cout

fp.get(buffer);

out:

return(buffer);

}

void main()

{

printf("=========================词法分析器==========================\n"); int i;

for (i=0;i

{

lableconst[i]=" ";//用于保存标识符

}

if (!fp)

cout

else

{

fp.get (cbuffer);

while (!fp.eof())

{

if(cbuffer=='\n')

{

row++;

fp.get(cbuffer);

}

else if (isalpha(cbuffer))

{

cbuffer=alphaprocess(cbuffer);

}

else if (isdigit(cbuffer))

cbuffer=digitprocess(cbuffer);

}

else

cbuffer=otherprocess(cbuffer);

}

cout

i=0;

while(i

{

cout

}

cout

cout

getchar();

}

}

(3)程序流程图:

五、测试数据及其结果分析

若源程序中没有09002801.txt文档,则会出现如下提示:

若文档中包含09002801.txt文档,文档代码为:

运行后结果如下:

六、调试过程中的问题

在代码调试过程中,由于代码编写时将主函数main和文件打开的顺序颠倒,导致未写入源文档也会提示词法分析结束,实际上并未进行词法分析过程,应该提示文件打开错,返回检查。在重新修改之后能够达到理想要求编译运行。

七、专业课程设计总结

通过这次实验,我对编译原理关于词法分析有了进一步的了解,能够把《编译原理》中有穷自动机的理论知识应用于实验中。

通过这次语义分析的实验, 我对高级语言的学习有了更深的认识,了解得更透彻我了解了高级语言转化为目标代码或汇编指令的过程。对今后的学习将起很大的作用,对以后的编程有很大的帮助。本次实验通过查找书本和网上搜索了解了大致地实验思路,虽然只是完成了一个简单的程序,但在组织程序结构中学到了很多,加深了对编译原理词法编译器的理解,掌握了编译程序的实现方法和技术,巩固了前面所学的相关理论知识。虽然完成了本次课程设计,但代码还有一些优化的地方,因为可能出现的符号均是事先例举出来,并不能包含所有可能的符号,有一定的局限性,今后会多多锻炼语句的优化方面。

参考资料:

[1] 王汝传. 编译技术原理及其实现方法. 成都: 成都科技大学出版社, 1998.

[2] 吕映芝 等编著. 编译原理. 北京: 清华大学出版社, 1998.

[3] 陈火旺 等编著. 程序设计语言编译原理. 北京: 国防工业出版社, 2000.

通达学院

日II 词法分析程序的构造 业 生 姓 名 级 学 号 导 教 师 导 单 位 计算机学院计算机科学与技术系 期 专业课程设计目:

词法分析程序的构造

一、 课题内容和要求

通过状态转换图构造C或者PASCAL语言子集的词法分析程序。

原理解析:选取语言,例如选取了C语言,选取其中一个子集,例如包含了部分关

键字main、float、if、for等等,特殊符号( 、

的标识符变量以及部分常量等,采用《编译原理》词法分析中有穷自动

机的思想构建出该语言子集的状态转换图,并编码实现。

基本要求:(1)将选取的语言子集编写一个简单程序,放在一个文本文件中;

(2)要将一个个单词区分清楚并归类(例如for属于关键字)。

二、需求和思路分析

本课题是用C++语言设计,选取的是C语言子集。编写对简单语言进行词法分

析的词法分析程序。

1、识别子集中的关键字、标识符、常数、运算符和分界符等。

2、对子集中的字符类型进行归类

三、概要设计

(1)状态转换图:

(2)核心代码:

1)定义:

char cbuffer;

char*keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void

","main","const","printf"}; //关键字

char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符

char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符

char *relation[7]={"" , ">=" , "==" ,"!="};

char *lableconst[80];

2)函数调用: search(char searchchar[],int wordtype)//查找类型

alphaprocess(char buffer) //字符处理过程

digitprocess(char buffer) //数字处理过程

otherprocess(char buffer) //分隔符、运算符、逻辑运算符等

main()//主函数

3) 状态类型:

状态转换图的形式:

■每个状态对应一个带标号的case语句 ■转向边对应goto语句

switch (wordtype)

{

case 1:

{ for (i=0;i

{

if (strcmp(keyword[i],searchchar)==0)

return(i+1);

}

return(0);}

case 2:

{

for (i=0;i

{

if (strcmp(border[i],searchchar)==0)

return(i+1);

}

return(0);

//关系运算符 //标识符

}

case 3:

{

for (i=0;i

{

if (strcmp(arithmetic[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 4:

{

for (i=0;i

{

if (strcmp(relation[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 5:

{

for (t=40;t

{

if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过

return(t+1);

}

lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存

空间

strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst

指针数组名

constnum++; //常数个数自加

return(t);

}

case 6:

{

for (i=0;i

{

if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过

return(i+1);

}

lableconst[i-1]=(char *)malloc(sizeof(searchchar));

strcpy(lableconst[i-1],searchchar);

lableconstnum++; //标识符个数自加

return(i);

}

5) 单字符判断

if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成

{

cout

fp.get(buffer);

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

"

goto out;

}

四、详细设计

实验环境:visual C++6.0 win7系统

源程序代码:

#include

#include

#include

#include

#include

using namespace std;

ifstream fp("09002801.txt",ios::in);

char cbuffer;

char *keyword[14]={"if","else","for","while","do","float","return","break","continue","int","void"

,"main","const","printf"}; //关键字

char *border[8]={ "," , ";" , "{" , "}" , "(" , ")" ,":=","."}; //分隔符

char *arithmetic[6]={"+" , "-" , "*" , "/" , "++" , "--"}; //运算符

char *relation[7]={"" , ">=" , "==" ,"!="}; //关系运算符 char *lableconst[80]; //标识符

int constnum=40;

int lableconstnum=0; //统计常数和标识符数量

int row=1;

int search(char searchchar[],int wordtype)

{

int i=0,t=0;

switch (wordtype)

{

case 1:

{ for (i=0;i

{

if (strcmp(keyword[i],searchchar)==0)

return(i+1);

}

return(0);}

case 2:

{

for (i=0;i

{

if (strcmp(border[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 3:

{

for (i=0;i

{

if (strcmp(arithmetic[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 4:

{

for (i=0;i

{

if (strcmp(relation[i],searchchar)==0)

return(i+1);

}

return(0);

}

case 5:

{

for (t=40;t

{

if (strcmp(searchchar,lableconst[t])==0)//判断该常数是否已出现过

return(t+1);

}

lableconst[t-1]=(char *)malloc(sizeof(searchchar)); //为新的元素分配内存空间

strcpy(lableconst[t-1],searchchar); //为数组赋值lableconst指针数组名 constnum++; //常数个数自加

return(t);

}

case 6:

{

for (i=0;i

{

if (strcmp(searchchar,lableconst[i])==0) //判断标识符是否已出现过

return(i+1);

}

lableconst[i-1]=(char *)malloc(sizeof(searchchar));

strcpy(lableconst[i-1],searchchar);

lableconstnum++; //标识符个数自加

return(i);

}

default:cout

}

}

char alphaprocess(char buffer) //字符处理过程

{

int atype;

int i=-1;

char alphatp[20];

while ((isalpha(buffer))||(isdigit(buffer)))

//这两个函数分别是判字符和判数字函数位于ctype.h中 {

alphatp[++i]=buffer;

fp.get(buffer);

}

alphatp[i+1]='\0';//在末尾添加字符串结束标志

if (atype=search(alphatp,1))

cout

else

{

atype=search(alphatp,6); //标识符

cout

}

return(buffer);

}

char digitprocess(char buffer) //数字处理过程

{

int i=-1;

char digittp[20];

int dtype;

while ((isdigit(buffer)))

{

digittp[++i]=buffer;

fp.get(buffer);

}

digittp[i+1]='\0';

dtype=search(digittp,5);

cout

return(buffer);

}

char otherprocess(char buffer) //分隔符、运算符、逻辑运算符等

{

int i=-1;

char othertp[20];

int otype,otypetp;

othertp[0]=buffer;

othertp[1]='\0';

if (otype=search(othertp,3))

{

fp.get(buffer);

othertp[1]=buffer;

othertp[2]='\0';

if (otypetp=search(othertp,3)) //判断该运算符是否是由连续的两个字符组成的 {

cout

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

}

}

if (otype=search(othertp,4)) //关系运算符

{

fp.get(buffer);

othertp[1]=buffer;

othertp[2]='\0';

if (otypetp=search(othertp,4)) //判断该关系运算符是否是由连续的两个字符组成的 {

cout

goto out;

}

else //单字符逻辑运算符

{

othertp[1]='\0';

cout

}

}

if (buffer=='!') //"=="的判断

{

fp.get(buffer);

if (buffer=='=')

//cout

fp.get(buffer);

goto out;

else

{

if (otype=search(othertp,2)) //分界符

{

cout

fp.get(buffer);

goto out;

}

}

if ((buffer!='\n')&&(buffer!=' '))

cout

fp.get(buffer);

out:

return(buffer);

}

void main()

{

printf("=========================词法分析器==========================\n"); int i;

for (i=0;i

{

lableconst[i]=" ";//用于保存标识符

}

if (!fp)

cout

else

{

fp.get (cbuffer);

while (!fp.eof())

{

if(cbuffer=='\n')

{

row++;

fp.get(cbuffer);

}

else if (isalpha(cbuffer))

{

cbuffer=alphaprocess(cbuffer);

}

else if (isdigit(cbuffer))

cbuffer=digitprocess(cbuffer);

}

else

cbuffer=otherprocess(cbuffer);

}

cout

i=0;

while(i

{

cout

}

cout

cout

getchar();

}

}

(3)程序流程图:

五、测试数据及其结果分析

若源程序中没有09002801.txt文档,则会出现如下提示:

若文档中包含09002801.txt文档,文档代码为:

运行后结果如下:

六、调试过程中的问题

在代码调试过程中,由于代码编写时将主函数main和文件打开的顺序颠倒,导致未写入源文档也会提示词法分析结束,实际上并未进行词法分析过程,应该提示文件打开错,返回检查。在重新修改之后能够达到理想要求编译运行。

七、专业课程设计总结

通过这次实验,我对编译原理关于词法分析有了进一步的了解,能够把《编译原理》中有穷自动机的理论知识应用于实验中。

通过这次语义分析的实验, 我对高级语言的学习有了更深的认识,了解得更透彻我了解了高级语言转化为目标代码或汇编指令的过程。对今后的学习将起很大的作用,对以后的编程有很大的帮助。本次实验通过查找书本和网上搜索了解了大致地实验思路,虽然只是完成了一个简单的程序,但在组织程序结构中学到了很多,加深了对编译原理词法编译器的理解,掌握了编译程序的实现方法和技术,巩固了前面所学的相关理论知识。虽然完成了本次课程设计,但代码还有一些优化的地方,因为可能出现的符号均是事先例举出来,并不能包含所有可能的符号,有一定的局限性,今后会多多锻炼语句的优化方面。

参考资料:

[1] 王汝传. 编译技术原理及其实现方法. 成都: 成都科技大学出版社, 1998.

[2] 吕映芝 等编著. 编译原理. 北京: 清华大学出版社, 1998.

[3] 陈火旺 等编著. 程序设计语言编译原理. 北京: 国防工业出版社, 2000.


相关内容

  • 编译原理--教学大纲
  • <计算机编译原理>课程大纲 一.适用对象 本课程适用于计算机科学与技术以及相关专业的网络教育.成人教育学生. 二.课程性质 本课程是计算机科学与技术专业学生的专业基础课. 编译原理课程是计算机专业的一门主干课程.课程介绍程序设计语言编译程序构造的一般原理.基本设计方法.主要实现技术和一些 ...

  • 张瑞编译原理实验报告
  • 黑龙江大学 "编译原理课程设计"读书报告 学院 年级 专业 学号 姓名 报告日期 成绩 软件学院 2012级 软件工程 20122515 张瑞 2014年6月28日 黑龙江大学计算机科学技术学院 黑龙江大学软件学院 概述 "编译原理"课程是计算机专业中一门重要 ...

  • 编译原理实验指导书(2015)
  • LIAOCHENG UNIVERSITY 编译原理 实验指导书 聊城大学计算机学院 2011年3月 目 录 <编译原理>课程实验教学大纲 ............................. 1 实验一 词法分析器的设计 .............................. ...

  • 简单的C语言编译器
  • 中国好资料 一个简单的C 语言编译器 一.小组成员 朱嘉俊(3991102161) 王筱(3991102168) 朱杭(3991102162) 朱林(3991102094)计算机996计算机996计算机996计算机994 二.运行方式 在DOS 环境下运行: Cminus.exe -h 三.概述 经 ...

  • 编译原理_词法分析器_实验报告
  • 词法分析器实验报告 实验目的: 设计.编制.调试一个词法分析子程序-识别单词,加深对词法分析原理的理解. 功能描述: 该程序要实现的是一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字.标识符.常数.运算符.分隔符五大类.并依次输出各个单词的内部编码及单词符号自身值.(遇到 ...

  • 语法分析程序
  • 北 京 林 业 大 学 实 验 任 务 书 北 京 林 业 大 学 11学年-12学年第 2学期 编译原理实验任务书 专业名称: 计算机科学与技术 实验学时: 4 课程名称:编译原理 任课教师: 李冬梅 实验题目:语法分析 实验环境:Paser Generator ,Visual C++ 自选另外一 ...

  • 2016腾讯软件开发面试题(不定项选择题[13
  • 腾讯.jpg 一.前言 前言.png 本来这篇文章打算在上一篇文章后一个星期就写完的,可是最近跟一个同学在讨论创业的事情,因此迟迟还没写完,拖到现在(2017年2月14日01:25:22),因此今晚必需赶出来. 二.2016 腾讯软件开发面试题(不定项选择题[13-25]) 13.浏览器访问某页面, ...

  • 基于符号执行的软件静态测试研究
  • 第23卷第6期2013年6月 计算机技术与发展 COMPUTER TECHNOLOGY AND DEVELOPMENT Vol.23No.6June 2013 基于符号执行的软件静态测试研究 梁娟娟,刘久富,朱丹丹,陈 柯 (南京航空航天大学自动化学院,江苏南京210016) 摘 要:文中基于符号执 ...

  • [编译原理]实验教学大纲
  • <编译原理>课程实验教学大纲 1.实验课程号: 20013B3sy 2.课程属性:必修 3.实验属性:非独立设课 4.学时学分: 12学时 5.实验应开学期:秋季 6.先修课程:C 语言FORTRAN 语言或PASCAL 语言,汇编语言,数据结构,离散数学等. 一.课程的性质与任务 本课 ...