词法分析器.docx
《词法分析器.docx》由会员分享,可在线阅读,更多相关《词法分析器.docx(16页珍藏版)》请在冰豆网上搜索。
![词法分析器.docx](https://file1.bdocx.com/fileroot1/2023-2/4/efdeda7c-ad72-4871-a8be-23e4aaac0af8/efdeda7c-ad72-4871-a8be-23e4aaac0af81.gif)
词法分析器
1.1单词符号的内部定义及在编译程序中的定义
我们对常量、变量、临时变量、保留关键字(if、while、begin、end、else、then、do等)、关系运算符、逻辑运算符、分号、括号等,规定其内部定义如下:
符号
种别编码
说明
sy_if
0
保留字if
sy_then
1
保留字then
sy_else
2
保留字else
sy_while
3
保留字while
sy_begin
4
保留字begin
sy_do
5
保留字do
sy_end
6
保留字end
a
7
赋值语句
semicolon
8
“;”
e
9
布尔表达式
Jinghao
10
“#”
S
11
语句
L
12
复合语句
Tempsy
15
临时变量
EA
18
Band(即布尔表达式中的B∧)
EO
19
Bor(即布尔表达式中的B∨)
Plus
34
“+”
Times
36
“*”
Becomes
38
“:
=”赋值
Op_and
39
“and”
Op_or
40
“or”
Op_not
41
“not”
Rop
42
关系运算符
Lparent
48
“(”
Rparent
49
“)”
Ident
56
变量
Intconst
57
整常量
#include"stdio.h"/*如果使用TC的话,需要配置头文件路径*/
#include"string.h"/*如果使用VC的话,可以配置头文件conio.h*/
#defineACC-2
/************************/
#definesy_if0
#definesy_then1
#definesy_else2
#definesy_while3
#definesy_begin4
#definesy_do5
#definesy_end6
#definea7
#definesemicolon8
#definee9
#definejinghao10
#defineS11
#defineL12
#definetempsy15
#defineEA18/*Eand*/
#defineE019/*Eor*/
#defineplus34
#definetimes36
#definebecomes38
#defineop_and39
#defineop_or40
#defineop_not41
#definerop42
#definelparent48
#definerparent49
#defineident56
#defineintconst57
1.2变量及数据结构说明
编译程序中涉及到的变量及数据结构说明如下:
charch='\0';/*从字符缓冲区读取当前字符*/
intcount=0;/*词法分析结果缓冲区计数器*/
staticcharspelling[10]={""};/*存放识别的单词符号*/
staticcharline[81]={""};/*一行字符缓冲区,最多80个字符*/
char*pline;/*字符缓冲区指针*/
staticcharntab1[100][10];/*变量名表,共100项,每项长度10*/
structntab
{
inttc;/*真值*/
intfc;/*假值*/
}ntab2[200];/*在布尔表达式E中保存有关布尔变量的真、假值*/
intlabel=0;/*指向ntab2的指针*/
structrwords{
charsp[10];
intsy;
};/*保留字表的结构,用来与输入缓冲区中的单词进行匹配*/
structrwordsreswords[10]={{"if",sy_if},
{"do",sy_do},
{"else",sy_else},
{"while",sy_while},
{"then",sy_then},
{"begin",sy_begin},
{"end",sy_end},
{"and",op_and},
{"or",op_or},
{"not",op_not}};/*保留字表初始化,大小为10*/
structaa{
intsy1;/*存放单词符号的种别编码*/
intpos;/*存放单词符号自身的值*/
}buf[1000],/*词法分析结果缓冲区,保存识别出来的单词符号*/
n,/*读取二元式的当前符号*/
n1,/*当前表达式中的符号*/
E,/*非终结符*/
sstack[100],/*算术或布尔表达式加工处理使用的符号栈*/
ibuf[100],/*算术或布尔表达式使用的缓冲区*/stack[1000];/*语法分析加工处理使用的符号栈*/
structaaoth;/*四元式中的空白位置*/
structfourexp{
charop[10];
structaaarg1;
structaaarg2;
intresult;
}fexp[200];/*四元式的结构定义*/
intssp=0;/*指向sstack栈指针*/
structaa*pbuf=buf;/*指向词法分析缓冲区的指针*/
intnlength=0;/*词法分析中记录单词的长度*/
inttt1=0;/*变量名表指针*/
char*cfile;/*源程序文件,~为结束符*/
intlnum=0;/*源程序行数记数*/
intsign=0;/*sign=1为赋值语句;=2为while语句;=3为if语句*/
/*******************************************************/
intnewt=0;/*临时变量计数器*/
intnxq=100;/*nxq总是指向下一个将要形成的四元式地址,*/
/*每次执行gen()时,地址自动增1*/
intlr;/*扫描LR分析表1过程中保存的当前状态值*/
intlr1;/*扫描LR分析表2或表3所保存的当前状态值*/
intsp=0;/*查找LR分析表时符号栈的栈顶指针*/
intstack1[100];/*状态栈1定义*/
intsp1=0;/*状态栈1的栈顶指针*/
intnum=0;/*算术或布尔表达式缓冲区指针*/
structll{
intnxq1;/*记录下一条四元式的地址*/
inttc1;/*真值链*/
intfc1;/*假值链*/
}labelmark[10];/*记录语句嵌套层次的数组,*/
/*即记录嵌套中每层的布尔表达式E的首地址*/
intlabeltemp[10];/*记录语句嵌套层次的数组,*/
/*即记录每层else之前的四元式地址*/
intpointmark=-1,/*labelmark数组指针*/
pointtemp=-1;/*labeltemp数组指针*/
1.3主函数main()
voidmain()
{
cfile=fopen("pas.dat","r");/*打开C语言源文件*/
readch();/*从源文件读一个字符*/
scan();/*词法分析*/
disp();
printf("\n程序运行结束!
\n");
getch();
}
1.4词法分析函数说明
(1)读取函数readline()、readch()
词法分析包含从源文件读取字符的操作,但频繁的读文件会影响程序执行效率,故实际上是从源程序文件“pas.dat”中读取一行到输入缓冲区,而词法分析过程中每次读取一个字符时则是通过执行readch()从输入缓冲区获得的;若缓冲区已被读空,则再执行readline()从pas.dat中读取下一行至输入缓冲区。
/*************从文件读一行到缓冲区*************/
readline()
{
charch1;
pline=line;
ch1=getc(cfile);
while(ch1!
='\n'&&!
feof(cfile))
{
*pline=ch1;
pline++;
ch1=getc(cfile);
}
*pline='\0';
pline=line;
}
/*************从缓冲区读取一个字符*********************/
readch()
{
if(ch=='\0')
{
readline();
lnum++;
}
ch=*pline;
pline++;
}
(2)扫描函数scan()
扫描函数scan()的功能是滤除多余空格并对主要单词进行分析处理,将分析得到的二元式存入二元式结果缓冲区。
/******************扫描主函数**************************/
scan()
{
inti;
while(ch!
='^')/*’^’是源程序结束符号*/
{
switch(ch)
{
case'':
break;
case'a':
case'b':
case'c':
case'd':
case'e':
case'f':
case'g':
case'h':
case'i':
case'j':
case'k':
case'l':
case'm':
case'n':
case'o':
case'p':
case'q':
case'r':
case's':
case't':
case'u':
case'v':
case'w':
case'x':
case'y':
case'z':
/*保留字和标识符中的字母只能是小写字母*/
identifier();/*识别保留字和标识符*/
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
number();/*识别整常数*/
break;
case'<':
readch();
if(ch=='=')
{
buf[count].pos=0;/*识别’<=’*/
}
else
{
if(ch=='>')buf[count].pos=4;/*识别’<>’*/
else
{
buf[count].pos=1;/*识别’<’*/
pline--;
}
}
buf[count].sy1=rop;/*识别关系运算符*/
count++;
break;
case'>':
readch();
if(ch=='=')
{
buf[count].pos=2;/*识别’>=’*/
}
else
{
buf[count].pos=3;/*识别’>’*/
pline--;
}
buf[count].sy1=rop;/*识别关系运算符*/
count++;
break;
case'(':
buf[count].sy1=lparent;/*识别’(’*/
count++;
break;
case')':
buf[count].sy1=rparent;/*识别’)’*/
count++;
break;
case'#':
buf[count].sy1=jinghao;/*识别’#’*/
count++;
break;
case'+':
buf[count].sy1=plus;/*识别’+’*/
count++;
break;
case'*':
buf[count].sy1=times;/*识别’*’*/
count++;
break;
case':
':
readch();
if(ch=='=')
buf[count].sy1=becomes;/*识别’:
=’*/
count++;
break;
case'=':
buf[count].sy1=rop;
buf[count].pos=5;/*识别’=’,关系算符*/
count++;
break;
case';':
buf[count].sy1=semicolon;/*识别’;’*/
count++;
break;
}
readch();
}
buf[count].sy1=-1;/*不可识别的符号*/
}
(3)变量处理及变量名表find()
变量处理中首先把以字母开头的字母数字串存到spelling[10]数组中,然后进行识别。
识别过程是先让它与保留关键字表中的所有关键字进行匹配,若获得成功则说明它为保留关键字,即将其内码值写入二元式结果缓冲区;否则说明其为变量,这时让它与变量名表中的变量进行匹配(变量匹配函数find()),如果成功,则说明该变量已存在并在二元式结果缓冲区中标记为此变量(单词自身值填为该变量在变量名表中的位置),否则将该变量登记到变量名表中,再将这个新变量存入二元式缓存数组中。
/**********************变量匹配,查找变量名表*******************/
find(charspel[])
{
intss1=0;
intii=0;
while((ss1==0)&&(ii{
if(!
strcmp(spel,ntab1[ii]))ss1=1;/*查找,匹配*/
ii++;
}
if(ss1==1)returnii-1;/*查找到*/
elsereturn-1;/*没查找到*/
}
/***************标识符和保留字的识别******************/
identifier()
{
intiii=0,j,k;
intss=0;
k=0;
do
{
spelling[k]=ch;
k++;
readch();
}while(((ch>='a')&&(ch<='z'))||((ch>='0')&&(ch<='9')));
pline--;
spelling[k]='\0';
while((ss==0)&&(iii<10))
{
if(!
strcmp(spelling,reswords[iii].sp))ss=1;/*保留字匹配*/
iii++;
}
if(ss==1)
{
buf[count].sy1=reswords[iii-1].sy;/*是保留字*/
}
else
{
buf[count].sy1=ident;/*是标识符,变量名*/
j=find(spelling);
if(j==-1)/*没有在变量名表中则添加*/
{
buf[count].pos=tt1;/*tt1是变量名表指针*/
strcpy(ntab1[tt1],spelling);
tt1++;
nlength++;
}
elsebuf[count].pos=j;/*获得变量名自身的值*/
}
count++;
for(k=0;k<10;k++)spelling[k]='';/*清空单词符号缓冲区*/
}
(5)数字识别number()
数字识别将识别出的数字转换为等值的十进制数值并填入二元式结果缓存数组。
/***********************数字识别**********************/
number()
{
intivalue=0;
intdigit;
do
{
digit=ch-'0';
ivalue=ivalue*10+digit;/*数字字符转换为十进制整常数*/
readch();
}while((ch>='0')&&(ch<='9'));
buf[count].sy1=intconst;/*整常数单词符号二元式*/
buf[count].pos=ivalue;
count++;
pline--;
}
(6)显示函数
显示函数的功能是在屏幕上输出词法分析的结果(即二元式序列和变量名表),同时给出二元式个数及源程序行数统计。
/**************显示词法分析结果:
单词符号二元式****************/
disp()
{
inttemp1=0;
printf("\n*********词法分析结果************************\n");
for(temp1=0;temp1{
printf("%d\t%d\n",buf[temp1].sy1,buf[temp1].pos);
if(temp1==20)
{
printf("Pressanykeytocontinue.......\n");
getch();
}
}
getch();
}