编译原理实践————flex下的词法分析器

编译原理实践————flex下的词法分析器

    • 实验目的
    • 实验原理
    • 实验设计
      • 输出形式
      • 正则表达式
    • flex/lex源程序介绍
      • 定义部分
      • 识别规则部分
      • 辅助函数部分
    • Ubuntu下flex/lex的使用
      • 测试方法
      • 测试例子
      • 测试结果
    • 测试的lex代码

实验目的

通过使用flex/lex来编写一个简单词法分析器,以便加深对词法分析的理解

实验原理

词法分析是从左往右分逐个字符地对源程序进行扫描,然后按照源程的构词规则规识别出一个个单词符号,把作为字符串的源程序等价地转化为单词符号中间程序。-----《编译与反编译技术》

实验设计

输出形式

词法分析程序输出的单词通常用二元式(单词种别,单词符合的属性值表示),但这里的输出形式为<所属类别,单词,种别码>
(1)关键字:while,for,if,else,case,int,char,void,return,main
(2)运算符:*,+, -,=,<,>,<=,>=,==,/
(3)界限符:( ) [ ] { } , : ;
(4)标识符(ID):仅由字母,数字组成的字符串
(5)常量:自然数
(6)种别码:在代码中可见

正则表达式

delim		[ \t]            // \->>转义,eg:\t->>制表符,\n->>换行符
digit        [0-9]
letter       [A-Za-z]

Identifier           {letter}({letter}|{digit})*
number	         {digit}{digit}*|0  
whitespace              {delim}+     //排除\t干扰

flex/lex源程序介绍

定义部分
%%
识别规则部分
%%
辅助函数部分

定义部分

定义部分
%%

该部分可以分为变量及引用文件声明和正则表达式声明,变量及引用文件声明可包含头文件、常数定义、全局变量定义、外部变量定义以及正规式定义,同时需要用“%{”和“%}”括起来,例如

%{
    //0-10为关键字种别码
    #include<stdio.h>
    #define While               1
    #define For                 2
  
    int  word_sum=0;                  //字符总数
    int  line=1;
%}
digit        [0-9]
letter       [A-Za-z]
Identifier           {letter}({letter}|{digit})*
number	         {digit}{digit}*|0  
%%

识别规则部分

遵循正则式-动作规则,正则式是被识别的单元,动作是词法分析器识别到相应正则式后要执行的操作,该操作可在识别规则部分直接定义,也可在辅助函数部分定义,然后进行引用,例如
直接定义:

{identifier}    fprintf(yyout,"\nline%d: <   关键字   ,   %s    ,    %d   >", line, yytext,Identifier  );

引用辅助函数:

定义部分
%%
//识别规则部分
{Identifier}  {identifier(id);}
%%
//辅助函数部分
void identifier(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   标识符   ,   %s    ,    %d   >", line, yytext,type  );
}

辅助函数部分

在这里用C语言来写识别规则部分所要用到的函数,如上面例子
这里还有一些flex/lex自带函数,这里就不列举了

Ubuntu下flex/lex的使用

测试方法

flex exp.l //默认生成lex.yy.c文件,flex -o xx.c exp.l 指定生成文件xx.c
gcc lex.yy.c //默认生成a.out gcc -o xx.out lex.yy.c 指定生成文件xxx.out
./a.out input.txt ouput.txt //这里设计的是文件的输入输出,但也可改成,键盘的输入,屏幕的输出
在这里插入图片描述
在这里插入图片描述

测试例子

int main()
{
    int a=10;
    if(a>5)  
    {
        a+=10;
        return a;
    }
    else return a+1;
}

测试结果

编译原理实践————flex下的词法分析器_第1张图片

测试的lex代码

%{
    //0-10为关键字种别码
    #include

    #define While               1
    #define For                 2
    #define If                  3
    #define Else                4
    #define Switch              5
    #define Case                6
    #define Int                 7
    #define Char                8
    #define Void                9
    #define Return              10

    //11-20为运算符种别码
    #define star                11    //   *
    #define plus                12    //   +
    #define minus               13    //   -
    #define assign              14    //   =
    #define relop_lt            15    //   <
    #define relop_gt            16    //   >
    #define relop_le            17    //   <=
    #define relop_ge            18    //   >=
    #define relop_eq            19    //   ==
    #define div                 20    //   /

    //21-27界限符种别码
    #define LP                  21    //   (
    #define RP                  22    //   )
    #define LBS                 23    //   {
    #define RBS                  24    //   }
    #define comma               25    //   ,
    #define SEM                 26    //   ;
    #define colon               27    //   :

    #define id                  28    //   标识符
    #define num                 29    //   常量
    #define Main                30
    
    // 全局常量定义
    int  word_sum=0;                  //字符总数
    int  line=1;



%}


delim		[ \t]            // \->>转义,eg:\t->>制表符,\n->>换行符
digit        [0-9]
letter       [A-Za-z]

Identifier           {letter}({letter}|{digit})*
number	         {digit}{digit}*|0  
whitespace              {delim}+

%%

\n {++line;}

while {KEYword(While);}
for   {KEYword(For);}
if    {KEYword(If);}
else  {KEYword(Else);}
case  {KEYword(Case);}
int  {KEYword(Int);}
char {KEYword(Char);}
void {KEYword(Void);}
return {KEYword(Return);}
main   {KEYword(Main);}

"*"   {Operator(star);}
"+"   {Operator(plus);}
"-"   {Operator(minus);}
"="   {Operator(assign);}
"<"   {Operator(relop_lt);}
">"   {Operator(relop_gt);}
"<="  {Operator(relop_le);}
">="  {Operator(relop_ge);}
"=="  {Operator(relop_eq);}
"/"   {Operator(div);}

"("   {Border(LP);}
")"   {Border(RP);}
"{"   {Border(LBS);}
"}"   {Border(RBS);}
","  {Border(comma);}
";"   {Border(SEM);}
":"   {Border(colon);}





{Identifier}  {identifier(id);}
{number}      {Constant(num);}
[ \t] {}

%%



void KEYword(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   关键字   ,   %s    ,    %d   >", line, yytext,type  );
}
void Operator(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   运算符   ,   %s    ,    %d   >", line, yytext,type  );
}

void  Border(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   界限符   ,   %s    ,    %d   >", line, yytext,type  );
}
void identifier(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   标识符   ,   %s    ,    %d   >", line, yytext,type  );
}

void Constant(int type)
{
    word_sum++;
    fprintf(yyout,"\nline%d: <   常量    ,   %s    ,    %d   >", line, yytext,type  );
}

int main(int argc, char **argv)
{
  if (argc>1)
  {
    FILE *file;
	file=fopen(argv[1],"r");
	if(file)
	  yyin=file;
  }
  if (argc>2)
  {
	FILE *file;
	file=fopen(argv[2],"w");
	if(file)
	{
	  yyout=file;
	  //freopen(argv[2],"w",stdout);
	 }
  }
    fprintf(yyout,"\n-----------------------------------------------------------\n");
     fprintf(yyout,"\n                      词法分析结果                          \n");
     fprintf(yyout,"\n-----------------------------------------------------------\n");
    fprintf(yyout,"行号      所属类别        单词         种别码");

  yylex();
   fprintf(yyout,"\n-----------------------------------------------------------");
   fprintf(yyout,"\n字符总数:%d ",word_sum);
    fprintf(yyout,"\n行数:%d ",line);
  yywrap();
}

int yywrap()
{
	return 1;
}



你可能感兴趣的:(编译原理,编译器)