Flex,连续扫描流(来自sockets)。 我是否错过了使用yywrap()的东西?

使用Flex进行模式识别,使用基于套接字的扫描仪(连续流)。 Flex没有找到与’array bounderies’重叠的匹配项。 所以我实现了yywrap()来设置新的数组内容,因为yylex()检测到(它将调用yywrap)。 到目前为止没有成功。

基本上(针对我的问题)这是我的代码:

%{ #include  #include  #include  #define BUFFERSIZE 26 /* 0123456789012345678901234 */ char cbuf1[BUFFERSIZE] = "Hello everybody, lex is su"; // Warning, no '\0' char cbuf2[BUFFERSIZE] = "per cool. Thanks! "; char recvBuffer[BUFFERSIZE]; int packetCnt = 0; YY_BUFFER_STATE bufferState1, bufferState2; %} %option nounput %option noinput %% "super" { ECHO; } . { printf( "%c", yytext[0] );} %% int yywrap() { int retval = 1; printf(">> yywrap()\n"); if( packetCnt <= 0 ) // Stop after 2 { // Copy cbuf2 into recvBuffer memcpy(recvBuffer, cbuf2, BUFFERSIZE); // yyrestart(NULL); // ?? has no effect // Feed new data to flex bufferState2 = yy_scan_bytes(recvBuffer, BUFFERSIZE); // packetCnt++; // Tell flex to resume scanning retval = 0; } return(retval); } int main(void) { printf("Lenght: %d\n", (int)sizeof(recvBuffer)) ; // Copy cbuf1 into recvBuffer memcpy(recvBuffer, cbuf1, BUFFERSIZE); // packetCnt = 0; // bufferState1 = yy_scan_bytes(recvBuffer, BUFFERSIZE); // yylex(); yy_delete_buffer(bufferState1); yy_delete_buffer(bufferState2); return 0; } 

这是我的输出:

 dkmbpro:test dkroeske$ ./text Lenght: 26 Hello everybody, lex is su>> yywrap() per cool. Thanks! >> yywrap() 

所以没有匹配’超级’。 根据文件,lexxer不会在yywrap之间“重置”。 我错过了什么? 谢谢。

flex提供输入流的机制是提供YY_INPUT宏的定义,每当flex需要重新填充其缓冲区时调用该宏[注1]。 使用三个参数调用宏,大致如下:

 YY_INPUT(buffer, &bytes_read, max_bytes) 

期望宏将max_bytes读入buffer ,并将bytes_read设置为读取的实际字节数。 如果此流中没有其他输入, YY_INPUT应将bytes_read设置为YY_NULL (为0)。 除了设置文件结束条件之外,无法标记输入错误。 不要将YY_INPUT设置为负值。

请注意, YY_INPUT不提供从何处读取输入或任何类型的userdata参数的指示。 唯一提供的机制是全局yyin ,它是一个FILE* 。 (您可以使用fdopen从文件/套接字描述符创建FILE*并使用fileno返回描述符。其他解决方法超出了本答案的范围。)

当扫描程序遇到流的结尾时,如YY_INPUT返回0所示,它完成当前令牌[注释2],然后调用yywrap来决定是否还有另一个要处理的流。 如手册所示,它不会重置解析器状态(即,它恰好位于哪个启动条件;如果启用了行计数,则为当前行号等)。 但是, 它不允许令牌跨越两个流。

当解析器/扫描程序应用于命令行上指定的许多不同文件时,最常使用yywrap机制。 在该用例中,如果令牌可以在一个文件中启动并继续到另一个文件中,则会有点奇怪; 大多数语言实现更喜欢他们的文件在某种程度上是独立的。 (例如,考虑多行字符串文字。)通常,您实际上也希望重置更多的解析器状态(行号,当然,有时是开始条件),但这是yywrap的责任。 [注3]

对于来自套接字的lexing,您可能希望从YY_INPUT实现中调用recv 。 但是出于实验目的,这里是一个简单的YY_INPUT ,只返回内存缓冲区中的数据:

 /* Globals which describe the input buffer. */ const char* my_in_buffer = NULL; const char* my_in_pointer = NULL; const char* my_in_limit = NULL; void my_set_buffer(const char* buffer, size_t buflen) { my_in_buffer = my_in_pointer = buffer; my_in_limit = my_in_buffer + buflen; } /* For debugging, limit the number of bytes YY_INPUT will * return. */ #define MY_MAXREAD 26 /* This is technically incorrect because it returns 0 * on EOF, assuming that YY_NULL is 0. */ #define YY_INPUT(buf, ret, maxlen) do { \ size_t avail = my_in_limit - my_in_pointer; \ size_t toread = maxlen; \ if (toread > avail) toread = avail; \ if (toread > MY_MAXREAD) toread = MY_MAXREAD; \ *ret = toread; \ memcpy(buf, my_inpointer, toread); \ my_in_pointer += toread; \ } while (0) 

笔记

  1. 这不是真的; 缓冲区状态包括一个标志,指示缓冲区是否可以重新填充。 如果使用yy_scan_bytes ,则创建的缓冲区状态将标记为不可重新填充。

  2. 它实际上比这复杂一点,因为flex扫描器有时需要向前看才能确定哪个令牌已匹配,并且在前瞻期间可能会出现流末尾指示。 在扫描程序备份到识别的令牌的末尾之后,它仍然必须重新扫描前瞻字符,这些字符可能包含多个令牌。 为了处理这个问题,它在缓冲区状态中设置了一个标志,表示已经到达流的末尾,这会阻止每次扫描器到达缓冲区末尾时调用YY_INPUT 。 尽管如此,确保您的YY_INPUT实现将继续返回流末尾以防在流结束返回后再次调用它可能是个好主意。

  3. 再举一个具体的例子,假设您想要实现某种#include机制。 flex提供了yy_push_state/yy_pop_state机制,允许您实现包含堆栈。 扫描include指令后,您将调用yy_push_state ,但需要从yywrap调用yy_pop_state 。 同样,很少有语言允许令牌在包含的源文件中启动并继续遵循include指令。

感谢大米 ,答案是重新定义YY_INPUT宏。 所以我做了:

 #undef YY_INPUT #define YY_INPUT(buf, result, max_size) inputToFlex(buf, &result, max_size) .... void inputToFlex(char *buf, unsigned long int *result, size_t max_size) { if( recv(psock, recvBuffer, RECVBUFFERSIZE, MSG_WAITALL) ) { memcpy(buf, recvBuffer, RECVBUFFERSIZE ); *result = RECVBUFFERSIZE; } else { *result = YY_NULL; } } 

这很好用,它在套接字关闭时调用yywrap()(由客户端调用)。 备注我使用的MSG_WAITALL而不是更常见的’0’。

另请注意rici的评论2.如果您的扫描仪需要查看我的解决方案是不够的,您需要实现’1字符重叠缓冲管理’。

谢谢你。 (它对二进制流也很有用)