1.内置变量yy_create_buffer:见后面的缓冲管理yy_delete_buffer:见后面的缓冲管理yy_flex_debug:见后面的缓冲管理yy_init_buffer:见后面的缓冲管理yy_flush_buffer:见后面的缓冲管理yy_load_buffer_state:见后面的缓冲管理yy_switch_to_buffer:见后面的缓冲管理yyin:输入缓冲流的文件指针,可以被替换以实现解析某个自定义的文件yyleng:当前匹配字串的长度yylex:解析函数,接口yylineno:当前匹配的文件行号yyout:输出流的指针yyrestart:手动调用yyrestart.会重启解析yyrestart(yyin);一般是打开某个文件之后,yyrestart(yyin)再解析.yytext:当前匹配的字串yywrap:解析一个文件完毕之后,会调用yywrap:返回1表示结束,0表示继续(此时最好重新打开yyin或者重置yyin流)2.几个重要函数:1).yymore():yymore()的含义是,当当前匹配的字串之后,想把后面配置的字串附加到这个字串后面,组成新的token返回.比如:%%mega-ECHO;yymore();kludgeECHO;如果:“mega-kludgethefollowingwillwritemega-mega-kludgetotheoutput。为什么呢?首先遇到mega-,接着被more了一下,因此就会把kludga附加到mega-后面,而后面的kludge的动作又是打印,因此会打印出:mega-mega-kludge2).yyless():yyless()的含义是:当当前的匹配之后,我想只返回前面几个字符,并且把后面回退到输入比如:%%foobarECHO;yyless(3);[a-z]+ECHO;inputfoobarthefollowingwillwriteoutfoobarbar:为什么呢?foobar输入之后,匹配foobar,ECHO打印出来,接着yyless(3),则输入流变为bar了(yytext为foo).接着再匹配,于是匹配到[a-z]+,因此再次打印出bar.3).BEGIN:flex下一个起始解析状态。见第3节,flex的状态.4).REJECT:相当于拒绝此匹配,让系统重新找下一个匹配。abcd,itwillwriteabcdabcabatotheoutput:%%a|ab|abc|abcdECHO;REJECT;.|\n/*eatupanyunmatchedcharacter*/5).unput(c):把c重新放到输入流。6).input():读取输入流下一个字符7).yyrestart():该函数迫使yylex重新解析。yyrestart有个函数指针流,可以再打开之后,重新使用yyrestart().3.解析源管理:1).默认是从yyin获取,而yyin则是stdout,也可以是其它文件。if(!yyin)yyin=stdin;if(!yyout)yyout=stdout;2).如果你打开了一个文件,并把yyin指向此文件,则从该文件中读取.比如:在main中:FILE*fp=NULL;fp=fopen(hell.txt,r);yyin=fp;之后再使用yylex()则flex从hell.txt中读取信息并解析.3).从字符串中解析先使用下列函数,转化缓冲,之后再使用yylex()a.yy_scan_string(char*).使用了yy_scan_string(char*)之后,flex会把char*放到yy的输入缓冲中(会调用到yy_switch_to_buffer.)b.yy_scan_bytes(constchar*base,intlen);c.yy_scan_buffer(char*base,yy_size_tsize)这几个函数内部都使用的是缓冲切换的创建等函数,见后面的章节.4).利用EOF内置规则,重新打开多个文件输入:比如:EOF{if(*++filelist)yyin=fopen(*filelist,r);elseyyterminate();}5).多缓冲问题:a.此问题可以按上面的EOF或者yywrap解决。b.另外一种形式,比如:#includeiostream或者类似于这种,这种形式的话,则不能使用yywrap,EOF来解决了。这就需要用到在flex动作中手动切换缓冲。flex对每个缓冲有个缓冲输入流指针,指向当前位置,各个被切换的缓冲互不相干扰,这恰好很好地解决了文件包含另外一个文件,而子文件也许要yylex的这种场合.这就需要使用到flex底层的缓冲管理了.见下节4.flex的缓冲管理:flex本质上都是对缓冲输入流进行yylex词法分析.缓冲是个结构体,每个缓冲有个缓冲输入流指针,指向当前位置,各个被切换的缓冲互不相干扰,而相关yyin,yyrestart,yy_create_buffer,yy_scan_string系列函数都是操纵flex底层缓冲的.flex缓冲是一个结构体:我们以下面的词法规则为例子:(来自flex官方网站的注解)/*theinclstateisusedforpickingupthename*ofanincludefile*/%xincl%{#defineMAX_INCLUDE_DEPTH10YY_BUFFER_STATEinclude_stack[MAX_INCLUDE_DEPTH];intinclude_stack_ptr=0;%}%%includeBEGIN(incl);[a-z]+ECHO;[^a-z\n]*\n?ECHO;incl[\t]*/*eatthewhitespace*/incl[^\t\n]+{/*gottheincludefilename*/if(include_stack_ptr=MAX_INCLUDE_DEPTH){fprintf(stderr,Includesnestedtoodeeply);exit(1);}include_stack[include_stack_ptr++]=YY_CURRENT_BUFFER;yyin=fopen(yytext,r);if(!yyin)error(...);yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));BEGIN(INITIAL);}EOF{if(--include_stack_ptr0){yyterminate();}else{yy_delete_buffer(YY_CURRENT_BUFFER);yy_switch_to_buffer(include_stack[include_stack_ptr]);}}YY_BUFFER_STATE就是一个缓冲。该lex文法使用到了incl,这个是状态,见4节的flex的状态管理.目前只需要知道它是个状态即可.在incl状态下才进行[\t]*的规则匹配.EOF见上面的描述,指某个输入流到了末尾则到了这个状态.BEGIN(INITIAL)类似于BEGIN(0),表示状态从开头解析(0表示不带状态的解析,也就说规则前没有这个标记的状态.上面的文法可以知道:a.在遇到include之后,跳到incl状态。b.在incl状态中,跳过空白的字符,得到文件名(includefile),先把当前的flexBuffer保存到数组栈,然后打开新的文件,并把flex的当前输入流切换到刚打开的新文件的输入流.c.切换到INITIAL状态(没有在规则前的默认的状态)d.这里用到了几个宏或者函数:yy_switch_to_buffer,yy_create_buffer,YY_CURRENT_BUFFER,yy_delete_buffer.这些函数看名字就应该知道其作用了。4.flex的状态(Startconditions).上面的缓冲管理已经涉及到状态管理了。flex的状态管理相当于普通词法的扩展。通过flex的状态,大大扩充了词法分析本身的功能。比如:a.STRING[^]*{/*eatupthestringbody...*/...}表示在STRING状态下才进行[^]*匹配。b.INITIAL,STRING,QUOTE\.{/*handleanescape...*/...}表示在INITIAL,STRING,QUOTE才匹配。\.flex的状态怎么使用呢?a.首先定义:以%开头(flex的申明本质上所有的都是以%开头)定义,有2种:%s,%x,其中%s=%x+INITIAL,也就说是%s的状态为%x定义的+INITIAL状态b.在规则域中,使用状态规则,比如comment是个状态,则有comment.\,其中.\是个lex规则文法,comment则就是一个状态了.c.有几个特殊内置的状态。INITIAL,*.比如:*规则,则表示这个规则在任何状态下有效.INITIAL是个默认状态。d.某个规则可以支持多个状态,使用“,”隔开。比如INITIAL,STRING,QUOTE规则.如果和EOF重用一个规则的话,则是quoteEOF。e.flex还提供了一套相关函数:yy_push_state,yy_pop_state,yy_top_state,BEGIN()可以说有了状态的支持,flex的功能更加强大了,简单的文法分析甚至可以不借助于yacc/bison来做了。一个完整的例子:%xstr%%charstring_buf[MAX_STR_CONST];char*string_buf_ptr;\string_buf_ptr=string_buf;BEGIN(str);str\{/*sawclosingquote-alldone*/BEGIN(INITIAL);*string_buf_ptr='\0';/*returnstringconstanttokentypeand*valuetoparser*/}str\n{/*error-unterminatedstringconstant*//*generateerrormessage*/}str\\[0-7]{1,3}{/*octalescapesequence*/intresult;(void)sscanf(yytext+1,%o,&result);if(result0xff)/*error,constantisout-of-bounds*/*string_buf_ptr++=result;}str\\[0-9]+{/*generateerror-badescapesequence;something*like'\48'or'\0777777'*/}str\\n*string_buf_ptr++='\n';str\\t*string_buf_ptr++='\t';str\\r*string_buf_ptr++='\r';str\\b*string_buf_ptr++='\b';str\\f*string_buf_ptr++='\f';str\\(.|\n)*string_buf_ptr++=yytext[1];str[^\\\n\]+{char*yptr=yytext;while(*yptr)*string_buf_ptr++=*yptr++;}5.flexC++的支持编译时,使用flex-+文件,就可以得到.cc的文件,而且flex也会生成C++相关类,对应的类和方法有:FlexLexer:成员方法有:a.yylex(),YYText(),YYLeng(),lineno(),set_debug(),debug(),b.构造函数yyFlexLexer(istream*arg_yyin=0,ostream*arg_yyout=0)c.缓冲: