lex yacc 入门教程(1)

声明:原创作品,转载注明出处http://www.cnblogs.com/vestinfo/

一、简介

推荐书籍《flex&bison》.

在UNIX下是flex和bison.网上介绍很多,大部分是写给懂的人看的,初学者一头雾水。这样来理解lex和yacc可能容易些:在linux下,有很多系统配置文件,一些linux下的软件也有配置文件,那么程序是如何读取配置文件中的信息的呢?

首先用到lex词法分析器,读取配置文件中的关键词(后面说到的token标记其实可看做关键词)。然后把关键词

递交给yacc,yacc对一些关键词进行匹配,看是否符合一定语法逻辑,如果符合就进行相应动作。

上面举得例子是分析配置文件内容的,当然可分析其他文件内容。

 

二、一个简单的lex文件例子

1、来看flex&bison这本书开篇给出的例子:输入几行字符串,输出行数,单词数和字符的个数。

关于yylex即lex中相关变量系列3文章介绍。

/* just like Unix wc */
%{
int chars = 0;
int words = 0;
int lines = 0;
%}
%%
[a-zA-Z]+  { words++; chars += strlen(yytext); }
\n         { chars++; lines++; }
.          { chars++; }
%%
main(int argc, char **argv)
{
  yylex();
  printf("%8d%8d%8d\n", lines, words, chars);
}

2、按照下面过程编译。

#flex test.l

#gcc lex.yy.c –lfl

#./a.out

 image9

 

 

 

3、分析这个简单的lex文件:

(1)%%把文件分为3段,第一段是c和lex的全局声明,第二段是规则段,第三段是c代码。

(2)第一段的c代码要用%{和%}括起来,第三段的c代码不用。

(3)第二段规则段,[a-zA-Z]+  \n   . 是正则表达式,{}内的是c编写的动作。

关于正则表达式系列3文章介绍。

 

4、如果不用-lfl选项,代码可以为下面这样(具体原因见lex的库和函数分析):

%{
int chars = 0;
int words = 0;
int lines = 0;
int yywrap();
%}
%%
[a-zA-Z]+  { words++; chars += strlen(yytext); }
\n         { chars++; lines++; }
.          { chars++; }
%%
main(int argc, char **argv)
{
  yylex();
  printf("%8d%8d%8d\n", lines, words, chars);
}
int yywrap()
{
	return 1;
}

 

三、修改第一个例子,将正则表达式放在全局声明中

%{
int chars = 0;
int words = 0;
int lines = 0;
%}
mywords	[a-zA-Z]+ 
mylines	\n 
mychars	.  
%%
{mywords}  { words++; chars += strlen(yytext); }
{mylines}  { chars++; lines++; }
{mychars}  { chars++; }
%%
main(int argc, char **argv)
{
  yylex();
  printf("%8d%8d%8d\n", lines, words, chars);
}

编译一同上。

四、The Scanner as Coroutine(协同程序)

即怎样将扫描到的标记给其他程序使用,下面的例子,希望扫描到+ 或 -时做一个特殊输出。

当调用yylex时,若扫描到return对应的标记时,yylex返回,且值就为return后的值;

若没扫描到return对应的标记,yylex继续执行,不返回。

下次调用自动从前一次的扫描位置处开始。

 

%{
enum yytokentype {
	ADD = 259,
	SUB = 260, 
};
%}
myadd	"+"
mysub	"-"
myother	.
%%
{myadd}    { return ADD; }
{mysub}    { return SUB; }
{myother}  { printf("Mystery character\n"); }
%%
main(int argc, char **argv)
{
	int tok;
	while(tok = yylex()) {				//yylex的返回值只能是ADD 或 SUB.
		if(tok == ADD || tok == SUB) {printf("meet + or -\n");}
		else {printf("this else statement will not be printed, \
			because if yylex return,the retrun value must be ADD or SUB.");}
	}
}

 

image21

 

 

 

 

 

 

五、yacc —— unix下是bison

1、yacc语法规则部分和BNF类同,先来看BNF巴克斯范式。

(1)<> 内包含的内容为必选项;

(2)[]  内的包含的内容为可选项;

(3){ } 内包含的为可重复0至无数次的项;

(4) | 表示在其左右两边任选一项,相当于"OR"的意思;

(5)::= 是“被定义为”的意思;

(6)双引号“”内的内容代表这些字符本身;而double _quote用来表示双引号。

(7)BNF范式举例,下面的例子用来定义java中的for语句:

     FOR_STATEMENT ::=

  "for" "(" ( variable_declaration |

  ( expression ";" ) | ";" )

  [ expression ] ";"

  [ expression ]

  ")" statement

2、yacc语法。

result: components { /*
        action to be taken in C */ }
        ;

(1)components是根据规则放在一起的终端和非终端符号,后面是{}括起来的执行的动作。

3、语法例子。

param : NAME EQ NAME { 
	printf("\tName:%s\tValue(name):%s\n", $1,$3); }			
	| NAME EQ VALUE {
	printf("\tName:%s\tValue(value):%s\n",$1,$3);}
	;
%token  A_STATE B_STATE NOT  
%%  
program :     
    A_STATE B_STATE {  
		printf("1");  
    }  
    c_state_not_token  {  
		printf("2");  
	}  
    |    NOT {   
		printf("3");  
    }  
c_state_not_token : C_STATE {}  
%% 


(1)如果匹配NAME EQ NAMENAME EQ VALUE则执行相应动作。其中标记NAME 、EQ、 VALUE是在

yacc文件第一段中定义的token,lex文件对目标扫描返回这些token。也就是说,lex文件对想解析的目标进行

扫描,然后返回需要的token(这些需要的token在.y文件中定义),yacc文件对规则冒号右边componets进行匹配,如果符合匹配则执行{}内的动作。

(2)components中的大写符号即token是在yacc文件中定义,而小写则根据下面的定义进行匹配。

A_STATE B_STATE NOT是第一段定义的token c_state_not_token是非终端符号,

在其后可以找到它的定义

4、再看一个例子以理解yacc规则。


simple_sentence: subject verb object
      |     subject verb object prep_phrase ;
subject:    NOUN
      |     PRONOUN
      |     ADJECTIVE subject ;
verb:       VERB
      |     ADVERB VERB
      |     verb VERB ;
object:     NOUN
      |     ADJECTIVE object ;
prep_phrase:     PREPOSITION NOUN ;

 

(1)理解 |  的意思,|表示左右两边任选一项,如| subject verb object prep_phrase ;中|的左边为空,

所以该句表示匹配空或者subject verb object prep_phrase ;而上面还有一句subject verb object ,

所以

simple_sentence: subject verb object

              | subject verb object prep_phrase ;

的意思是匹配subject verb object 或 subject verb object prep_phrase ;

后续关于flex和bison的联合使用见系列2、3等http://www.cnblogs.com/vestinfo/

转载于:https://www.cnblogs.com/helloweworld/archive/2012/09/29/2708931.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值