Cygwin环境的熟悉和lex的使用1

                      Cygwin环境的熟悉和lex的使用1

一. 目的:

     熟悉cygwin环境的使用,学习使用lex写简单的词法分析程序,会在cygwin环境下使用flex调试lex写的程序。

二. 内容:

      读懂exam1.l和exam2.l两个例子,使用cygwin下的flex工具将exam1.l和exam2.l编译并调试通过。并且修改exam2.l,在其基础上增加如下记号:

      (1)  左右大小括号:{ } ( )

      (2)  将关系算符改写成C中的形式

      (3)  分号、赋值号:;  =

      (4)  关键字:if else

      (5)  双斜线表示的注释://

      (6)  算术运算符号:+ - * /

      (7) 将标识符改为可含有下划线,并且可以以下划线开头

      (8) 将注释内容忽略

      完善exam1.l中installID和installNum两辅助函数的功能.

三.要求:

       在cygwin下用flex和gcc工具将实验调试通过,并写出测试例测试正确性。

四.参考:

       exam1.l 和exam2.l为测试例子。Test1.p和test2.p可分别作为两个程序的测试用例。

五.源代码:

       1.l:

%{
#include <stdio.h> 
#define LT					1
#define	LE					2
#define GT					3
#define	GE					4
#define	EQ					5
#define NE					6
#define ADD					7
#define JIAN					8
#define CHEN					9
#define CHU					10
#define FUZHI				11
#define WHILE				18
#define	DO				19
#define IF				11
#define	ELSE				12
#define ID          20
#define NUMBER      21
#define RELOP       22
#define NEWLINE     23
#define ERRORCHAR   24

int yylval;
%}

delim		[ \t \n]
string  id
ws			{delim}+
letter	[A-Za-z]
digit		[0-9]
id			(_)*{letter}(_)*({letter}|{digit})*
number	{digit}+(\.{digit}+)?(E[+-]?{digit}+)?
/* 状态(或条件)定义可以定义在这里 
 * INITIAL是一个默认的状态,不需要定义
 */
%s COMMENT  
%s ZHUSHI
%%

<INITIAL>"/*"						{BEGIN COMMENT;ECHO;}
<COMMENT>"*/"						{BEGIN INITIAL;ECHO;}
<COMMENT>.|\n						{ECHO;}
<INITIAL>"\\"						{BEGIN ZHUSHI;;}
<ZHUSHI>"\t"						{BEGIN INITIAL;;}
<ZHUSHI>.|\n	          {;}
 /* ECHO是一个宏,相当于 fprintf(yyout, "%s", yytext)*/
<INITIAL>{ws}	          {;}
<INITIAL>while					{return (WHILE);}
<INITIAL>if					{return (IF);}
<INITIAL>else					{return (ELSE);}
<INITIAL>do		          {return (DO);}
<INITIAL>{id}	          {yylval = installID ();return (ID);}
<INITIAL>{number}	      {yylval = installNum ();return (NUMBER);}
<INITIAL>"<"	          {yylval = LT;return (RELOP);}
<INITIAL>"<="	          {yylval = LE;return (RELOP);}
<INITIAL>"=="	          {yylval = EQ;return (RELOP);}
<INITIAL>"!="	          {yylval = NE;return (RELOP);}
<INITIAL>">"	          {yylval = GT;return (RELOP);}
<INITIAL>">="	          {yylval = GE;return (RELOP);}
<INITIAL>"{"	          {return (RELOP);}
<INITIAL>"}"	          {return (RELOP);}
<INITIAL>"("	          {return (RELOP);}
<INITIAL>")"	          {return (RELOP);}
<INITIAL>";"	          {return (RELOP);}
<INITIAL>"+"	          {yylval = ADD;return (RELOP);}
<INITIAL>"-"	          {yylval = JIAN;return (RELOP);}
<INITIAL>"*"	          {yylval = CHEN;return (RELOP);}
<INITIAL>"/"	          {yylval = CHU;return (RELOP);}
<INITIAL>"="	          {yylval = FUZHI;return (RELOP);}
<INITIAL>.							{return ERRORCHAR;}

%%
int installID () {
  /* 把词法单元装入符号表并返回指针。*/
	return ID;
}
int installNum () {
	/* 类似上面的过程,但词法单元不是标识符而是数 */
  return NUMBER;
}
int yywrap (){
  return 1;
}

