【编译原理】Lex词法分析器

来源:互联网 发布:成功广告案例知乎 编辑:程序博客网 时间:2024/06/11 10:34

一、实验目的

设计并实现一个词法分析器,深刻理解编译原理中词法分析器的原理。

 

二、实验内容

通过使用自己熟悉的语言设计并实现一个词法分析器,是此法分析器按要求的格式输出经过分析的程序段。

要求分析一下程序片段:

[delphi] view plaincopy在CODE上查看代码片派生到我的代码片
  1. const a=10;  
  2. var b,c;  
  3. procedure p;  
  4.   begin  
  5.     c:=b+a;  
  6.   end;  
  7.   
  8. begin  
  9.  read(b);  
  10.  while b#0 do  
  11.   begin  
  12.    call p;writeln(2*c);read(b);  
  13.   end  
  14. end.  

该程序片段存放在example.txt中。


三、实验步骤

 1、对PL\0文法中各类单词分类:

  (1)保留字:const、var、procedure、begin、end、if、then、while、do、read、call、write、writeln

  (2)常数:由0-----9这几个数字组成

  (3)标识符:由字母打头的字母和数字的字符串

  (4)运算符:+,-,*,/,:=,>=,<=,#

  (5)分界符:,、.、(、)、;

  2、将各类单词对应到lex中:

  (1)保留字:

reservedWord [const|var|procedure|begin|end|if|then|while|do|read|call|write|writeln],由于在lex中不区分大小写,所以将保留字写成:

reservedWord [cC][oO][nN][sS][tT]|[vV][aA][rR]|[pP][rR][oO][cC][eE][dD][uU][rR][eE]|

[bB][eE][gG][iI][nN]|[eE][nN][dD]|[iI][fF]|[tT][hH][eE][nN]|[wW][hH][iI]

[lL][eE]|[dD][oO]|[rR][eE][aA][dD]|[cC][aA][lL][lL]|[wW][rR][iI][tT][eE]

[wW][rR][iI][tT][eE][lL][nN]

  (2)常数:

constant ([0-9])+  /*0---9这几个数字可以重复*/

  (3)标识符:

      identfier [A-Za-z]([A-Za-z][0-9])*

  (4)运算符:

      operator \+|-|\*|\/|:=|>=|<=|#|=  /*在lex中,有特殊意义的运算符要加转义字符\,如+、*及*、/

  (5)分界符:

      delimiter [,\.;\(\)]

  3、PL/0的语言的词法分析器要求跳过分隔符(如空格,回车,制表符),对应的lex定义为:

     delim [""\n\t]

whitespace{delim}+

  4、为lex制定一些规则:

     {reservedWord}{count++;printf("\t%d\t(1,‘%s’)\n",count,yytext);}   /*对保留字定规则,输出设置*/

     {operator} {count++;printf("\t%d\t(2,‘%s’)\n",count,yytext); }

     {delimiter}{count++;printf("\t%d\t(3,‘%s’)\n",count,yytext);}

{constant}{count++;printf("\t%d\t(4,‘%s’)\n",count,yytext);}

{identfier}{count++;printf("\t%d\t(5,‘%s’)\n",count,yytext);}

{whitespace} {/* do    nothing*/ }         /*遇到空格,什么都不做*/

  5、写子程序:

   voidmain()

{

   printf("词法分析器输出类型说明:\n");

         printf("1:保留字\n");

         printf("2:运算符\n");

         printf("3:分界符\n");

         printf("4:常  数\n");

         printf("5:标识符\n");

         printf("\n");

         yyin=fopen("example.txt","r");

             yylex(); /* start the analysis*/

         fclose(yyin);

         system("PAUSE");/*暂停*/

}

 intyywrap()

 {

        return 1;

}

当lex 读完输入文件之后就会调用函数 yywrap 。如果返回1 表示程序的工作已经完成了,否则,返回 0。


四、实现的源代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. %{  
  2.     #include <stdio.h>  
  3.     #include <stdlib.h>   
  4.     int count = 0;  
  5. %}   
  6.   
  7. delim [" "\n\t]   
  8. whitespace {delim}+   
  9. operator \+|-|\*|\/|:=|>=|<=|#|=  
  10. reservedWord [cC][oO][nN][sS][tT]|[vV][aA][rR]|[pP][rR][oO][cC][eE][dD][uU][rR][eE]|[bB][eE][gG][iI][nN]|[eE][nN][dD]|[iI][fF]|[tT][hH][eE][nN]|[wW][hH][iI][lL][eE]|[dD][oO]|[rR][eE][aA][dD]|[cC][aA][lL][lL]|[wW][rR][iI][tT][eE]|[wW][rR][iI][tT][eE][lL][nN]  
  11. delimiter [,\.;\(\)]  
  12. constant ([0-9])+  
  13. identfier [A-Za-z]([A-Za-z][0-9])*  
  14. %%   
  15. {reservedWord} {count++;printf("%d\t(1,‘%s’)\n",count,yytext);}  
  16. {operator} { count++;printf("%d\t(2,‘%s’)\n",count,yytext); }  
  17. {delimiter} {count++;printf("%d\t(3,‘%s’)\n",count,yytext);}  
  18. {constant} {count++;printf("%d\t(4,‘%s’)\n",count,yytext);}  
  19. {identfier} {count++;printf("%d\t(5,‘%s’)\n",count,yytext);}   
  20. {whitespace} { /* do    nothing*/ }   
  21.   
  22. %%   
  23. void main()   
  24. {  
  25.     printf("词法分析器输出类型说明:\n");  
  26.     printf("1:保留字\n");  
  27.     printf("2:运算符\n");  
  28.     printf("3:分界符\n");  
  29.     printf("4:常  数\n");  
  30.     printf("5:标识符\n");  
  31.     printf("\n");  
  32.     yyin=fopen("example.txt","r");   
  33.         yylex(); /* start the analysis*/   
  34.     fclose(yyin);  
  35.     system("PAUSE");/*暂停停,  使DOS窗口停住*/  
  36. }   
  37.  int yywrap()   
  38.  {   
  39.     return 1;   
  40.  }   

五、实操作

将源代码存储为a.l,然后用flex(Lex)进行编译,输入flex a.l,编译后生成lex.yy.c文件,用c编译器打开(确保example.txt存储在相同目录下),编译运行即可!


六、运行结果


Lex与yacc确实是很不错的工具!如果单用编程语言,如C,C++,Java写的话,代码就多了不少。


0 1