编译原理实验三、 词法分析实验报告

本文档详细记录了一次编译原理实验的过程,内容涉及词法分析器的设计与实现,使用Java语言,包括实验目的、实验内容、环境配置、数据准备、程序设计与实现、实验结果分析及个人心得体会。
摘要由CSDN通过智能技术生成

目录

一、实验目的

二、实验内容

三、实验环境

四、数据准备

五、词法分析器程序设计描述

六、词法分析器程序实现展示

关键模块:

代码:

七、实验结果及分析

第一组实验:

第二组实验:

第三组实验:

八、实验心得体会


一、实验目的

理解词法分析在整个编译过程中的作用,掌握词法分析的基本原理及运行过程,并实现一个简单的词法分析器

二、实验内容

根据给定的编程语言文法(见下表),编写一个简单的词法分析器,要求该词法分析器读入指定的待分析源代码后,以“(单词/符号编码 , 单词/符号)”的格式,依次输出该源代码中所有的单词与符号。

语言文法:单词与符号分为五类——保留字、标识符、常数、运算符、界符,分类及编码的具体详情见下列各表。

保留字

单词/符号

编码

正规式

begin

beginsym

begin

end

endsym

end

input

inputsym

input

output

outputsym

output

if

ifsym

if

then

thensym

then

else

elsesym

else

elif

elifsym

elif

do

dosym

do

while

whilesym

while

break

breaksym

break

var

varsym

var

and

andsym

and

or

orsym

or

not

notsym

not

true

truesym

true

false

falsesym

false

标识符

单词/符号

编码

正规式

<标识符>

ident

(字母)(字母|数字)*

常数

单词/符号

编码

正规式

<常数>

digit

(数字)(数字)*

运算符

单词/符号

编码

正规式

+

plus

+

-

minus

-

*

times

*

/

divide

/

%

mod

%

=

becomes

=

==

eql

==

!=

neq

!=

<

lss

<

<=

leq

<=

>

gtr

>

>=

geq

>=

界符

单词/符号

编码

正规式

(

lparen

(

)

rparen

)

[

lbracket

[

]

rbracket

]

{

lcurbkt

{

}

rcurbkt

}

,

comma

,

.

period

.

输入样例

begin

var a = 6

if a%2 != 0

then a=a+1

else a=a-1

end

输出样例

(beginsym , begin)

(varsym , var)

(ident , a)

(becomes , =)

(digit , 6)

(ifsym , if)

(ident , a)

(mod , %)

(digit , 2)

(neq , !=)

(digit , 0)

(thensym , then)

(ident , a)

(becomes , =)

(ident , a)

(plus , +)

(digit , 1)

(elsesym , else)

(ident , a)

(becomes , =)

(ident , a)

(minus , -)

(digit , 1)

(endsym , end)

注:本次实验会进行大量的字符串处理及查表操作,建议各位同学使用C++、Java或python语言完成作业,不建议使用C语言。

三、实验环境

Windows或Linux系统,gcc 7.3.0,g++ 7.3.0,Java JDK 1.8,Python 3.6(以上编译器\解释器均可使用更高版本)。

四、数据准备

data文件夹下的三个txt文件,为本次实验中需要进行词法分析的源程序代码数据。

五、词法分析器程序设计描述

 

六、词法分析器程序实现展示

关键模块:

  1. 初始化数据keyWord、keyCode、symbolCode

class Classfier{

private:

      map<string,string>keyCode,symbolCode;

      set<string>keyWord;

     

public:

