使用直接分析法编制C语言子集的词法分析程序

使用直接分析法编制C语言子集的词法分析程序,第1张

选我为最佳答案吧!

南华大学

计算机科学与技术学院

实 验 报 告

( 2011~2012 学年度 第 二 学期 )

课程名称

程序设计语言与编译

姓名 学号

专业 电气信息类 班级

地点 8—209 教师

题目: 用直接分析方法编制C++语言子集的词法分析程序.

一、分析

对于单词符号我们将其分成四类:保留字K、标识符I、常数C和界符P,每类单词符号均可使用一张表格表示.在词法分析过程中,保留字K和界符P这两个表格的内容是固定不变的(由语言确定),源程序字符串只能从其中选取,而标识符I、常数C这两表是在分析过程中不断形成的.

对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是K、I、C或P中之一,那么就以单词的二元式形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串.

各类单词的二元式表述均具有相同的结构与长度,形式如下:

(单词种别t,单词自身的值i)

t是单词种别,而单词种别共分为K、I、C、P四类且每类对应一张表格.因此,t实际上就是一个指向这四类中某一类对应表格的指针.i则为指向该类表格中一个特定项目的指针.

所以整个的词法分析过程就是从源程序中获得一个个的单词符号,将这些符号分别填入四张类表中,并且有一个二元式序列构成一个索引,这个索引为以后的语法分析提供处理上的方便.

为了减少实习量,可以适量地选取K,P中的一个子集来进行.如下表:

表1 保留字K表

内部地址 1 2 3 4 5 6 7 8 9 10

保 留 字 BEGIN CONST DO ELSE  END IF PROCEDURE THEN VAR WHILE

表2 界符P表

内部地址 1 2 3 4 5 6 7 8 9 10

界 符 ; + : : ( , ) < < <

组合界符 = = >

保留字表包括10个有代表性的保留字,界符表包括关系运算符三种(8,9,10),算术运算符(2),分隔符三种(1,4,6),一对圆括号,加上赋值号共10种.这两表的内容表明PASCAL语言的条件语句,赋值语句,WHILE型循环语句,复合语句,过程及变量说明均可作为源程序例子输入给词法分析程序,标识符表I中的每一项包含一个标识符,常数表C中的每一项包含一个整常数,后两表的内容都是在词法分析过程中产生的.

如何从源程序中识别出一个个的单词符号呢?图1中的流图清晰地反映出这一过程.

图1中,双圆圈的状态表示终态,即能到达终态就代表识别出一个单词符号,而带有*号的终态是指处理时应回退一字符.

二、算法

词法分析器在扫描过程中,依次从源程序中取出源字符,根据图1的扫描过程状态转换图,当碰到终态时,即双圆圈的状态时就得到一个单词符号,此时可以根据第一个字符判断单词属于K,I,C,P中哪一类,从而确定单词的"单词种别"和"单词自身的值".整个词法分析的算法流程如图2.

三、实现

选择实习环境为TURBO C2.0语言. 实现程序见附录.

四、总结

上机前应做好准备.即根据实习目的、要求和分析,选择相应的数据结构,使用C语言参照算法中的流程编写词法分析的程序.将编好的程序上机进行调试.注意调试的例子应有词法正确的,也应有词法错误的或是超出所选数据结构范围的.

实验完成达到实习目的之后,若尚有余力者,可以对所选子集适当扩大或是增加相应功能如:扩充界符和保留字数目;允许实型常数;进行词法错误检查;最大范围扩充以至PASCAL语言所有字符的集合.

实验完成以后编写出完整的实验报告,反映出最后的实验学习结果.

附录

/* 实验代码:*/

实验结果:

五、结果感想

实验中需要识别的词有:

关键字:DIM、IF、DO、STOP、END单词种别码为1.2.3.4.5。

标识符;单词种别码为6。

常数为无符号整形数;单词种别码为7。

运算符包括:=、-、*、**单词种别码为8.9.10.11。

分隔符包括:,、(、); 单词种别码为12.13.14。

通过此次实验,让我了解到如何设计、编制并调试词法分析程序,加深对词法分析原理的理解;熟悉了构造词法分析程序的手工方式的相关原理,根据识别语言单词的状态转换图,使用某种高级语言(例如C++语言)直接编写此法分析程序。另外,也让我重新熟悉了C++语言的相关内容,加深了对C++语言的用途的理解。

C语言词法分析器

#include<iostream>

#include<stdio.h>

#include<string>

using namespace std

FILE *f //定义一个文件变量

static int line = 1 //表示光标所在的行数

struct ID{ char *nameint count}id[100]//用于存放ID号码

static int I = 0//用于记录ID存放的数量

int Number[100]//用于存放数字

static int P = 0//用于记录存放慎销昌数字的个数

int error[100] = {0} //用于记录错误所在的行数

static int K = 0//记录错误次数

void Error() //斗唯记录错误

void loginID(char *) //注册ID号

void loginNumber(int &)//记录数字

void noteLine(char &)//记录光标所在的行数

void print() //输出分析结果

int same(char *chr) //判断单词是否已经存在

void Error()

{ error[K++] = line}

void loginID(char *chr) //注册ID号

