如何一次输入一个词法分析器字节的数据?

时间:2019-07-10 05:20:38

标签: c bison lex

我正在尝试将lexer +解析器调整为系统中具有以下接口的流接口:

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 = $1; $$ = $1; YYACCEPT ; }
;

line: T_NEWLINE
    | mixed_expression T_NEWLINE { $$ = (int)$1; }
    | expression T_NEWLINE { $$ = $1; }
    | T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;

mixed_expression: T_FLOAT                        { $$ = $1; }
      | mixed_expression T_PLUS mixed_expression     { $$ = $1 + $3; }
      | mixed_expression T_MINUS mixed_expression    { $$ = $1 - $3; }
      | mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
      | mixed_expression T_DIVIDE mixed_expression   { $$ = $1 / $3; }
      | T_LEFT mixed_expression T_RIGHT      { $$ = $2; }
      | expression T_PLUS mixed_expression       { $$ = $1 + $3; }
      | expression T_MINUS mixed_expression      { $$ = $1 - $3; }
      | expression T_MULTIPLY mixed_expression   { $$ = $1 * $3; }
      | expression T_DIVIDE mixed_expression     { $$ = $1 / $3; }
      | mixed_expression T_PLUS expression       { $$ = $1 + $3; }
      | mixed_expression T_MINUS expression      { $$ = $1 - $3; }
      | mixed_expression T_MULTIPLY expression   { $$ = $1 * $3; }
      | mixed_expression T_DIVIDE expression     { $$ = $1 / $3; }
      | expression T_DIVIDE expression       { $$ = $1 / (float)$3; }
;

expression: T_INT               { $$ = $1; }
      | expression T_PLUS expression    { $$ = $1 + $3; }
      | expression T_MINUS expression   { $$ = $1 - $3; }
      | expression T_MULTIPLY expression    { $$ = $1 * $3; }
      | T_LEFT expression T_RIGHT       { $$ = $2; }
;

目前,我将数据馈送到解析器的代码如下:

    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在停下来的地方捡起来?

谢谢!

1 个答案:

答案 0 :(得分:1)

来自评论:

  

问题在于流api仅通过调用回调来通知更多数据,这意味着如果先前的回调根本不返回该线程,则无法使用新数据再次调用该回调

此注释建议在回调的上下文中进行词汇处理。回调必须处理所有字节。在该回调返回之前,不会再有其他回调。

Lex(和Yacc)不能以这种方式使用。您必须在此输入机制之上构建一个阻塞API(等待回调击中他的某些信号量),或者使用轮询(在睡眠中循环旋转直到API指示字节可用)。

使用Lex和Yacc,很难继续对可预测的输入块进行解析,以使yyparse在它们之间返回。例如,如果您希望使用某种语言扫描每个顶级定义,则需要单独的yyparse调用。需要黑客以确保解析可以在上次调用中断的地方继续进行。

如果输入被任意地分为某些回调所提供的块,这些块不遵循任何语法边界,那就算了吧。