void writeout(int c){
  switch(c){
  	case ERRORCHAR: fprintf(yyout, "(ERRORCHAR, \"%s\") ", yytext);break;
  	case RELOP: fprintf(yyout, "(RELOP, \"%s\") ", yytext);break;  	  
    case WHILE: fprintf(yyout, "(WHILE, \"%s\") ", yytext);break;
    case DO: fprintf(yyout, "(DO, \"%s\") ", yytext);break;
    case IF: fprintf(yyout, "(IF, \"%s\") ", yytext);break;
    case ELSE: fprintf(yyout, "(ELSE, \"%s\") ", yytext);break;
    case NUMBER: fprintf(yyout, "(NUM, \"%s\") ", yytext);break;
    case ID: fprintf(yyout, "(ID, \"%s\") ", yytext);break;
    case NEWLINE: fprintf(yyout, "\n");break;
    default:break;
  }
  return;
}

int main (int argc, char ** argv){
	int c,j=0;
	if (argc>=2){
	  if ((yyin = fopen(argv[1], "r")) == NULL){
	    printf("Can't open file %s\n", argv[1]);
	    return 1;
	  }
	  if (argc>=3){
	    yyout=fopen(argv[2], "w");
	  }
	}
	while (c = yylex()){
		writeout(c);
		j++;
		if (j%5 == 0) writeout(NEWLINE);
	}
	if(argc>=2){
	  fclose(yyin);
	  if (argc>=3) fclose(yyout);
	}
	return 0;
}<strong>
</strong>

      Test.p:

while _a >= -1.2E-2  do b_x<=2  {if(c!=5)c==(d+e)*f; else c=(e-f)/2;}

六.结果及分析:

