南华大学
计算机科学与技术学院
实 验 报 告
( 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
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)