2016-09-29 102 views
0

我正在解释器上工作,但我遇到了一些问题。重复的词法分析器,错误分段错误

在我的lex:

<INITIAL>\{     {BEGIN(BLOC);} 
<BLOC>[^}]*\}    {BEGIN(INITIAL);strncpy(yylval.sval, yytext, MAXVARSIZE); 
          temp = strlen(yylval.sval); 
          yylval.sval[temp-1] = '\0'; 
          return BLOCK;} 

法返回块{}之间,在我的野牛解析器,我设置了弹性缓冲:

ifs: 
    IF PAREOPEN condition PARECLOSE BLOCK {if($3 > 0){scan_string($5);}} 

; 
[...] 

void scan_string(const char* str) 
{ 
    yy_switch_to_buffer(yy_scan_string(str)); 

} 

int main(int argc, char *argv[]) { 
    yyin = stdin; 
      do { 
     printf("aqui2\n"); 
     yyparse(); 

    } while(!feof(yyin)); 

} 

但后来野牛产生分段错误。我想恢复缓冲区为原来的yyin

+0

这里没有递归。 – EJP

回答

1

我不认为这种方法可行。见下文。

您不应该致电yy_switch_to_buffer; yy_scan_string会自动执行此操作。此外,为了切换回yyin,您需要有一个<<EOF>>规则,该规则检测文件结尾指示(或本例中为缓冲区结尾)并切换回yyin。为了确保您保留原始缓冲区,您需要在某个临时变量中保留YY_CURRENT_BUFFER,并在该临时变量上调用yy_switch_to_buffer;如果您从yyin创建新的缓冲区,则会丢失任何缓冲的输入。

管理输入缓冲区堆栈的一种更简单的方法是使用缓冲区堆栈;您可以拨打yypush_buffer_state开始扫描新缓冲区,并在您的<<EOF>>规则中使用yypop_buffer_state。但是,yy_scan_stringyypush_buffer_state之间存在奇怪的相互作用,它需要您先推送当前缓冲区的副本,然后用yy_scan_string创建的缓冲区状态替换它。例如,参见this answer。 (您可能想要read the relevant section of the Flex manual,尽管它用于嵌套文件,但不是字符串,但它有一个完整的示例。)

没有看到更多的代码,很难知道段错误来自哪里。这可能是您的<<EOF>>处理程序中的错误,您不会显示。它也可能与yylval.sval的处理有关;如果这是一个指向缓冲区的指针(即一个char*),那么它显然不会在任何地方被初始化,这可能会在你将其中的strncpy写入时产生错误。

但在我看来,最有可能的是你已经包含了一个固定长度的字符数组作为你的语义值联合的一部分。由于多种原因,这是一个非常糟糕的主意,其中最主要的原因是它在解析器堆栈中浪费了很多空间:每个条目都会包含固定长度的缓冲区。而且,固定长度的缓冲区从来就不是一个好主意;你可以很容易地溢出它们。

在这种情况下,它根本无法工作,因为该数组将成为野牛分析器堆栈条目的一部分,并且只要ifs动作终止,该条目就会从堆栈中删除。这会让Flex的缓冲区留下一个悬挂指针,这几乎肯定会产生问题。

所以,你可以尝试以下方法:

  • 更改sval成员在工会char*(这将需要各种代码的变化)

  • 在更换<BLOC>模式,将flex文件,如下所示:

    <INITIAL>\{   { BEGIN(BLOC); } 
    <BLOC>[^}]*\}  { BEGIN(INITIAL); 
             yylval.sval = malloc(yyleng); 
             memcpy(yylval.sval, yytext, yyleng - 1); 
             yylval.sval[yyleng - 1] = '\0'; 
             return BLOCK; 
            } 
    
  • 更改ifs在您的野牛分析器中的动作,以便它free是动态分配的字符串缓冲区(它可以这样做,因为yy_scan_string会生成副本)。

  • 添加<<EOF>>规则并修改scan_string以使用缓冲区堆栈,如上所述。

即使所有这一切,我不认为这是一个很好的策略。在野牛动作中改变弹性缓冲区只有在解析器没有读取一个超前令牌时才会起作用,这使得它非常脆弱。 (对于其他类似yacc的解析器生成器,它总是读取一个lookahead标记,它根本不起作用)。它不可能最终如何处理嵌套块,你可能想在某些时候实现它。