(WHILE,while),(ID,_a),( RELOP,>=),( NUM,-1.2E-2),(DO,do),(ID,b_x),( RELOP,<=), ( NUM,2), ( RELOP,{), ( RELOP,(), (ID,c), ( RELOP,!=), (NUM,5), ( RELOP,)), (ID,c), ( RELOP,==), ( RELOP,(), (ID,d), ( RELOP,+), (ID,e), ( RELOP,*), ( ID,f), ( RELOP,;), ( ELSE,else), (ID,c), ( RELOP,=), ( RELOP,(), (ID,e), ( RELOP,-), (ID,f), ( RELOP,)), ( RELOP,/), ( NUM,2), ( RELOP,;),  (RELOP,})

       词法分析器从第一个字符开始扫描,将相应的字符与匹配的类别输出在屏幕上,忽略空格和换行字符,将注释也忽略,能识别“;”和“=”。

七.附录

     exam1.l
/* 这是注释的形式,与C中的/*...* /注释相同。 */
/* 第一部分是定义、声明部分。这部分内容可以为空。*/

%{

/* 写在 %{...%}这对特殊括号内的内容会被直接拷贝到C文件中。
 *
 * 这部分通常进行一些头文件声明,变量(全局,外部)、常量
 * 的定义,用C语法。
 *
 * %{和%}两个符号都必须位于行首 
 */

/* 下面定义了需要识别的记号名,如果和yacc联合使用,这些记号名都应该在yacc中定义 */
#include <stdio.h> 
#define LT					1
#define	LE					2
#define GT					3
#define	GE					4
#define	EQ					5
#define NE					6

#define WHILE				18
#define	DO					19
#define ID          20
#define NUMBER      21
#define RELOP       22

#define NEWLINE     23
#define ERRORCHAR   24

int yylval;
/* yylval 是yacc中定义的变量,用来保存记号的属性值,默认是int类型。 
 * 在用lex实现的词法分析器中可以使用这个变量将记号的属性传递给用
 * yacc实现的语法分析器。
 *
 * 注意:该变量只有在联合使用lex和yacc编写词法和语法分析器时才可在lex
 *       中使用,此时该变量不需要定义即可使用。
 *       单独使用lex时,编译器找不到这个变量。这里定义该变量为了“欺骗”编译器。
 */
 

%}

/* 这里进行正规定义和状态定义。
 * 下面就是正规定义,注意,正规定义和状态定义都要顶着行首写。
 */
 
delim		[ \t \n]
/* \用来表示转义,例如\t表示制表符,\n表示换行符。*/
ws			{delim}+
letter	[A-Za-z_]
digit		[0-9]
id			{letter}({letter}|{digit})*
/* 注意:上面正规定义中出现的小括号表示分组,而不是被匹配的字符。
 *       而大括号括起的部分表示正规定义名。
 */
number	{digit}+(\.{digit}+)?(E[+-]?{digit}+)?



/* %%作为lex文件三个部分的分割符,必须位于行首 */
/* 下面这个%%不能省略 */
%%

  /* 第二部分是翻译规则部分。 */
  /* 写在这一部分的注释要有前导空格,否则lex编译出错。*/
  /* 翻译规则的形式是:正规式  {动作}
   * 其中,正规式要顶行首写,动作要以C语法写(动作会被拷贝到yylex()函数中,),\
   * 正规式和动作之间要用空白分割。
   */
  
{ws}	          {;/* 此时词法分析器没有动作,也不返回,而是继续分析。 */}
  /* 正规式部分用大括号扩住的表示正规定义名,例如{ws}。
   * 没有扩住的直接表示正规式本身。
   * 一些元字符没办法表示它本身,此时可以用转义字符或
   * 用双引号括起来,例如"<"
   */
while	          {return (WHILE);}
do		          {return (DO);}
{id}	          {yylval = installID (); return (ID);}
{number}	      {yylval = installNum (); return (NUMBER);}
"<"	            {yylval = LT; return (RELOP);}
"<="	          {yylval = LE; return (RELOP);}
"="	            {yylval = EQ; return (RELOP);}
"<>"	          {yylval = NE; return (RELOP);}
">"	            {yylval = GT; return (RELOP);}
">="	          {yylval = GE; return (RELOP);}

.								{yylval = ERRORCHAR; return ERRORCHAR;}
 /*.匹配除换行之外的任何字符,一般可作为最后一条翻译规则。*/
 
%%
/* 第三部分是辅助函数部分,这部分内容以及前面的%%都可以省略 */
/* 辅助函数可以定义“动作”中使用的一些函数。这些函数
 * 使用C语言编写,并会直接被拷贝到lex.yy.c中。
 */

int installID () {
  /* 把词法单元装入符号表并返回指针。*/
	return ID;
}


int installNum () {
	/* 类似上面的过程,但词法单元不是标识符而是数 */
  return NUMBER;
}


/* yywrap这个辅助函数是词法分析器遇到输入文件结尾时会调用的,用来决定下一步怎么做:
 * 若yywrap返回0,则继续扫描;返回1,则词法分析器返回报告文件已结束的0。
 * lex库中的标准yywrap程序就是返回1,你也可以定义自己的yywrap。
 */
int yywrap (){
  return 1;
}

void writeout(int c){
  switch(c){
  	case ERRORCHAR: fprintf(yyout, "(ERRORCHAR, \"%s\") ", yytext);break;
  	case RELOP: fprintf(yyout, "(RELOP, \"%s\") ", yytext);break;  	  
    case WHILE: fprintf(yyout, "(WHILE, \"%s\") ", yytext);break;
    case DO: fprintf(yyout, "(DO, \"%s\") ", yytext);break;
    case NUMBER: fprintf(yyout, "(NUM, \"%s\") ", yytext);break;
    case ID: fprintf(yyout, "(ID, \"%s\") ", yytext);break;
    case NEWLINE: fprintf(yyout, "\n");break;
    default:break;
  }
  return;
}

/* 辅助函数里可以使用yytext和yyleng这些外部定义的变量。
 * yytext指向输入缓冲区当前词法单元(lexeme)的第一个字符,
 * yyleng给出该词法单元的长度		*/

/* 如果你的词法分析器并不是作为语法分析器的子程序,
 * 而是有自己的输入输出,你可以在这里定义你的词法
 * 分析器的main函数,main函数里可以调用yylex()
 */

int main (int argc, char ** argv){
	int c,j=0;
	if (argc>=2){
	  if ((yyin = fopen(argv[1], "r")) == NULL){
	    printf("Can't open file %s\n", argv[1]);
	    return 1;
	  }
	  if (argc>=3){
	    yyout=fopen(argv[2], "w");
	  }
	}
	/* yyin和yyout是lex中定义的输入输出文件指针,它们指明了
	 * lex生成的词法分析器从哪里获得输入和输出到哪里。
	 * 默认:键盘输入,屏幕输出。 
	 */
	while (c = yylex()){
		writeout(c);
		j++;
		if (j%5 == 0) writeout(NEWLINE);
	}
	if(argc>=2){
	  fclose(yyin);
	  if (argc>=3) fclose(yyout);
	}
	return 0;
}
     exam2.l
%{

#include <stdio.h> 
#define LT					1
#define	LE					2
#define GT					3
#define	GE					4
#define	EQ					5
#define NE					6
#define LLK                                     7
#define RLK                                     8
#define LBK                                     9
#define RBK                                     10
#define IF                               11
#define ELSE                             12
#define EQU                              13
#define SEM                              14

#define WHILE				18
#define	DO					19
#define ID          20
#define NUMBER      21
#define RELOP       22

#define NEWLINE     23
#define ERRORCHAR   24
#define ADD                       25
#define  DEC                         26
#define  MUL                         27
#define  DIV                        28


%}

 
delim		[ \t \n]
ws			{delim}+
letter	[A-Za-z_]
digit		[0-9]
id			{letter}({letter}|{digit})*
number	{digit}+(\.{digit}+)?(E[+-]?{digit}+)?

/* 状态(或条件)定义可以定义在这里 
 * INITIAL是一个默认的状态,不需要定义
 */
%s COMMENT
%s COMMENT2
%%

<INITIAL>"/*"						{BEGIN COMMENT;}
<COMMENT>"*/"						{BEGIN INITIAL;}
<COMMENT>.|\n						{;}
<INITIAL>"//"						{BEGIN COMMENT2;}
<COMMENT2>\n					{BEGIN INITIAL;}
<COMMENT2>.					{;}

 /* ECHO是一个宏,相当于 fprintf(yyout, "%s", yytext)*/

<INITIAL>{ws}	          {;}
<INITIAL>while					{return (WHILE);}
<INITIAL>do		          {return (DO);}
<INITIAL>if		          {return (IF);}
<INITIAL>else		          {return (ELSE);}
<INITIAL>{id}	          {return (ID);}
<INITIAL>{number}	      {return (NUMBER);}
<INITIAL>"<"	          {return (RELOP);}
<INITIAL>"<="	          {return (RELOP);}
<INITIAL>"="	          {return (RELOP);}
<INITIAL>"!="	          {return (RELOP);}
<INITIAL>">"	          {return (RELOP);}
<INITIAL>">="	          {return (RELOP);}
<INITIAL>"("	          {return (RELOP);}
<INITIAL>")"	          {return (RELOP);}
<INITIAL>"{"	          {return (RELOP);}
<INITIAL>"}"	          {return (RELOP);}
<INITIAL>"+"	          {return (RELOP);}
<INITIAL>"-"	          {return (RELOP);}
<INITIAL>"*"	          {return (RELOP);}
<INITIAL>"/"	          {return (RELOP);}
<INITIAL>";"	          {return (RELOP);}

<INITIAL>.							{return ERRORCHAR;}

 
%%

int yywrap (){
  return 1;
}

void writeout(int c){
  switch(c){
  	case ERRORCHAR: fprintf(yyout, "(ERRORCHAR, \"%s\") ", yytext);break;
  	case RELOP: fprintf(yyout, "(RELOP, \"%s\") ", yytext);break;  	  
    case WHILE: fprintf(yyout, "(WHILE, \"%s\") ", yytext);break;
    case DO: fprintf(yyout, "(DO, \"%s\") ", yytext);break;
    case IF: fprintf(yyout, "(IF, \"%s\") ", yytext);break;
    case ELSE: fprintf(yyout, "(ELSE, \"%s\") ", yytext);break;
    case NUMBER: fprintf(yyout, "(NUM, \"%s\") ", yytext);break;
    case ID: fprintf(yyout, "(ID, \"%s\") ", yytext);break;
    case NEWLINE: fprintf(yyout, "\n");break;
    default:break;
  }
  return;
}


int main (int argc, char ** argv){
	int c,j=0;
	if (argc>=2){
	  if ((yyin = fopen(argv[1], "r")) == NULL){
	    printf("Can't open file %s\n", argv[1]);
	    return 1;
	  }
	  if (argc>=3){
	    yyout=fopen(argv[2], "w");
	  }
	}

	while (c = yylex()){
		writeout(c);
		j++;
		if (j%5 == 0) writeout(NEWLINE);
	}
	if(argc>=2){
	  fclose(yyin);
	  if (argc>=3) fclose(yyout);
	}
	return 0;
}


  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值