   Classfier(){

     

      keyCode.insert(pair<string,string>("begin","beginsym"));

      keyCode.insert(pair<string,string>("end","endsym"));

      keyCode.insert(pair<string,string>("input","inputsym"));

      keyCode.insert(pair<string,string>("output","outputsym"));

      keyCode.insert(pair<string,string>("if","ifsym"));

      keyCode.insert(pair<string,string>("then","thensym"));

      keyCode.insert(pair<string,string>("else","elsesym"));

      keyCode.insert(pair<string,string>("elif","elifsym"));

      keyCode.insert(pair<string,string>("do","dosym"));

      keyCode.insert(pair<string,string>("while","whilesym"));

      keyCode.insert(pair<string,string>("break","breaksym"));

      keyCode.insert(pair<string,string>("var","varsym"));

      keyCode.insert(pair<string,string>("and","andsym"));

      keyCode.insert(pair<string,string>("or","orsym"));

      keyCode.insert(pair<string,string>("not","notsym"));

      keyCode.insert(pair<string,string>("true","truesym"));

      keyCode.insert(pair<string,string>("false","falsesym"));

     

     

      keyWord.insert("begin");

      keyWord.insert("end");

      keyWord.insert("input");

      keyWord.insert("output");

      keyWord.insert("if");

      keyWord.insert("then");

      keyWord.insert("else");

      keyWord.insert("elif");

      keyWord.insert("do");

      keyWord.insert("while");

      keyWord.insert("break");

      keyWord.insert("var");

      keyWord.insert("and");

      keyWord.insert("or");

      keyWord.insert("not");

      keyWord.insert("true");

      keyWord.insert("false");

     

     

      symbolCode.insert(pair<string,string>("+","puls"));

      symbolCode.insert(pair<string,string>("-","minus"));

      symbolCode.insert(pair<string,string>("*","times"));

      symbolCode.insert(pair<string,string>("/","divide"));

      symbolCode.insert(pair<string,string>("%","mode"));

      symbolCode.insert(pair<string,string>("=","becomes"));

      symbolCode.insert(pair<string,string>("==","eql"));

      symbolCode.insert(pair<string,string>("!=","neq"));

      symbolCode.insert(pair<string,string>("<","lss"));

      symbolCode.insert(pair<string,string>("<=","leq"));

      symbolCode.insert(pair<string,string>(">","gtr"));

      symbolCode.insert(pair<string,string>(">=","geq"));

      symbolCode.insert(pair<string,string>("(","lparen"));

      symbolCode.insert(pair<string,string>(")","rparen"));

      symbolCode.insert(pair<string,string>("[","lbracket"));

      symbolCode.insert(pair<string,string>("]","rbracket"));

      symbolCode.insert(pair<string,string>("{","lcurbkt"));

      symbolCode.insert(pair<string,string>("}","lcurbkt"));

      symbolCode.insert(pair<string,string>(",","comma"));

      symbolCode.insert(pair<string,string>(".","period"));

   }

  1. 判断字符是否为数字或字母函数、判断字符串是否为数字或关键字函数、输出函数

bool isLetter(char ch){

   if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')){

      return true;

   }else{

      return false;

   }

}

bool isNumber(char ch){

   if(ch>='0'&&ch<='9'){

      return true;

   }else{

      return false;

   }

}

void printResult(string code,string word){

  

   cout<<"("<<code<<","<<word<<")\n";

}

代码:

#include<iostream>

#include<fstream>

#include<string>

#include<set>

#include<map>

using namespace std;

#define IDENT "ident"

#define DIGIT "digit"

#define ERROR "error"

