我怎样才能一次提供一个词法分析器字节的数据?
How can I feed a lexer bytes of data at a time?
我正在尝试将词法分析器 + 解析器调整为我系统中的流接口,该接口具有以下接口:
bool writeData(stream *obj, char *data, size_t length); //lets the stream know of data coming from upstream so that it prepare it to be read from downstream
void read(stream *obj, char *data, size_t length); //read the processed data
size_t readLengthAvailable(stream *obj); //return the amount of data available to be read
我有一个用 flex + bison 实现的语法作为可重入扫描器,但我遇到的问题是似乎没有一个接口可以一次提供词法分析器数据。
[ \t] ; // ignore all whitespace
[0-9]+\.[0-9]+ {yylval->fval = atof(yytext); return T_FLOAT;}
[0-9]+ {yylval->ival = atoi(yytext); return T_INT;}
\n {return T_NEWLINE;}
"+" {return T_PLUS;}
"-" {return T_MINUS;}
"*" {return T_MULTIPLY;}
"/" {return T_DIVIDE;}
"(" {return T_LEFT;}
")" {return T_RIGHT;}
calculation: line { *(int*)out = ; $$ = ; YYACCEPT ; }
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { $$ = (int); }
| expression T_NEWLINE { $$ = ; }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
;
目前我向解析器提供数据的代码如下所示:
FILE* yyin = stdin;
int result = 0;
yyscan_t scanner;
yy_lex_init(&scanner);
do {
result = 0;
char *line = NULL;
size_t size = 0;
if (getline(&line, &size, stdin) == -1) {
printf("No line\n");
fflush(0);
continue;
}
yy_scan_bytes(line, size - 2, scanner); // - 2 to remove CRLF
int parseResult = yy_parse(scanner, &result);
printf("[Result (%d)]: %d\n", parseResult, result);
fflush(0);
} while(!feof(yyin));
然而,当我尝试执行“1 + CRLF”后跟“1”之类的操作时,我希望得到错误后跟 2,但我得到语法错误后跟 1。
1 + 1
[Result (0)]: 2
1 +
Parse error: syntax error
[Result (1)]: 0
1
[Result (0)]: 1
有没有办法让 flex 从停止的地方继续?
谢谢!
来自评论:
The problem is that the stream api only notifies more data by calling the callback meaning that if the previous callback simply didnt return the thread isnt available to call the callback again with the new data
此评论表明词法分析是在回调的上下文中完成的。回调必须处理所有字节;在那个回调 returns.
之前不会有另一个回调
Lex(和 Yacc)不能以这种方式使用。您必须在此输入机制之上构建一个阻塞 API(等待他被回调命中的信号量),或者使用轮询(在一个循环中旋转,直到 API表示字节可用)。
使用 Lex 和 Yacc,很难继续解析可预测的输入块,因此 yyparse
returns 在它们之间。例如,如果您希望扫描一种语言中的每个 top-level 定义,则需要单独的 yyparse
调用。需要 hack 以确保解析可以在上一个调用停止的地方继续。
如果输入被任意分成由不遵循任何句法边界的回调提供的块,那就算了。
我正在尝试将词法分析器 + 解析器调整为我系统中的流接口,该接口具有以下接口:
bool writeData(stream *obj, char *data, size_t length); //lets the stream know of data coming from upstream so that it prepare it to be read from downstream
void read(stream *obj, char *data, size_t length); //read the processed data
size_t readLengthAvailable(stream *obj); //return the amount of data available to be read
我有一个用 flex + bison 实现的语法作为可重入扫描器,但我遇到的问题是似乎没有一个接口可以一次提供词法分析器数据。
[ \t] ; // ignore all whitespace
[0-9]+\.[0-9]+ {yylval->fval = atof(yytext); return T_FLOAT;}
[0-9]+ {yylval->ival = atoi(yytext); return T_INT;}
\n {return T_NEWLINE;}
"+" {return T_PLUS;}
"-" {return T_MINUS;}
"*" {return T_MULTIPLY;}
"/" {return T_DIVIDE;}
"(" {return T_LEFT;}
")" {return T_RIGHT;}
calculation: line { *(int*)out = ; $$ = ; YYACCEPT ; }
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { $$ = (int); }
| expression T_NEWLINE { $$ = ; }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
;
目前我向解析器提供数据的代码如下所示:
FILE* yyin = stdin;
int result = 0;
yyscan_t scanner;
yy_lex_init(&scanner);
do {
result = 0;
char *line = NULL;
size_t size = 0;
if (getline(&line, &size, stdin) == -1) {
printf("No line\n");
fflush(0);
continue;
}
yy_scan_bytes(line, size - 2, scanner); // - 2 to remove CRLF
int parseResult = yy_parse(scanner, &result);
printf("[Result (%d)]: %d\n", parseResult, result);
fflush(0);
} while(!feof(yyin));
然而,当我尝试执行“1 + CRLF”后跟“1”之类的操作时,我希望得到错误后跟 2,但我得到语法错误后跟 1。
1 + 1
[Result (0)]: 2
1 +
Parse error: syntax error
[Result (1)]: 0
1
[Result (0)]: 1
有没有办法让 flex 从停止的地方继续?
谢谢!
来自评论:
The problem is that the stream api only notifies more data by calling the callback meaning that if the previous callback simply didnt return the thread isnt available to call the callback again with the new data
此评论表明词法分析是在回调的上下文中完成的。回调必须处理所有字节;在那个回调 returns.
之前不会有另一个回调Lex(和 Yacc)不能以这种方式使用。您必须在此输入机制之上构建一个阻塞 API(等待他被回调命中的信号量),或者使用轮询(在一个循环中旋转,直到 API表示字节可用)。
使用 Lex 和 Yacc,很难继续解析可预测的输入块,因此 yyparse
returns 在它们之间。例如,如果您希望扫描一种语言中的每个 top-level 定义,则需要单独的 yyparse
调用。需要 hack 以确保解析可以在上一个调用停止的地方继续。
如果输入被任意分成由不遵循任何句法边界的回调提供的块,那就算了。