引号字符串 returns 空字符串的 Flex 操作

Flex action for quoted string returns empty string

我正在尝试使用 Flex 手册 [1] 中显示的示例。该示例显示了可能包含八进制代码的引号字符串的 Flex 规则。

手册对收盘价操作的描述有点不完整。它只是有这样的评论:

/* return string constant token type and
*  value to parser
*/

所以我创建了我认为可行的代码,但显然我的代码不正确。

下面是词法分析器,后面是解析器。当我执行生成的解析器时,我得到这个输出:

The string is: ''

我期望和想要的是这个输出:

The string is: 'John Doe'

我的输入是这样的:"John Doe"

请问我做错了什么?

这是词法分析器:

%option noyywrap
%x STR
%{
#include "parse.tab.h"
#define MAX_STR_CONST 100
%}
%% 
    char string_buf[MAX_STR_CONST];
    char *string_buf_ptr;
    
\"            { string_buf_ptr = string_buf; BEGIN(STR); }
                
                
<STR>{
    \"          { /* closing quote - all done */
                   BEGIN(INITIAL);
                   *string_buf_ptr = '[=14=]';
                   yylval.strval = strdup(string_buf_ptr);
                   return(STRING); 
                }
                
    \n          {  /* error - unterminated string constant */
                   perror("Error - unterminated string");
                   yyterminate();
                }
                
    \[0-7]{1,3} { /* octal escape sequence */
                   int result;
                   (void) sscanf(yytext+1, "%o", &result);
                   if (result > 0xff) {
                      perror("Error - octal escape is out-of-bounds");
                      yyterminate();
                   }
                   *string_buf_ptr++ = result;
                 }
               
    \[0-9]+    { /* bad escape sequence */
                   perror("Error - bad escape sequence");
                   yyterminate();
                }
                
    \n         *string_buf_ptr++ = '\n';
    \t         *string_buf_ptr++ = '\t';
    \r         *string_buf_ptr++ = '\r';
    \b         *string_buf_ptr++ = '\b';
    \f         *string_buf_ptr++ = '\f';
    
    \(.|\n)    *string_buf_ptr++ = yytext[1];
    
    [^\\n\"]+  {
                   char *yptr = yytext; 
                   while (*yptr)
                      *string_buf_ptr++ = *yptr++;
                }
}
%%

这是解析器:

%{
#include <stdio.h>
#include <stdlib.h>
/* interface to the lexer */
extern int yylineno; /* from lexer */
int yylex(void);
void yyerror(const char *s, ...);
extern FILE *yyin;
int yyparse (void);
%}
%union {
   char *strval;
}
%token <strval> STRING
%%
start 
    : STRING       { printf("The string is: '%s'", );}
;
%%

int main(int argc, char *argv[])
{
    yyin = fopen(argv[1], "r");
    
    yyparse();
    
    fclose(yyin);
    
    return 0;
}

void yyerror(const char *s, ...)
{
  fprintf(stderr, "%d: %s\n", yylineno, s);
}

[1] 请参阅 Flex 手册中的第 24-25 页 https://epaperpress.com/lexandyacc/download/flex.pdf

您的操作是:

*string_buf_ptr = '[=10=]';
yylval.strval = strdup(string_buf_ptr)
return STRING;

很明显,string_buf_ptrstrdup 将 return 空字符串的 newly-allocated 副本,因为您只需设置 [= 指向的字符12=] 到 0.

两条评论:

  • 这个错误基本上与 Flex(或 Bison)无关。我知道人们总是很想假设您正在使用的最不熟悉的技术是错误的来源,但做出这样的假设并不是一种非常有效的调试技术。
  • 调试器通常是比 Whosebug 更快的查找错误的方法。使用 Gdb 有一些学习曲线,但它最终肯定会有所回报(甚至很快)。

此外,perror 旨在根据 errno 的值向用户显示错误消息。这在这种情况下不是很有用;你可能想打电话给 yyerror。 (但是,您需要在词法分析器中声明它,除非您安排将其原型插入 parse.tab.h。请参阅 bison 手册中的 %code requires/%code provides 了解如何做那个。)