bool isLetter(char ch){

   if((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')){

      return true;

   }else{

      return false;

   }

}

bool isNumber(char ch){

   if(ch>='0'&&ch<='9'){

      return true;

   }else{

      return false;

   }

}

void printResut1(string code,string word){

  

   cout<<"("<<code<<","<<word<<")\n";

}

class Classfier{

private:

      map<string,string>keyCode,symbolCode;

      set<string>keyWord;

     

public:

   Classfier(){

     

      keyCode.insert(pair<string,string>("begin","beginsym"));

      keyCode.insert(pair<string,string>("end","endsym"));

      keyCode.insert(pair<string,string>("input","inputsym"));

      keyCode.insert(pair<string,string>("output","outputsym"));

      keyCode.insert(pair<string,string>("if","ifsym"));

      keyCode.insert(pair<string,string>("then","thensym"));

      keyCode.insert(pair<string,string>("else","elsesym"));

      keyCode.insert(pair<string,string>("elif","elifsym"));

      keyCode.insert(pair<string,string>("do","dosym"));

      keyCode.insert(pair<string,string>("while","whilesym"));

      keyCode.insert(pair<string,string>("break","breaksym"));

      keyCode.insert(pair<string,string>("var","varsym"));

      keyCode.insert(pair<string,string>("and","andsym"));

      keyCode.insert(pair<string,string>("or","orsym"));

      keyCode.insert(pair<string,string>("not","notsym"));

      keyCode.insert(pair<string,string>("true","truesym"));

      keyCode.insert(pair<string,string>("false","falsesym"));

     

     

      keyWord.insert("begin");

      keyWord.insert("end");

      keyWord.insert("input");

      keyWord.insert("output");

      keyWord.insert("if");

      keyWord.insert("then");

      keyWord.insert("else");

      keyWord.insert("elif");

      keyWord.insert("do");

      keyWord.insert("while");

      keyWord.insert("break");

      keyWord.insert("var");

      keyWord.insert("and");

      keyWord.insert("or");

      keyWord.insert("not");

      keyWord.insert("true");

      keyWord.insert("false");

     

     

      symbolCode.insert(pair<string,string>("+","puls"));

      symbolCode.insert(pair<string,string>("-","minus"));

      symbolCode.insert(pair<string,string>("*","times"));

      symbolCode.insert(pair<string,string>("/","divide"));

      symbolCode.insert(pair<string,string>("%","mode"));

      symbolCode.insert(pair<string,string>("=","becomes"));

      symbolCode.insert(pair<string,string>("==","eql"));

      symbolCode.insert(pair<string,string>("!=","neq"));

      symbolCode.insert(pair<string,string>("<","lss"));

      symbolCode.insert(pair<string,string>("<=","leq"));

      symbolCode.insert(pair<string,string>(">","gtr"));

      symbolCode.insert(pair<string,string>(">=","geq"));

      symbolCode.insert(pair<string,string>("(","lparen"));

      symbolCode.insert(pair<string,string>(")","rparen"));

      symbolCode.insert(pair<string,string>("[","lbracket"));

      symbolCode.insert(pair<string,string>("]","rbracket"));

      symbolCode.insert(pair<string,string>("{","lcurbkt"));

      symbolCode.insert(pair<string,string>("}","lcurbkt"));

      symbolCode.insert(pair<string,string>(",","comma"));

      symbolCode.insert(pair<string,string>(".","period"));

   }

  

   ~Classfier(){

      keyCode.empty();

      symbolCode.empty();

      keyWord.empty();

   }

  

   bool isKeyWord(string word){

      set<string>::iterator it = keyWord.find(word);

      return !(it == keyWord.end());

   }

  

   bool isDigit(string word){

      int size = word.size();

      for(int i=0;i<size;++i){

         if(!isNumber(word[i])){

            return false;

         }

      }

      return true;

   }

  

   string getKeyWordCode(string word){

      return keyCode[word];

   }

  

   string getSymbolCode(string symbol){

      return symbolCode[symbol];

   }

};

int main(){

   string path;

   Classfier clsfier;

   cout<<"请输入要进行词法分析的文件名:";

   cin>>path;

   fstream file;

   file.open(path.c_str(),ios::in);

   while(!file.is_open()){

      cout<<"文件打开失败,请重新输入:";

      cin>>path;

      file.open(path.c_str(), ios::in);

   }

   string line;

   while(getline(file,line)){

      if(line.empty()) continue;

      int size = line.size(),i=0;

      while(i<size){

         if(line[i]==' '){

            while(i<size&&line[i]==' '){

               ++i;

            }

         }else if(isLetter(line[i])){

            string word;

            while(i<size&&(isLetter(line[i])||isNumber(line[i]))){

               word.push_back(line[i++]);

            }

            if(clsfier.isKeyWord(word)){

               printResut1(clsfier.getKeyWordCode(word),word);

            }else{

               printResut1(IDENT,word);

            }

         }else if(isNumber(line[i])){

            string word;

            while(i<size&&(isLetter(line[i])||isNumber(line[i]))){

               word.push_back(line[i++]);

            }

            if(clsfier.isDigit(word)){

               printResut1(DIGIT,word);

            }else{

               printResut1(ERROR,word);

            }

         }else if(line[i]=='='||line[i]=='<'||line[i]=='<'){

           

            string word;

            word.push_back(line[i++]);

            if(line[i]=='='){

               word.push_back(line[i++]);

               printResut1(clsfier.getSymbolCode(word),word);

            }else{

               printResut1(clsfier.getSymbolCode(word),word);

            }

         }else if(line[i]=='!'){

            string word;

            word.push_back(line[i++]);

            if(line[i]=='='){

               word.push_back(line[i++]);

               printResut1(clsfier.getSymbolCode(word),word);

            }else{

               printResut1(ERROR,word);

            }

         }else{

            string word;

            word.push_back(line[i++]);

            switch(word[0]){

               case'+':

               case'-':

               case'*':

               case'/':

               case'%':

               case'(':

               case')':

               case'[':

               case']':

               case'{':

               case'}':

               case',':

               case'.':

                  printResut1(clsfier.getSymbolCode(word),word);

                  break;

               default:

                  printResut1(ERROR,word);

                  break;

            }

         }

      }

   }

   file.close();

   return 0;

}

七、实验结果及分析

第一组实验:

 

运行结果:

 

第二组实验:

 

实验结果:

 

第三组实验:

 

输出结果:

 

 

八、实验心得体会

本次实验进行了大量的字符串处理及查表操作,需要思路清晰,以及在细节上的处理,最难的地方在于找逻辑关系。通过如何设计、编制并调试词法分析程序,把理论知识应用于实验中,理解了词法分析在整个编译过程中的作用,掌握了词法分析的基本原理及运行过程,也让我重新熟悉了C++的相关内容,对以后的编程有很大的帮助。

  • 6
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
设计思想 (1)程序主体结构部分: 说明部分 %% 规则部分 %% 辅助程序部分 (2)主体结构的说明 在这里说明部分告诉我们使用的LETTER,DIGIT, IDENT(标识符,通常定义为字母开头的字母数字串)和STR(字符串常量,通常定义为双引号括起来的一串字符)是什么意思.这部分也可以包含一些初始化代码.例如用#include来使用标准的头文件和前向说明(forward ,references).这些代码应该再标记"%{"和"%}"之间;规则部分>可以包括任何你想用来分析的代码;我们这里包括了忽略所有注释中字符的功能,传送ID名称和字符串常量内容到主调函数和main函数的功能. (3)实现原理 程序中先判断这个句语句中每个单元为关键字、常数、运算符、界符,对与不同的单词符号给出不同编码形式的编码,用以区分之。 PL/0语言的EBNF表示 <常量定义>::=<标识符>=<无符号整数>; <标识符>::=<字母>={<字母>|<数字>}; <加法运算符>::=+|- <乘法运算符>::=*|/ <关系运算符>::==|#|<|<=|>|>= <字母>::=a|b|…|X|Y|Z <数字>::=0|1|2|…|8|9 三:设计过程 1. 关键字:void,main,if,then,break,int,Char,float,include,for,while,printfscanf 并为小写。 2."+”;”-”;”*”;”/”;”:=“;”:”;”<“;”<=“;”>“;”>=“;”<>“;”=“;”(“;”)”;”;”;”#”为运算符。 3. 其他标记 如字符串,表示以字母开头的标识符。 4. 空格符跳过。 5. 各符号对应种别码 关键字分别对应1-13 运算符分别对应401-418,501-513。 字符串对应100 常量对应200 结束符# 四:举例说明 目标:实现对常量的判别 代码: digit [0-9] letter [A-Za-z] other_char [!-@\[-~] id ({letter}|[_])({letter}|{digit}|[_])* string {({letter}|{digit}|{other_char})+} int_num {digit}+ %% [ |\t|\n]+ "auto"|"double"|"int"|"struct"|"break"|"else"|"long"|"switch"|"case"|"enum"|"register"|"typedef"|"char"|"extern"|"return"|"union"|"const"|"float"|"short"|"unsigned"|"continue"|"for"|"signed"|"void"|"default"|"goto"|"sizeof"|"do"|"if"|"static"|"while"|"main" {Upper(yytext,yyleng);printf("%s,NULL\n",yytext);} \"([!-~])*\" {printf("CONST_string,%s\n",yytext);} -?{int_num}[.]{int_num}?([E][+|-]?{int_num})? {printf("CONST_real,%s\n",yytext);} "0x"?{int_num} {printf("CONST_int,%s\n",yytext);} ","|";"|"("|")"|"{"|"}"|"["|"]"|"->"|"."|"!"|"~"|"++"|"--"|"*"|"&"|"sizeof"|"/"|"%"|"+"|"-"|">"|"<"|">="|"<="|"=="|"!="|"&"|"^"|"|"|"&"|"||"|"+="|"-="|"*="|"/="|"%="|">>="|"<<="|"&="|"^="|"|="|"=" {printf("%s,NULL\n",yytext);} {id} {printf("ID,%s\n",yytext);} {digit}({letter})+ {printf("error1:%s\n",yytext);} %% #include <ctype.h> Upper(char *s,int l) { int i; for(i=0;i<l;i++) { s[i]=toupper(s[i]); } } yywrap() { return 1; } 五:DFA 六:数据测试 七:心得体会 其实匹配并不困难,主要是C++知识要求相对较高,只要把握住指针就好了。 附源程序: #include<iostream.h> #include<stdio.h> #include<stdlib.h> #include<string.h> int i,j,k,flag,number,status; /*status which is use to judge the string is keywords or not!*/ char ch; char words[10] = {" "}; char program[500]; int Scan(char program[]) { char *keywords[13] = {"void","main","if","then","break","int", "char","float","include","for","while","printf", "scanf"}; number = 0; status = 0; j = 0; ch = program[i++]; /* To handle the lettle space ands tab*/ /*handle letters*/ if ((ch >= 'a') && (ch <= 'z' )) { while ((ch >= 'a') && (ch <= 'z' )) { words[j++]=ch; ch=program[i++]; } i--; words[j++] = '\0'; for (k = 0; k < 13; k++) if (strcmp (words,keywords[k]) == 0) switch(k) { case 0:{ flag = 1; status = 1; break; } case 1:{ flag = 2; status = 1; break; } case 2:{ flag = 3; status = 1; break; } case 3:{ flag = 4; status = 1; break; } case 4:{ flag = 5; status = 1; break; } case 5:{ flag = 6; status = 1; break; } case 6:{ flag = 7; status = 1; break; } case 7:{ flag = 8; status = 1; break; } case 8:{ flag = 9; status = 1; break; } case 9:{ flag = 10; status = 1; break; } case 10:{ flag = 11; status = 1; break; } case 11:{ flag = 12; status = 1; break; } case 12:{ flag = 13; status = 1; break; } } if (status == 0) { flag = 100; } } /*handle digits*/ else if ((ch >= '0') && (ch <= '9')) { number = 0; while ((ch >= '0' ) && (ch <= '9' )) { number = number*10+(ch-'0'); ch = program[i++]; } flag = 200; i--; } /*opereation and edge handle*/ else switch (ch) { case '=':{ if (ch == '=') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 401; } else { i--; flag = 402; } break; } case'>':{ if (ch == '>') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 403; } else { i--; flag = 404; } break; } case'<':{ if (ch == '<') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 405; } else { i--; flag = 406; } break; } case'!':{ if (ch == '!') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 407; } else { i--; flag = 408; } break; } case'+':{ if (ch == '+') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 409; } else if (ch == '+') { words[j++] = ch; words[j] = '\0'; flag = 410; } else { i--; flag = 411; } break; } case'-':{ if (ch == '-') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 412; } else if( ch == '-') { words[j++] = ch; words[j] = '\0'; flag = 413; } else { i--; flag = 414; } break; } case'*':{ if (ch == '*') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 415; } else { i--; flag = 416; } break; } case'/':{ if (ch == '/') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 417; } else { i--; flag = 418; } break; } case';':{ words[j] = ch; words[j+1] = '\0'; flag = 501; break; } case'(':{ words[j] = ch; words[j+1] = '\0'; flag = 502; break; } case')':{ words[j] = ch; words[j+1] = '\0'; flag = 503; break; } case'[':{ words[j] = ch; words[j+1] = '\0'; flag = 504; break; } case']':{ words[j] = ch; words[j+1] = '\0'; flag = 505; break; } case'{':{ words[j] = ch; words[j+1] = '\0'; flag = 506; break; } case'}':{ words[j] = ch; words[j+1] = '\0'; flag = 507; break; } case':':{ words[j] = ch; words[j+1] = '\0'; flag = 508; break; } case'"':{ words[j] = ch; words[j+1] = '\0'; flag = 509; break; } case'%':{ if (ch == '%') words[j++] = ch; words[j] = '\0'; ch = program[i++]; if (ch == '=') { words[j++] = ch; words[j] = '\0'; flag = 510; } else { i--; flag = 511; } break; } case',':{ words[j] = ch; words[j+1] = '\0'; flag = 512; break; } case'#':{ words[j] = ch; words[j+1] = '\0'; flag = 513; break; } case'@':{ words[j] = '#'; flag = 0; break; } default:{ flag = -1; break; } } return flag; } main() { i=0; printf("please input a program end with @"); do { ch = getchar(); program[i++] = ch; }while(ch != '@'); i = 0; do{ flag = Scan(program); if (flag == 200) { printf("(%2d,%4d)",flag,number); } else if (flag == -1) { printf("(%d,error)",flag); } else { printf("(%2d,%4s)",flag,words); } }while (flag != 0); system("pause"); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

女主对此感到厌烦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值