2.04 Flex词法分析器的IO结构及输入管理

大多数情况下,flex词法分析器从文件或STDIN(终端用户)中读取输入。从文件读取和从终端读取存在着一个微小但是重要的差异——预读机制。如果词法分析器从文件读取,它可以通过大段的读操作来提高工作效率。但是如果它从终端读取,用户可能一次只输入一行,并且期望每行输入完成时,词法分析器能够立刻处理。在这种情况下处理效率不再是一个问题。幸运的是,flex词法恩稀奇会检查当前输入是否来自终端并决定使用哪种读取方式。

flex处理输入的数据结构为yy_buffer_state,而YY_BUFFER_STATE是typedef定义的yy_buffer_state结构体的指针类型。

#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
	{
	FILE *yy_input_file; /* 输入文件的句柄 */

	char *yy_ch_buf;		/* 输入缓冲区 */
	char *yy_buf_pos;		/* 在输入缓冲区中当前读取的位置 */

	/* 输入缓冲区的字节数,不包括终结符(EOB)字符。EOB为End of Block的缩写 */
	int yy_buf_size; 

	/* yy_ch_buf中已经读取了的字符数,不包括终结符(EOB)字符 */
	int yy_n_chars;

	/* 我们是否“拥有”缓冲区。也就是说,我们知道已经创建了缓冲区,并且可以重新分配以增长缓冲区,并应该适时释放缓冲区 */
	int yy_is_our_buffer;

	/* 是否是“交互性”的输入。如果是交互性输入或者以STDIN作为输入,用getc()函数代替fread()函数,使得每行结束后词法分析器可以立即处理 */
	int yy_is_interactive;

	/* 是否在行首。若是,则下次匹配时"^"规则将生效;若不是,反之 */
	int yy_at_bol;

    int yy_bs_lineno; /* 行号 */
    int yy_bs_column; /* 列号 */

	/* 在到达输入结束时,是否填充输入缓冲区 */
	int yy_fill_buffer;

    /* 缓冲区状态 */
	int yy_buffer_status;

#define YY_BUFFER_NEW 0 /* 当遇到EOF后,使用yyrestart()函数,可以将yy_buffer_status置为YY_BUFFER_NEW。这样允许用户可以重新指定下一个输入继续词法分析*/
#define YY_BUFFER_NORMAL 1 /* 一般正常情况下,yy_buffer_status是这个状态*/
#define YY_BUFFER_EOF_PENDING 2 /*当遇到了EOF但仍有一些文本要处理,yy_buffer_status置为YY_BUFFER_EOF_PENDING,以表明不应该再尝试从输入源读取数据了。但由于可能还有一些已经读取的输入还没有处理完,可能仍有许多token要匹配,直到所有为处理的字符被“耗尽”。*/
	};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */

该结构定义了一个单一输入源。它包含一个字符串缓冲区,以及一些变量和标记。通常它会有一个指向所读文件的FILE*,但是我们也可以创建一个与文件无关的YY_BUFFER_STATE实例来分析已经在内存中的字符串。

默认的flex词法分析器的输入行为大致如下:

YY_BUFFER_STATE bp;
extern FILE* yyin;

// ..... 省略,此处包含任何在第一次调用词法分析器之前所需要做的事情

if(!yyin){
	yyin = stdin; // 默认输入设备是stdin
}
bp = yy_create_buffer(yyin, YY_BUFFER_SIZE); // YY_BUFFER_SIZE由flex定义,大小通常是16k
yy_switch_to_buffer(bp); // 告诉它使用我们刚刚创建的缓冲区

如果yyin还没有被设置,就把stdin设置给它。然后使用yy_create_buffer函数创建一个读取yyin的新缓冲区,通过yy_switch_to_buffer函数来将新缓冲区切换为当前读取的输入,以便于词法分析器从最新的缓冲区读取开始分析。

当需要顺序读取多个文件时,每次打开一个文件需要调用一次yyrestart(fp)函数,把词法分析器的输入切换到输入文件fp。

其他一些函数也可以用来创建缓冲区,包括yy_scan_string(“This is a string.”)用于分析以空字符’\0’结尾的字符串,和yy_scan_buffer(char *base, size)分析长度确定的数据流。

flex提供了两个动作代码中比较有用的宏,input()和unput()。每次input()的调用将返回输入流的下一个字符。它可以帮助我们读取一小段输入而不用定义相应的模式。每次对unput©的调用把字符c推回到输入流。这个功能可以向前查看输入但不做处理。

总结以下,输入管理的三个层次是:

  • 设置yyin来读取所需文件
  • 创建并使用YY_BUFFER_STATE输入缓冲区
  • 重定义YY_INPUT
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值