一、 实验目的
设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。
二、 实验要求
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
[ 39 sizeof 24
] 40 # 0
5、 词法分析程序的主要算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到的单词符号的第一个字符的种类,拼出相应的单词符号。
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小时。
实验代码实现(C语言)
#include<stdio.h>
#include<string.h>
// typedef struct data
// {
// int syn;
// char token[20];
// int num;
// struct data *next;
// }*list;
char *rwtab[25]={"main","if","then","while","do","static","int","double","struct","break","else","long","switch","case","typedef","char","return","const","float","short","continue","for","void","sizeof"};
char *ca[19]={"+","-","*","/","**","==","<","<>","<=",">",">=","=","[","]",":","(",")"};
void pre(); //预处理
int cmpkey(char *str);
int cmpca(char *str);
int main(){
pre();
FILE *fp=fopen("D:\\AAAcode\\C_C++\\compile\\exp01\\pre.txt","rt");
FILE *result = fopen("D:\\AAAcode\\C_C++\\compile\\exp02\\input.txt","w");
char c,str[20];
int syn=0;
c=fgetc(fp);
int i=0;
while(c!=EOF){
i=0;syn=-1;
for(i=0;i<20;i++){ str[i]=0; }
str[0]=c;
if(c==' '){
c=fgetc(fp);
continue;
}
else if ((c>='a' && c<='z')||(c>='A' && c<='Z')){
for(i=0; ;i++){
str[i]=c;
c=fgetc(fp);
if(( c>='0' && c<='9' )||(c>='a' && c<='z')||(c>='A' && c<='Z')){
//这个地方好像不用
continue;
}else{
//识别是否为关键词
if(cmpkey(str)>0){
//
syn=cmpkey(str);
}else{
syn=25;
}
break;
}
}
}
else if ( c>='0' && c<='9' ){
//new
for(i=0;c>='0' && c<='9';i++){
str[i]=c;
c=fgetc(fp);
}
//识别数字
syn=26;
}
else if (cmpca(str)>=0){
//识别界符
str[0]=c;
syn=cmpca(str);
c=fgetc(fp);
str[1]=c;
if(cmpca(str)>=0){
syn=cmpca(str);
}else{
str[1]=0;
}
}
else{
printf("Error!\n");
c=fgetc(fp);
continue;
}
fwrite(&syn,sizeof(int),1,result);
printf("%-20s %d\n",str,syn);
}
}
void pre(){
FILE *fpr = fopen("D:\\AAAcode\\C_C++\\compile\\exp01\\text.txt","rt");
FILE *fpw = fopen("D:\\AAAcode\\C_C++\\compile\\exp01\\pre.txt","w");
char c=' ',d=0;
// c=fgetc(fpr);
while(c!=EOF){
do{
fputc(c,fpw);
c=fgetc(fpr);
//去掉注释
if(c=='/'){
d=fgetc(fpr);
if(d=='/'){
do{
c=fgetc(fpr);
}while(c!='\n'&&c!='\r');
}else if(d=='*'){
do{
c=fgetc(fpr);
if(c=='*'){
d=fgetc(fpr);
if(d=='/'){
c=' ';
break;
}
}
}while(1);
}
else{
fputc(c,fpw);
c=d;
}
}
}while(c!=' '&&c!='\n'&&c!='\t'&&c!=EOF);
//处理空格
do{
c=fgetc(fpr);
//
if(c=='/'){
d=fgetc(fpr);
if(d=='/'){
do{
c=fgetc(fpr);
}while(c!='\n'&&c!='\r');
}else if(d=='*'){
do{
c=fgetc(fpr);
if(c=='*'){
d=fgetc(fpr);
if(d=='/'){
c=' ';
break;
}
}
}while(1);
}
else{
fputc(c,fpw);
c=d;
}
}
} while (c==' '||c=='\n'||c=='\t');
fputc(' ',fpw);
}
fclose(fpr);
fclose(fpw);
}
int cmpkey(char *str){
for(int i=0;i<24;i++){
if(strcmp(str,rwtab[i])==0){
return i+1;
}
}
return -1;
}
int cmpca(char str[]){
if(strcmp(str,"#")==0) return 0;
for(int i=0;i<17;i++){
if(strcmp(str,ca[i])==0){
return i+27;
}
}
return -1;
}