ILD

Flex学习笔记5: Multiple input buffers
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2019-8-2 站点:Inside Linux Development

Multiple input buffers

一些scanner会都多个stream读取输入,由于flex使用大的buffer读取输入,因此你不能简单的写一个YY_IPUT(),因为你可能在buffer还没有处理完的时候(include语句后面还有很长的buffer)就需要切换输入文件。


为了处理这些文件,flex提供了一些机制。


YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size )

YY_BUFFER_STATE在内部是一个指针,指向一个透明的结构体struct yy_buffer_state。file只被YY_INPUT的yyin,如果你重定义了YY_IPUT,不在用它,你可以传一个NULL,size是buffer的大小,你可以使用宏YY_BUF_SIZE。


void yy_switch_to_buffer ( YY BUFFER STATE new buffer )

切换buffer


void yy_delete_buffer ( YY BUFFER STATE buffer )

删除buffer相关的存储


void yypush_buffer_state ( YY BUFFER STATE buffer )

栈操作,入栈一个buffer


void yypop_buffer_state ( )

弹出一个buffer,被弹出的buffer将使用yy_delete_buffer删除。


void yy_flush_buffer ( YY BUFFER STATE buffer )

丢掉buffer中的内容,从YY_INPUT()重新填充。


YY_CURRENT_BUFFER宏返回当前的BUFFER。


下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/* the "incl" state is used for picking up the name
* of an include file
*/
%x incl
%%
include    BEGIN(incl);
 
[a-z]+    ECHO;
[^a-z\n]*\n?    ECHO;
 
<incl>[ \t]*    /* eat the whitespace */
<incl>[^ \t\n]+    { /* got the include file name */
    yyin = fopen( yytext, "r" );
    if ( ! yyin )
        error( ... );
    yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE ));
    BEGIN(INITIAL);
}
 
<<EOF>> {
    yypop_buffer_state();
    if ( !YY_CURRENT_BUFFER )
    {
        yyterminate();
    }
}


下面的routines还可以scanning内存中的字符串。

YY_BUFFER_STATE yy_scan_string ( const char *str )

YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len )

yy会拷贝到buffer中去scan。


YY_BUFFER_STATE yy_scan_buffer (char *base, yy size t size)

这个直接scan base,最后两个字节必须为YY_END_OF_BUFFER_CHAR (ASCII NUL)


End-of-File Rules

特殊的rule <<EOF>>,表示读取到文件末尾,且yywarp()返回了非0(意味着没有更多文件了)。action必须执行下面的操作之一:


如果<<EOF>>没有指定start conditon,那么它应用到所有还没有执行<<EOF>>的start condition,想要指定一个<<EOF>>只用在初始start condition,使用:

<INITIAL><<EOF>>


Miscellaneous Macros

YY_USER_ACTION宏,在每个被匹配的rule的action执行之前,执行这个宏。

YY_NUM_RULES,rules的个数。

YY_USER_INIT,在scanner扫描之前执行的初始化。


yy_set_interactive(is_interactive)

是否是交互式输入


YY_BREAK

rules的action是一个大的swtich块,YY_BREAK用来结束一个action,通常是break


Values Available To the User

char *yytext

    存储当前token,它可以被修改,但是不能追加内容。

    如果指定了%array选项,那么yytext被声明为 char yytext[YYLMAX]


int yyleng

    存储当前token的长度


FILE *yyin

void yyrestart(FILE *new_file)

    切换yyin,但是buffer中的内容丢失了。


FILE *yyout

    ECHO使用yyout来输出。


YY_CURRENT_BUFFER

    当前buffer


YY_START

    当前start condition的整数值


Interfacing with Yacc

yacc parser-generator主要使用flex来获取token。因此yylex()的主要作用是返回下一个token的类型,以及设置yylval。


因此典型的用法:

%{

    #include "y.tab.h"

%}


%%


[0-9]+        yylval = atoi( yytext ); return TOK_NUMBER;


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.