我想創建一個使用flex/bison分析器的讀取 - 評估打印循環。麻煩的是,flex生成的詞法分析器需要FILE *類型的輸入,我希望它是char *。無論如何要做到這一點?字符串輸入到flex詞法分析器
一個建議是創建一個管道,爲其提供字符串並打開文件描述符併發送給詞法分析器。這很簡單,但它感覺很複雜,不是很平臺獨立。有沒有更好的辦法?
我想創建一個使用flex/bison分析器的讀取 - 評估打印循環。麻煩的是,flex生成的詞法分析器需要FILE *類型的輸入,我希望它是char *。無論如何要做到這一點?字符串輸入到flex詞法分析器
一個建議是創建一個管道,爲其提供字符串並打開文件描述符併發送給詞法分析器。這很簡單,但它感覺很複雜,不是很平臺獨立。有沒有更好的辦法?
以下例行程序可用於對掃描存儲器內的字符串的文件,而不是設定輸入緩衝器(如yy_create_buffer一樣):
YY_BUFFER_STATE yy_scan_string(const char *str)
:掃描string` NUL封端YY_BUFFER_STATE yy_scan_bytes(const char *bytes, int len)
:掃描從位置字節開始的len字節(包括可能的NUL)請注意,這兩個函數都會創建,返回相應的YY_BUFFER_STATE句柄(必須使用yy_delet e_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();
}
有關如何掃描內存緩衝區(如字符串)的信息,請參閱Flex手冊的this section。
這是我需要做的:
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,這在你思考時是有意義的。 yy_scan_string()
, yy_scan_buffer()
,和yy_scan_bytes()
(見documentation):
撓曲可以使用三個中的任一個的功能解析char *
。這是第一個示例:
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()
等效語句(這需要一個雙空值終止字符串):
char string[] = "String to be parsed.\0";
YY_BUFFER_STATE buffer = yy_scan_buffer(string, sizeof(string));
我的回答重申了一些由@dfa和提供的信息@ jlholland,但他們的答案的代碼似乎都不適合我。
其他方式,您可以在lex文件中重新定義函數YY_INPUT,然後將您的字符串設置爲LEX的輸入。如下:
#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); }
在你的主。c,在掃描之前,您需要首先設置lex緩衝區:
set_lexbuf(your_string);
scanning...
接受的答案不正確。它會導致內存泄漏。
在內部,yy_scan_string調用yy_scan_bytes,yy_scan_bytes又調用yy_scan_buffer。
yy_scan_bytes爲輸入緩衝區的COPY分配內存。
yy_scan_buffer直接在提供的緩衝區上工作。使用這三種形式,你必須調用yy_delete_buffer來釋放flex緩衝區狀態信息(YY_BUFFER_STATE)。
但是,使用yy_scan_buffer可以避免內部緩衝區的內部分配/複製/釋放。
yy_scan_buffer的原型不接受const char *,你不能期望內容保持不變。
如果你分配內存來保存你的字符串,你負責在你調用yy_delete_buffer之後釋放它。
此外,不要忘記當你解析JUST這個字符串時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);
}
這裏是使用野牛/柔性的解析器您的CPP代碼中,根據它解析字符串,並改變一個字符串值 (代碼的幾個部分被去除,從而有可能是不相關部分的一個小例子有。) 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
嘿dfa(考慮到它的靈活性,這是適合的)請問您可以添加一些關於雙空要求的內容? – 2013-09-08 09:06:04
由於`yy_scan_buffer`需要一個可寫緩衝區(它臨時修改緩衝區,插入NUL來終止`yytext`,然後恢復原始字符),所以樣本main可能會失敗,並且它需要兩個終止NUL字節。 – 2014-05-08 16:02:15
順便說一句,在我的C++程序中,我需要用`size_t len`參數聲明`yy_scan_bytes`以避免鏈接器錯誤。 – coldfix 2015-05-05 15:42:38