《编译原理》综合性
实 验 报 告
实验学期  2016    2017  学年 第  1  学期
专业  计算机科学与技术  班级      1403     
学生姓名  黄世增  学号      **********     
任课教师              赵曦               
实验成绩                                   
《编译原理》课程综合性实验报告
开课实验室:C210                                2016年 12月  6日
实验题目
        词法分析器的设计
一、实验目的
通过设计、编制、调试一个具体的词法分析程序,实现对高级程序设计语言源程序进行扫描, 并将其分解为各种单词的词法分析方法;加深对课堂教学的理解;提高词法分析方法的实践能力。
二、实验要求
任选一种高级程序设计语言编程完成词法分析器词法分析器应以教材所述分词原理为依据,使用恰当的数据结构和方法,结构清晰、高效。
编制一个读单词过程,源程序保存在文本文件(也可键盘输入)读取该文件,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、分界符五大类依次输出各个单词的内部单词种别及单词符号自身值,遇到错误时可显示“Eorror”,然后跳过错误部分继续显示。
二、实验设备与环境
1.硬件:PC机Pentium100以上。
2.软件:Win10,VS2010。
三、实验内容
1.正规文法
<关键字>-> int |for| while | do | return | break | continue
<运算符和界符>-> |+ | - | * | / |==| < | <= |!= | > | >= | , | ; | ( | ) | {|}
夏狂热
<标识符>-> letter (letter | digit)*
<整型常数>-> digit digit*
2.算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼接出相应的单词符号。
2.1 主程序
                      否
               
                        是
  输出单词二元组
 
图1 词法分析主程序示意图
其中初始包括关键字、运算符、界限符的置初值。
2.2 扫描子程序的算法思想:
在词法分析中,先以只读方式读取一个文件,自文件头开始扫描文本,滤去开头的空格、回车符、换行符等。读取的字符送入word。扫描第一个字符,看匹配的类型,并进行相应的类型分析,满足判断类型时,输出其种别码和值。
                                 
            是                        是
   
   
    字母
                                  数字                                  其他
    运算符、        符号
    界符等符号
                            否
              是
   
   
图 2 扫描子程序
四、实验步骤
编写程序时,先定义几个全局变量,key[]事先存放7个关键字,words[]用来存放识别出来的单词二元组,text用来存放从文件读取的内容,word用于存放识别出来的单词,length存放字符个数,k存放识别出来的单词个数。
首先,将文本内容读取到text中,文本内容最后一个字符是空白符,然后调用scan方法,逐个扫描每个字符,如果word的第一个字符是字母,则进行拼字符串,再判断是关键字还是标识符;如果word的第一个字符是数字,则在word清空之前判断是否有识别出非数字字符,若有,则出错,若没有,则识别出来的字符串是常数;若word第一个字符是运算符或界限符,则各自存到words[]中。最后扫描结束后输出。
五、实验结果及分析
六、实验小结和思考
通过这次实验,我对词法分析器有了进一步的了解,而且对词法分析和语法分析在实践中的应用有了深入的掌握, 让我对高级语言的学习有了更深的认识 ,了解得更透彻。
七、源程序清单
#include<stdio.h>
#include<stdlib.h>
#include<string>
using namespace std;
#define MAX 10000
struct WordString
{
    string Word;//单词
    int category;//类别
};
char *key[7] = {"int","for", "while", "do", "return", "break", "continue"};//关键字
WordString words[MAX];        //创建一个单词符号串
string text;                  //读入的文本存入text中
string word;              //分割出的单词用word表示
int length;          //字符个数
int k;                //总单词个数
void scan()
{
    int i,j;
    k=0;
    word="";
    for(i=0;i<=length-1;i++)
    {
        if(word!=""){
            if(((word[0]>='A')&&(word[0]<='Z'))||((word[0]>='a')&&(word[0]<='z')))//首字符是字母
坚强的石头专辑            {
                if(((text[i]>='A')&&(text[i]<='Z'))||((text[i]>='a')&&(text[i]<='z'))||((text[i]>=48)&&(text[i]<=57)))
                {
                    word+=text[i];
                }
                else
                {
                    words[k].Word=word;
                    淘宝背景音乐代码for(j=0;j<7;j++)
                    {
                        if(words[k].Word==key[j])
                        {
                            words[k].category=1;//表示关键字
                            就现在 吴莫愁mvbreak;
                        }
                        else if(j==6)
                            words[k].category=2;//表示标识符
                    }
                    k++;
                    word="";
                    i--;
                }
            }
            else if(word[0]==','||word[0]==';'||word[0]=='{'||word[0]=='}'||word[0]=='('||word[0]==')')//首字符是界限符
            {
                words[k].Word=word;
                words[k].category=5;//表示界限符
                k++;
                word="";
                i--;
            }
            else if(word[0]=='+'||word[0]=='-'||word[0]=='*'||word[0]=='/'||word[0]=='='||word[0]=='>'||word[0]=='<'||word[0]=='!')//首字符是运算符
            {
                if(text[i]=='=')
                {
                    word+=text[i];
                    words[k].Word=word;
                    words[k].category=4;//表示运算符
                    k++;
                    word="";
                }
                else
                {
                    words[k].Word=word;
                    words[k].category=4;//表示运算符
                    k++;
                    word="";
                    i--;
                }
            }
            else if(word[0]>=48&&word[0]<=57)//首字符是数字
            {
                if(text[i]>=48&&text[i]<=57)
                {
                    word+=text[i];
                }
                else if((text[i]>='A'&&text[i]<='Z')||(text[i]>='a'&&text[i]<='z'))
                {
                    word+=text[i];
                    words[k].category=6;//表示出错,标识符以数字开头
                }
                else
                {
                    words[k].Word=word;
                    if(words[k].category!=6)
                        words[k].category=3;//表示常数
                    k++;
                    word="";
                    i--;
                }
            }
        }
        else
        {
            if(text[i]!=10&&text[i]!=32&&text[i]!=9)
            {
                word+=text[i];
            }
        }
    }
}
int main()
{   
    FILE *fp;                                //文件指针seeya
    fp=fopen("","r");        //打开文件
    if(fp==NULL)
    {
        printf("Can't open this file!\n");
        exit(0);
    }
    int i=0;
    while(!feof(fp))                        //判断是否到文件结尾
    {
        text+=fgetc(fp);
        i++;
    }
    length=i;//text最后一个字符是空字符
    fclose(fp);                              //关闭文件
    scan();
    for吉他独奏曲谱(i=0;i<k;i++)        //输出
    {
        if(words[i].category==6)
            printf("%s Eorror\n",words[i].Word.c_str());
        else
            printf("(%d, %s)\n",words[i].category,words[i].Word.c_str());
    }
    getchar();
    return 0;
}