使用Flex进行基于套接字的扫描仪(连续流)进行模式识别。 Flex没有找到与阵列bounderies重叠的匹配项。所以我很快就实现了yywrap()来设置新的数组内容yylex()检测到<> (它将调用yywrap)。到目前为止没有成功。
基本上(为了指出我的问题)这是我的代码:
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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()
所以没有匹配超级&#39;。根据文件,lexxer没有重置&#39;在yywrap之间。我错过了什么?感谢。
答案 0 :(得分:3)
向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*
。 (您可以使用FILE*
从文件/套接字描述符创建fdopen
并使用fileno
返回描述符。其他解决方法超出了本答案的范围。)
当扫描程序遇到流的结尾时,如YY_INPUT
返回0所示,它完成当前令牌[注释2],然后调用yywrap
以确定是否有另一个流到处理。如手册所示,它不会重置解析器状态(即,它恰好位于哪个启动条件;如果启用了行计数,则为当前行号等)。但是,它不允许令牌跨越两个流。
当解析器/扫描程序应用于命令行上指定的许多不同文件时,最常使用yywrap
机制。在该用例中,如果令牌可以在一个文件中启动并继续到另一个文件中,则会有点奇怪;大多数语言实现更喜欢他们的文件在某种程度上是独立的。 (例如,考虑多行字符串文字。)通常,您实际上也希望重置更多的解析器状态(行号,当然,有时是开始条件),但这是{{1}的责任。 }。 [注3]
对于来自套接字的lexing,您可能希望从yywrap
实施中调用recv
。但是出于实验目的,这里只是一个简单的YY_INPUT
,只返回内存缓冲区中的数据:
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)
,则创建的缓冲区状态将标记为不可重新填充。
实际上有点复杂,因为flex扫描器有时需要向前看以确定哪个令牌已匹配,并且在前瞻期间可能会出现流末尾指示。在扫描程序备份到识别的令牌的末尾之后,它仍然必须重新扫描前瞻字符,这些字符可能包含多个令牌。为了处理这个问题,它在缓冲区状态中设置一个标志,表示已经到达流末尾,这样每次扫描器到达缓冲区末尾时都会阻止调用yy_scan_bytes
。尽管如此,确保您的YY_INPUT
实现将继续返回流末尾,以防在流返回结束后再次调用它。
对于另一个具体示例,假设您想要实现某种YY_INPUT
机制。 #include
提供flex
机制,允许您实现包含堆栈。扫描yy_push_state/yy_pop_state
指令后,您需要致电yy_push_state
,但需要从include
调用yy_pop_state
。同样,很少有语言允许令牌在包含的源文件中启动并继续遵循yywrap
指令。
答案 1 :(得分:2)
感谢 rice ,答案是重新定义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我用而不是更常见的&#39; 0&#39;。
另请注意 rici的评论2.如果您的扫描仪需要看起来我的解决方案是不够的, 你需要实现&#39; 1字符重叠缓冲管理&#39;。
谢谢你。 (它对二进制流也很有用)