编译原理----Lex词法分析器

一、实验目的

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

 

二、实验内容

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

要求分析一下程序片段:

const a=10;
var b,c;
procedure p;
  begin
    c:=b+a;
  end;

begin
 read(b);
 while b#0 do
  begin
   call p;writeln(2*c);read(b);
  end
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。


四、实现的源代码

%{
	#include <stdio.h>
	#include <stdlib.h> 
	int count = 0;
%} 

delim [" "\n\t] 
whitespace {delim}+ 
operator \+|-|\*|\/|:=|>=|<=|#|=
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]
delimiter [,\.;\(\)]
constant ([0-9])+
identfier [A-Za-z]([A-Za-z][0-9])*
%% 
{reservedWord} {count++;printf("%d\t(1,‘%s’)\n",count,yytext);}
{operator} { count++;printf("%d\t(2,‘%s’)\n",count,yytext); }
{delimiter} {count++;printf("%d\t(3,‘%s’)\n",count,yytext);}
{constant} {count++;printf("%d\t(4,‘%s’)\n",count,yytext);}
{identfier} {count++;printf("%d\t(5,‘%s’)\n",count,yytext);} 
{whitespace} { /* do    nothing*/ } 

%% 
void main() 
{
    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");/*暂停停,  使DOS窗口停住*/
} 
 int yywrap() 
 { 
 	return 1; 
 } 

五、实操作

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


六、运行结果


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




已标记关键词 清除标记
相关推荐
实验二 词法分析器 一、实验目的 掌握词法分析器的构造原理,掌握手工编程或LEX编程方法之一。 二、实验内容 编写一个LEX源程序,使之生成一个词法分析器,能够输入的源程序转换为单词序列输出。 三、实验环境 Flex+VC6.0 四、实验注意 1.Id正则表达式:{letter}({letter}|{digit})* 2.Num正则表达式:{digit}+(\.{digit}+)?(E[+-]?{digit}+)? 3.注释:(\/\*(.)*\*\/) 4.关键字再加上其他字符就又能编程id,所以在词法分析时,id的判断应该放在关键字前面,这样才不会误判 5.由于本程序知识简单的打印数字,因此没有考虑数字的转换 6.">="比">"多一个字符,它应该放在前面判断,其他类似的也应该如此安排 五、实验代码 ******************************************************************************* 实验文件:lex.l、lex.yy.c 实验结果:lex.exe 运行方式:打开lex.exe,弹出input.txt,在其中输入所要测试的程序,保存并关闭,即可在output.txt中看到所得结果 ******************************************************************************* %{ void Install(char *type); %} %option noyywrap delim [ \t] newline [\n] digit [0-9] num {digit}+(\.{digit}+)?(E[+-]?{digit}+)? letter [A-Za-z] id {letter}({letter}|{digit})* key ("if"|"while"|"do"|"break"|"true") basic ("int"|"float"|"bool"|"char") op (">="|"<="|"=="|">"|"<"|"="|"!="|"+"|"-"|"*"|"/") comment (\/\*(.)*\*\/) %% delim {;} newline {printf("\n");} {num} {Install("Num");} {key} {Install("Key");} {basic} {Install("Basic");} {op} {Install("Op");} ";" {Install("Comma");} {id} {Install("ID");} {comment} {Install("Comment");} "(" | "[" | "{" {Install("lbracket");} ")" | "]" | "}" {Install("rbracket");} %% void Install(char *s) { fprintf(yyout, "%s:%s ", s, yytext); } int main() { printf("please input the test program in input.txt\n"); system("input.txt"); yyin = fopen("input.txt", "r"); yyout = fopen("output.txt", "w" ); yylex(); fclose(yyout); fclose(yyin); printf("analysis result in output.txt\n"); system("output.txt"); return 0; } 六、实验小结 本次的实验由于使用了flex,所以代码较短,麻烦的事flex的正则式表达,由于该使用规则只有简单介绍,而网上找的教程难免有比重就轻之嫌,所以得到上述表达式着实费力,且有的没有成功,例如bracket的(\ ((.)*\ ))或者("("(.)*")")使用时都没有成功,所以便单独写出,有点不伦不类。至于其他的,都较为简单,完。
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页