C flex lexer的字符串输入
我想使用flex/bison解析器创建一个read-eval-print循环。问题是,flex生成的lexer需要FILE*类型的输入,我希望它是char*。有什么办法可以这样做吗C flex lexer的字符串输入,c,bison,yacc,lex,flex-lexer,C,Bison,Yacc,Lex,Flex Lexer,我想使用flex/bison解析器创建一个read-eval-print循环。问题是,flex生成的lexer需要FILE*类型的输入,我希望它是char*。有什么办法可以这样做吗 一个建议是创建一个管道,向其提供字符串,打开文件描述符并发送到lexer。这相当简单,但感觉很复杂,而且不太独立于平台。有更好的方法吗?有关如何扫描内存缓冲区(如字符串)的信息,请参阅Flex手册的部分。以下例程可用于设置输入缓冲区以扫描内存字符串而不是文件(如yy_create_buffer所做的): YY\u
一个建议是创建一个管道,向其提供字符串,打开文件描述符并发送到lexer。这相当简单,但感觉很复杂,而且不太独立于平台。有更好的方法吗?有关如何扫描内存缓冲区(如字符串)的信息,请参阅Flex手册的部分。以下例程可用于设置输入缓冲区以扫描内存字符串而不是文件(如yy_create_buffer所做的):
:扫描以NUL结尾的字符串`YY\u BUFFER\u STATE YY\u scan\u string(const char*str)
:从位置字节开始扫描len字节(可能包括NUL)YY_BUFFER_STATE YY_scan_bytes(const char*bytes,int len)
YY\u BUFFER\u STATE YY\u scan\u BUFFER(char*base,YY\u size\u t size)
int main() {
yy_scan_buffer("a test string");
yylex();
}
以下是我需要做的:
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;
}
您无法将typedef外部化,这在您考虑它时是有意义的。flex可以使用以下三个函数之一解析
char*
:yy\u scan\u 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\u scan\u buffer()
的等效语句(需要以双空结尾的字符串):
我的答案重申了@dfa和@jlholland提供的一些信息,但他们的答案代码似乎对我都不起作用。另外,您可以在lex文件中重新定义函数YY_INPUT,然后将字符串设置为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...
公认的答案是错误的。这将导致内存泄漏 在内部,yy_scan_字符串调用yy_scan_字节,而yy_scan_字节又调用yy_scan_缓冲区 yy_scan_字节为输入缓冲区的副本分配内存 yy_扫描_缓冲区直接作用于提供的缓冲区 对于这三种形式,您必须调用yy_delete_buffer来释放flex缓冲区状态信息(yy_buffer_state) 但是,使用yy_扫描_缓冲区,可以避免内部缓冲区的内部分配/复制/释放 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);
}
%%
返回0;
. 返回1;
%%
int yywrap()
{
申报表(1);
}
int main(int argc,const char*const argv[]
{
FILE*fileHandle=fopen(argv[1],“rb”);
if(fileHandle==NULL){
佩罗尔(“福彭”);
返回(退出失败);
}
fseek(fileHandle,0,SEEK\u END);
long fileSize=ftell(fileHandle);
fseek(fileHandle,0,SEEK_SET);
//当使用yy_扫描_字节时,不要在此处添加2。。。
char*string=malloc(fileSize+2);
fread(字符串、文件大小、大小(char)、文件句柄);
fclose(文件句柄);
//添加flex所需的两个NUL终止符。
//对于yy_scan_bytes(),省略此项,它分配、复制和
//给我们买这些。
字符串[文件大小]='\0';
字符串[文件大小+1]='\0';
//我们的输入文件可能包含NUL('\0'),因此必须使用
//yy_scan_buffer()或yy_scan_bytes()。用于普通C(NUL-
//终止)字符串,我们最好使用yy_scan_string()和
//让flex管理制作一份副本,使原件成为
//常量字符(即文字)字符串。
YY_BUFFER_STATE BUFFER=YY_scan_BUFFER(字符串,文件大小+2);
//这是一个flex源文件,用于yacc/bison调用yyparse()
//而在这里。。。
int标记;
做{
token=yylex();//可以修改“字符串”的内容。
}while(令牌!=0);
//flex完成后,告诉它释放分配的内存。
yy_删除_缓冲区(缓冲区);
//现在我们可以释放(现在变脏了的)缓冲区了。
自由(弦);
返回(退出成功);
}
下面是一个小示例,用于在cpp代码中使用bison/flex作为解析器来解析字符串并根据它更改字符串值
(代码中很少有部分被删除,因此可能存在不相关的部分。)
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
%{
#包括“parser.h”
#包括“lex.h”
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int yyerror(yyscan_u t scanner,字符串结果,常量字符*s){
(d)扫描器;
在libmatheval中有一个有趣的代码:
/* Redefine macro to redirect scanner input from string instead of
* standard input. */
#define YY_INPUT( buffer, result, max_size ) \
{ result = input_from_string (buffer, max_size); }
嘿,dfa(考虑到它的灵活性,它是合适的)您能添加一些关于双空要求的内容吗?示例main可能会失败,因为yy\u scan\u buffer
需要一个可写的缓冲区(它临时修改缓冲区,插入NUL以终止yytext
,然后恢复原始字符)顺便说一下,在我的C++程序中,我需要声明<代码> yyyScxyByth[b/Cuth],用<代码> SiZeZT LeN/Cux>参数来避免链接器错误。如果包含1。<代码> yyyScIsListSuth<代码>,而不是<代码> yyyScasyBuffux<代码> 2,则示例是正确的。清除。以逻辑方式设置缓冲区(需要清理),并且不需要长度规范或双空终端
/* Redefine macro to redirect scanner input from string instead of
* standard input. */
#define YY_INPUT( buffer, result, max_size ) \
{ result = input_from_string (buffer, max_size); }