字符串输入到flex lexer

bjo*_*rns 52 c yacc lex bison flex-lexer

我想使用flex/bison解析器创建一个read-eval-print循环.麻烦的是,flex生成的词法分析器需要输入FILE*类型,我希望它是char*.反正有没有这样做?

一个建议是创建一个管道,将其提供给字符串并打开文件描述符并发送给词法分析器.这很简单,但感觉很复杂,而且与平台无关.有没有更好的办法?

dfa*_*dfa 55

以下例程可用于设置输入缓冲区以扫描内存中的字符串而不是文件(如yy_create_buffer所做的那样):

  • YY_BUFFER_STATE yy_scan_string(const char *str):扫描NUL终止的字符串
  • YY_BUFFER_STATE yy_scan_bytes(const char *bytes, int len):从位置字节开始扫描len个字节(包括可能的NUL)

请注意,这两个函数都创建,返回相应的YY_BUFFER_STATE句柄(完成后必须使用yy_delete_buffer()删除它),因此yylex()扫描字符串或字节的副本.这种行为可能是合乎需要的,因为yylex()会修改它正在扫描的缓冲区的内容.

如果你想避免副本(和yy_delete_buffer)使用:

  • YY_BUFFER_STATE yy_scan_buffer(char *base, yy_size_t size)

样本主要:

int main() {
    yy_scan_buffer("a test string");
    yylex();
}
Run Code Online (Sandbox Code Playgroud)

  • 样本main可能会失败,因为`yy_scan_buffer`需要一个可写缓冲区(它暂时修改缓冲区,插入NUL来终止`yytext`然后恢复原始字符),并且它需要两个终止NUL字节. (3认同)
  • 如果它包含1.`yy_scan_string`而不是`yy_scan_buffer`和2.清理,那么该示例将是正确的.`scan_string`自动设置一个缓冲区(需要清理),不需要长度规范或双空终止符. (2认同)

unw*_*ind 20

有关如何扫描内存缓冲区(如字符串)的信息,请参阅Flex手册的此部分.


sev*_*vko 11

柔性可以解析char *使用三种功能中的任何一个:yy_scan_string(), yy_scan_buffer(),和yy_scan_bytes()(参见文档).这是第一个例子:

typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_string(char * str);
extern void yy_delete_buffer(YY_BUFFER_STATE buffer);

int main(){
    char string[] = "String to be parsed.";
    YY_BUFFER_STATE buffer = yy_scan_string(string);
    yyparse();
    yy_delete_buffer(buffer);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

等价语句yy_scan_buffer()(需要双重以空字符结尾的字符串):

char string[] = "String to be parsed.\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
Run Code Online (Sandbox Code Playgroud)

我的回答重申了@dfa和@jlholland提供的一些信息,但他们的答案代码似乎都不适合我.


小智 8

这是我需要做的:

extern yy_buffer_state;
typedef yy_buffer_state *YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_buffer(char *, size_t);

int main(int argc, char** argv) {

  char tstr[] = "line i want to parse\n\0\0";
  // note yy_scan_buffer is is looking for a double null string
  yy_scan_buffer(tstr, sizeof(tstr));
  yy_parse();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

你不能extern typedef,这在你想到它时才有意义.

  • 只需指定一个“\0”,因为第二个隐式存在(由于字符串文字)。 (2认同)

Tad*_*cci 5

接受的答案是不正确的。会导致内存泄漏。

在内部,yy_scan_string 调用 yy_scan_bytes,后者又调用 yy_scan_buffer。

yy_scan_bytes 为输入缓冲区的副本分配内存。

yy_scan_buffer 直接作用于提供的缓冲区。

对于所有三种形式,您必须调用 yy_delete_buffer 来释放 Flex 缓冲区状态信息 (YY_BUFFER_STATE)。

但是,使用 yy_scan_buffer,您可以避免内部缓冲区的内部分配/复制/释放。

yy_scan_buffer 的原型不采用 const char* 并且您不能期望内容保持不变。

如果您分配了内存来保存字符串,则您有责任在调用 yy_delete_buffer 之后释放它。

另外,当您仅解析此字符串时,不要忘记让 yywrap 返回 1(非零)。

下面是一个完整的例子。

%%

<<EOF>> return 0;

.   return 1;

%%

int yywrap()
{
    return (1);
}

int main(int argc, const char* const argv[])
{
    FILE* fileHandle = fopen(argv[1], "rb");
    if (fileHandle == NULL) {
        perror("fopen");
        return (EXIT_FAILURE);
    }

    fseek(fileHandle, 0, SEEK_END);
    long fileSize = ftell(fileHandle);
    fseek(fileHandle, 0, SEEK_SET);

    // When using yy_scan_bytes, do not add 2 here ...
    char *string = malloc(fileSize + 2);

    fread(string, fileSize, sizeof(char), fileHandle);

    fclose(fileHandle);

    // Add the two NUL terminators, required by flex.
    // Omit this for yy_scan_bytes(), which allocates, copies and
    // apends these for us.   
    string[fileSize] = '\0';
    string[fileSize + 1] = '\0';

    // Our input file may contain NULs ('\0') so we MUST use
    // yy_scan_buffer() or yy_scan_bytes(). For a normal C (NUL-
    // terminated) string, we are better off using yy_scan_string() and
    // letting flex manage making a copy of it so the original may be a
    // const char (i.e., literal) string.
    YY_BUFFER_STATE buffer = yy_scan_buffer(string, fileSize + 2);

    // This is a flex source file, for yacc/bison call yyparse()
    // here instead ...
    int token;
    do {
        token = yylex(); // MAY modify the contents of the 'string'.
    } while (token != 0);

    // After flex is done, tell it to release the memory it allocated.    
    yy_delete_buffer(buffer);

    // And now we can release our (now dirty) buffer.
    free(string);

    return (EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)