实验一 源程序的预处理及词法分析程序设计
(6学时)
一、 实验目的
设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。
二、 实验要求
1、实现预处理功能
源程序中可能包含有对程序执行无意义的符号,要求将其剔除。
首先编制一个源程序的输入过程,从键盘、文件或文本框输入若干行语句,依次存入输入缓冲区(字符型数据);然后编制一个预处理子程序,去掉输入串中的回车符、换行符和跳格符等编辑性文字;把多个空白符合并为一个;去掉注释。
2、实现词法分析功能
输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。其中,
syn为单词种别码。
Token为存放的单词自身字符串。
Sum为整型常量。
具体实现时,可以将单词的二元组用结构进行处理。
3、待分析的C语言子集的词法
1)关键字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof do
所有的关键字都是小写。
2)运算符和界符
+ - * / : := < <> <= > >= = ; ( ) #
3)其他标记ID和NUM
通过以下正规式定义其他标记:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、制表符和换行符组成
空格一般用来分隔ID、NUM、专用符号和关键字,词法分析阶段通常被忽略。
4、各种单词符号对应的种别码
表1 各种单词符号的种别码
单词符号 种别码 单词符号 种别码
main 1 ; 41
if 2 ( 42
then 3 ) 43
while 4 int 7
do 5 double 8
static 6 struct 9
ID 25 break 10
NUM 26 else 11
+ 27 long 12
- 28 switch 13
* 29 case 14
/ 30 typedef 15
: 31 char 16
:= 32 return 17
< 33 const 18
<> 34 float 19
<= 35 short 20
> 36 continue 21
>= 37 for 22
= 38 void 23
default 39 sizeof 24
do 40 # 0
5、 词法分析程序的主要算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号。
1. 主程序示意图
主程序示意图如图1所示。
图1 词法分析主程序示意图
其中初值包括以下两方面:
(1) 关键字表初值
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如能查到匹配的单词,则该单词为关键字,否则为一般标识符。关键字表为一个字符串数组,其描述如下:
char *rwtab[27]={“main”,”if”,”then”,”while”,”do”,” static”,”int”,” double”,”struct”,”break”,”else”,”long”,”switch”,”case”,”typedef”,”char”,”return”,”const”,”float”,”short”,”continue”,”for”,”void”,”default”,”sizeof”,”do”};
(2) 程序中需要用到的主要变量:syn,token和sum。
2. 扫描子程序的算法思想
首先设置三个变量:token用来存放构成单词符号的字符串;sum用来存放整型单词;syn用来存放单词符号的种别编码。扫描子程序主要部分流程如图2所示。
图2 词法分析程序流程
三、实验报告要求
1.写出编程思路、源代码(或流程图);
2.写出上机调试时发现的问题,以及解决的过程;
3.写出你所使用的测试数据及结果;
4.谈谈你的体会。
5.上机6小时,完成实验报告2小时。
四、源程序如下:
#include
#include
#include
char prog1[20000],prog2[20000];
int p,q,syn,m=0;
char token[100];
char *rwtab[44]={"#","main","if","then","while","do","static","int",
"double","struct","break","else","long","switch","case","typedef",
"char","return","const","float","short","continue","for","void",
"sizeof","ID","NUM","+","-","*","/",":",":=","<","<>","<=",">",
">=","=","default","do",";","(",")"};
void Empty(char prog1[])//数组清零
{
for(int i=0;i<20000;i++)
prog1[i]=' ';
}
int isLetter(char ch)//字母判别
{
if((ch>='a'&&ch<='z')||(ch>='A')&&ch<='Z')
return 1;
else
return 0;
}
int isNum(char ch)//数字判别
{
if(ch>='0'&&ch<='9')
return 1;
else
return 0;
}
void dealEmpty(char prog1[],char prog2[])//处理空格
{
p=q=0;
char ch=prog1[p++];
while(ch!='$'){
if(ch==' '){
do{
ch=prog1[p++];
}while(ch==' ');
prog2[q++]=' ';
}
prog2[q++]=ch;
ch=prog1[p++];
}
prog2[q]='$';
}
void dealLine(char prog1[],char prog2[])//处理换行
{
p=q=0;
char ch=prog1[p++];
while(ch!='$'){
if(ch=='\n')
ch=prog1[p++];
prog2[q++]=ch;
ch=prog1[p++];
}
prog2[q]='$';
}
void dealNote(char prog1[],char prog2[])//处理注释
{
p=q=0;
char ch=prog1[p++];
while(ch!='$'){
if(ch=='/'){
ch=prog1[p++];
if(ch=='/'){
do{
ch=prog1[p++];
}while(ch!='\n');
}
if(ch=='*'){
do{
ch=prog1[p++];
}while(ch!='*'&&prog1[p]!='/');
p++;
ch=prog1[p++];
}
else{
p=p-2;
ch=prog1[p++];
}
}
prog2[q++]=ch;
ch=prog1[p++];
}
prog2[q]='$';
}
void YCL()//预处理
{
dealEmpty(prog1,prog2);
Empty(prog1);
dealLine(prog2,prog1);
Empty(prog2);
dealNote(prog1,prog2);
}
void scaner()//扫描子程序
{
for(int i=0;i<100;i++)
token[i]=' ';
char ch=prog2[p++];
while(ch==' '){
ch=prog2[p];
p++;
}
if(isLetter(ch)){
m=0;
while(isLetter(ch)||isNum(ch)){
token[m++]=ch;
ch=prog2[p++];
}
token[m++]='\0';
p--;
syn=25;
for(int i=0;i<44;i++)
if(strcmp(token,rwtab[i])==0){
syn=i;
break;
}
}
else if(isNum(ch)){
m=0;
while(isNum(ch)){
token[m++]=ch;
ch=prog2[p++];
}
token[m++]='\0';
p--;
syn=26;
}
else switch(ch){
case'<':m=0;
token[m++]=ch;
ch=prog2[p++];
if(ch=='>'){
syn=34;
token[m++]=ch;
}
else if(ch=='='){
syn=35;
token[m++]=ch;
}
else{
syn=33;
p--;
}
token[m++]='\0';
break;
case'>':m=0;
token[m++]=ch;
ch=prog2[p++];
if(ch=='='){
syn=37;
token[m++]=ch;
}
else{
syn=36;
p--;
}
token[m++]='\0';
break;
case':':m=0;
token[m++]=ch;
ch=prog2[p++];
if(ch=='='){
syn=32;
token[m++]=ch;
}
else{
syn=31;
p--;
}
token[m++]='\0';
break;
case'+':syn=27;token[0]=ch;token[1]='\0';break;
case'-':syn=28;token[0]=ch;token[1]='\0';break;
case'*':syn=29;token[0]=ch;token[1]='\0';break;
case'/':syn=30;token[0]=ch;token[1]='\0';break;
case'=':syn=38;token[0]=ch;token[1]='\0';break;
case';':syn=41;token[0]=ch;token[1]='\0';break;
case'(':syn=42;token[0]=ch;token[1]='\0';break;
case')':syn=43;token[0]=ch;token[1]='\0';break;
case'#':syn=0;token[0]=ch;token[1]='\0';break;
case'$':syn=-2;token[0]=ch;token[1]='\0';break;
default:syn=-1;token[0]=ch;token[1]='\0';break;
}
}
int main()
{
p=0;
char ch;
printf("Please input string:\n");
do{
ch=getchar();
prog1[p++]=ch;
}while(ch!='$');
prog1[p]='$';
YCL();
p=0;
do{
scaner();
if(syn==25)
printf("%s,%d\n",token,syn);
else if(syn==26)
printf("%s,%d\n",token,syn);
else if(syn==-1)
printf("不能识别字符%s\n",token);
else
printf("%s,%d\n",token,syn);
}while(syn!=-2);
system("pause");
}
五、运行结果