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

时间:2014-06-01 11:31:08

标签: c lex flex-lexer

使用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之间。我错过了什么?感谢。

2 个答案:

答案 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

注释

  1. 这不是真的;缓冲区状态包括一个标志,指示缓冲区是否可以重新填充。如果您使用/* 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) ,则创建的缓冲区状态将标记为不可重新填充。

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

  3. 对于另一个具体示例,假设您想要实现某种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;。

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