input到flex词法分析器的string

我想创build一个使用flex / bison分析器的read-eval-print循环。 麻烦的是,flex生成的词法分析器需要FILE *types的input,我希望它是char *。 有没有办法做到这一点?

一个build议是创build一个pipe道,给它提供string并打开文件描述符并发送给词法分析器。 这是相当简单的,但它感觉错综复杂,不是平台独立。 有没有更好的办法?

以下例程可用于设置用于扫描内存string而不是文件的input缓冲区(如yy_create_buffer所做的那样):

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

请注意,这两个函数都会创build,返回相应的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(); } 

有关如何扫描内存缓冲区(例如string)的信息,请参阅Flex手册的此部分 。

这是我需要做的事情:

 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; } 

你不能extern的typedef,这是有道理的,当你考虑它。

flex可以使用以下三个函数中的任何一个来parsingchar *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; } 

yy_scan_buffer()的等价语句(它需要一个双重空string):

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

我的回答重申了@dfa和@jlholland提供的一些信息,但是他们的答案都不是我的代码。

接受的答案是不正确的。 这会造成内存泄漏。

在内部,yy_scan_string调用yy_scan_bytes,然后调用yy_scan_buffer。

yy_scan_bytes为input缓冲区的COPY分配内存。

yy_scan_buffer直接在提供的缓冲区上工作。

有了这三种forms,你必须调用yy_delete_buffer来释放弹性缓冲区状态信息(YY_BUFFER_STATE)。

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

yy_scan_buffer的原型不接受一个const char *,你不能期望内容保持不变。

如果你分配内存来保存你的string,你负责在你调用yy_delete_buffer之后释放它。

另外,当你parsingJUST这个string时,不要忘记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 (ie, 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); } 

另外,你可以在lex文件中重新定义函数YY_INPUT,然后将你的string设置为LEX的input。 如下:

 #undef YY_INPUT #define YY_INPUT(buf) (my_yyinput(buf)) char my_buf[20]; void set_lexbuf(char *org_str) { strcpy(my_buf, org_str); } void my_yyinput (char *buf) { strcpy(buf, my_buf); } 

在你的main.c中,在扫描之前,你需要先设置lex的缓冲区:

 set_lexbuf(your_string); scanning... 

这里是一个小例子,在你的cpp代码中使用bison / flex作为一个parsing器来parsingstring,并根据它改变一个string值(less数部分代码被删除,所以可能有不相关的部分)parser.y:

 %{ #include "parser.h" #include "lex.h" #include <math.h> #include <fstream> #include <iostream> #include <string> #include <vector> using namespace std; int yyerror(yyscan_t scanner, string result, const char *s){ (void)scanner; std::cout << "yyerror : " << *s << " - " << s << std::endl; return 1; } %} %code requires{ #define YY_TYPEDEF_YY_SCANNER_T typedef void * yyscan_t; #define YYERROR_VERBOSE 0 #define YYMAXDEPTH 65536*1024 #include <math.h> #include <fstream> #include <iostream> #include <string> #include <vector> } %output "parser.cpp" %defines "parser.h" %define api.pure full %lex-param{ yyscan_t scanner } %parse-param{ yyscan_t scanner } {std::string & result} %union { std::string * sval; } %token TOKEN_ID TOKEN_ERROR TOKEN_OB TOKEN_CB TOKEN_AND TOKEN_XOR TOKEN_OR TOKEN_NOT %type <sval> TOKEN_ID expression unary_expression binary_expression %left BINARY_PRIO %left UNARY_PRIO %% top: expression {result = *$1;} ; expression: TOKEN_ID {$$=$1; } | TOKEN_OB expression TOKEN_CB {$$=$2;} | binary_expression {$$=$1;} | unary_expression {$$=$1;} ; unary_expression: TOKEN_NOT expression %prec UNARY_PRIO {result = " (NOT " + *$2 + " ) " ; $$ = &result;} ; binary_expression: expression expression %prec BINARY_PRIO {result = " ( " + *$1+ " AND " + *$2 + " ) "; $$ = &result;} | expression TOKEN_AND expression %prec BINARY_PRIO {result = " ( " + *$1+ " AND " + *$3 + " ) "; $$ = &result;} | expression TOKEN_OR expression %prec BINARY_PRIO {result = " ( " + *$1 + " OR " + *$3 + " ) "; $$ = &result;} | expression TOKEN_XOR expression %prec BINARY_PRIO {result = " ( " + *$1 + " XOR " + *$3 + " ) "; $$ = &result;} ; %% lexer.l : %{ #include <string> #include "parser.h" %} %option outfile="lex.cpp" header-file="lex.h" %option noyywrap never-interactive %option reentrant %option bison-bridge %top{ /* This code goes at the "top" of the generated file. */ #include <stdint.h> } id ([a-zA-Z][a-zA-Z0-9]*)+ white [ \t\r] newline [\n] %% {id} { yylval->sval = new std::string(yytext); return TOKEN_ID; } "(" {return TOKEN_OB;} ")" {return TOKEN_CB;} "*" {return TOKEN_AND;} "^" {return TOKEN_XOR;} "+" {return TOKEN_OR;} "!" {return TOKEN_NOT;} {white}; // ignore white spaces {newline}; . { return TOKEN_ERROR; } %% usage : void parse(std::string& function) { string result = ""; yyscan_t scanner; yylex_init_extra(NULL, &scanner); YY_BUFFER_STATE state = yy_scan_string(function.c_str() , scanner); yyparse(scanner,result); yy_delete_buffer(state, scanner); yylex_destroy(scanner); function = " " + result + " "; } makefile: parser.h parser.cpp: parser.y @ /usr/local/bison/2.7.91/bin/bison -y -d parser.y lex.h lex.cpp: lexer.l @ /usr/local/flex/2.5.39/bin/flex lexer.l clean: - \rm -f *.o parser.h parser.cpp lex.h lex.cpp