【编译原理】实验一 源程序的预处理及词法分析程序设计

一、 实验目的

设计并实现一个包含预处理功能的词法分析程序,加深对编译中词法分析过程的理解。

二、 实验要求

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  词法分析主程序示意图

其中初值包括如下两方面:

  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;
}

  • 15
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值