{

int k = 0

int h = 0

for(int i = 0i <Ii++)

{

if(!strcmp(chr,id.name)) //如果单词已经存在

{

id.count++

k = 1

}

}

if(k == 0) //该单词不存在

{

h = I + 1

//I = h

id[h].count++

id[h].name = chr

//strcpy(id[h].name ,chr)

}

}

void loginNumber(int &nu)

{ Number[P++] = nu}

void noteLine(char &ch)

{

if ( ch == ' ' )

++line

}

void print()//输出部分

{

//cout <<"关键字以及变量:" <<endl

//for(int i = 0i <100i++)

//cout <<i <<" " <<id.name <<" " <<id.count <<endl

cout <<"数字:" <<endl

for(int i = 1i <= Pi++)

cout <<i <<": " <<Number[i-1] <<endl

if(error[0] != 0)

{

cout <<"出现的错误!" <<endl

for(int i = 1i <= Ki++)

cout <<"第" <<i <<"个错误: " <<"第" <<error[i-1] <<"行" <<endl

}

else cout <<"没有错误!" <<endl

}

//文件处理部分

void noblank( char &ch) //跳过空格,回车

{

noteLine(ch)

while(ch == ' ' || ch == ' ')

ch = fgetc(f)

}

void identifier(char name[],char &ch)//字母变宽扒量

{

int i

for(i = 0i <20i++)

name = ''

i = 0

while (('0'<= ch &&ch <= '9')||('a'<= ch&&ch <= 'z')||('A'<= ch&&ch <='Z'))

{

name = ch

i++

ch = fgetc(f)

}

loginID(name)

//for(int j = 0j <ij++)

//{cout <<name[j]}

// cout <<' '

}

int number(char &ch)//数字

{

int num=0

while('0'<= ch &&ch <= '9')

{

num = num* 10 + (ch-'0')

ch = fgetc(f)

}

if( ('a'<= ch&&ch <= 'z')||('A'<= ch&&ch <='Z'))

{

Error()

}

else if( ch == '.')

{}

loginNumber(num) //记录数字

return num

}

void test(char &ch)//符号

{

char str[2]={'0/'}

if(ch == '*')

{ str[0] = chch = fgetc(f)}

if(ch == '.')

{ str[0] = chch = fgetc(f)}

if(ch == ',')

{ str[0] = chch = fgetc(f)}

if(ch == '"')

{ str[0] = chch = fgetc(f)}

if(ch == '/')

{ str[0] = chch = fgetc(f)}

if(ch == '%')

{ str[0] = chch = fgetc(f)}

if(ch == '^')

{ str[0] = chch = fgetc(f)}

if(ch == '-')

{ str[0] = chch = fgetc(f)}

if(ch == '{')

{ str[0] = chch = fgetc(f)}

if(ch == '}')

{ str[0] = chch = fgetc(f)}

if(ch == '[')

{ str[0] = chch = fgetc(f)}

if(ch == ']')

{ str[0] = chch = fgetc(f)}

if(ch == '')

{str[0] = chch = fgetc(f)}

if(ch == ':')

{ str[0] = chch = fgetc(f)}

if(ch == '?')

{ str[0] = chch = fgetc(f)}

if(ch == '(')

{ str[0] = chch = fgetc(f)}

if(ch == ')')

{str[0] = chch = fgetc(f)}

if(ch =='+')

{

str[0] = ch

if((ch = fgetc(f)) == '+' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

//cout <<str[0]<<endl

}

if(ch == '-')

{

str[0] = ch

if((ch = fgetc(f)) == '-' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

//cout <<str[0]<<endl

}

if(ch == '&')

{

str[0] = ch

if((ch = fgetc(f)) == '&' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

//cout <<str[0]<<endl

}

if(ch == '|')

{

str[0] = ch

if((ch = fgetc(f)) == '|' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

//cout <<str[0]<<endl

}

if(ch == '!')

{

str[0] = ch

if((ch = fgetc(f)) == '=' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

//cout <<str[0]<<endl

}

if(ch == '=')

{

str[0] = ch

if((ch = fgetc(f)) == '=' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

}

if(ch == '>')

{

str[0] = ch

if((ch = fgetc(f)) == '=' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

else

if(ch == '>' )

{

str[1] = ch

ch = fgetc(f)

//cout <<str[0] <<str[1] <<endl

}

}

if(ch == '<')

{

str[0] = ch

if((ch = fgetc(f)) == '=' )

{

str[1] = ch

ch = fgetc(f)

}

else

if(ch == '<' )

{

str[1] = ch

ch = fgetc(f)

}

}

}

int main()

{

char ch

char name[30]

for(int i = 0i <30i++)

name = '/0'

f = fopen("c.txt","r") //打开指定输入文件

if (f == NULL)

cout<<"文件不存在!"<<endl

ch = fgetc(f)

while(!feof(f))

{

noblank( ch )//跳过回车,空格

if( ( ch >= 'a' &&ch <= 'z' )||( ch >= 'A' &&ch <= 'Z' ))

{ identifier(name,ch)} //处理字母

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

{ number(ch)} //处理数字

else

{ test(ch)} //处理符号

}

print() //打印词法分析结果

fclose(f) //关闭文件

system("pause")

return 0

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12502358.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存