如何在lex / yacc中读取具有固定缓冲区限制的任意长序列?

问题描述

我想解析/存储以下序列:Ann {* some arbitrary long sequence *}

我的缓冲区长度(YYLMAX)设置为8K。鉴于序列可以是任意长,我尝试通过这种方式做到这一点:

  1. 搜索Ann令牌,后跟{*。看到后进入ANN状态。
  2. 处于ANN状态时,一次读取一个字符,直到YYLMAX-1。将此令牌返回给YACC,YACC将其复制/追加到C ++字符串缓冲区(动态增加)。
  3. 重复步骤(2),直到看到*}。此时将状态设置为INITIAL(0)。

对于小序列(小于8K),我的代码可以正常工作。但是,如果序列超过8K,则第一个 grab 可以正常工作,但是由于它与annotation_text规则匹配,因此词法分析器似乎将状态重置为INITIAL。因此,当我继续阅读序列中的下一个字符时,由于词法分析器规则ANN[^*]不再匹配,最终导致解析错误。我想避免这种情况,并保持在ANN状态,直到读取完整的序列,直到看到*}。实施此行为的正确方法是什么?一个示例示例会有所帮助。

我不想增加YYLMAX的长度,因为我事先不知道Ann {* ... *}块中序列的最大长度。

谢谢您的任何想法。

我的YACC语法的相关代码段如下所示:

string curr_annotation = "{*";

annotation            : _STIL_ANN _STIL_ANN_LCURLY annotation_text _STIL_ANN_RCURLY
                        { 
                          curr_annotation += "*}";
                          std::cout << "Going to add annotation '" << curr_annotation << "'" << std::endl;
                          p_block->addAnn(curr_annotation,stil_yylineno);
                          curr_annotation = "{*";
                        }
                      ;
                      
annotation_text       : _STIL_ANN_TEXT
                        {
                          std::cout << "appending to annotation" << std::endl;
                          curr_annotation += $1;
                        }
                      | annotation_text _STIL_ANN_TEXT
                      ;

我的LEXER的相关代码段如下所示:

WHITESPACE      [ \t\n\r]
START_BLK_ANN   {WHITESPACE}*"{*"
END_BLK_ANN     "*}"
...

<ANN>{START_BLK_ANN}           { printf("match1\n");
                                 TRACE(("<ANN>START_BLK_ANN <%s> \n",yytext));
                                 return(token(_STIL_ANN_LCURLY));
                               }
<ANN>{END_BLK_ANN}             { printf("match2\n"); TRACE(("<ANN>END_BLK_ANN <%s> \n",yytext));
                                 BEGIN 0;
                                 return(token(_STIL_ANN_RCURLY));
                               } 
<ANN>[^*]                      { printf("match3\n"); yylval.string = stiltok_grab_annotation();
                                 TRACE(("ANN_TEXT <%s> \n",yylval.string));
                                 return(token(_STIL_ANN_TEXT));
                               } 

{IDENTIFIER}                   {
                                 printf("got here\n"); 
                                 temp_sym_name = yytext;
                                 tokVal = stiltoktbl.locatetoken(temp_sym_name);
                                 yylval.string = yytext;
                                 if (tokVal != UNDEFINED_TOKEN) {
                                   if (tokVal == _STIL_USER_KEYWORD) {
                                     BEGIN USERKW;
                                     TRACE(("USER_KEYWORD <%s> \n",yytext));
                                   }
                                   else if (tokVal == _STIL_Include)  {
                                     TRACE(("INCLUDE \n"));
                                     BEGIN INCLUDE;
                                     return(token(_STIL_INCLUDE));
                                   }
                                   else if (tokVal == _STIL_Ann) {
                                     TRACE(("ANN \n"));
                                     BEGIN ANN;                   <== Ann Token seen switch state.
                                     return(token(_STIL_ANN));
                                   }
                                   else {
                                     TRACE(("KEYWORD <%s> \n",yytext));
                                   }
                                   return(tokVal);
                                 }
                                 else {
                                   TRACE(("IDENTIFIER <%s> \n",yytext));
                                   return(token(_STIL_IDENTIFIER));
                                 }

stiltok_grab_annotation看起来像这样:

char * stiltok_grab_annotation() {

  TRACEID("stiltok_grab_annotation",SEV_4);

  char * p_ann_begin = yytext;  // point past "{*" prefix
  char * p_ann_end   = p_ann_begin + 1;
  char c1 = yyinput();
  char c2 = yyinput();
  *(p_ann_end++) = c1;
  *(p_ann_end++) = c2;
  while ( c1 != '*' || c2 != '}') {
    c1 = c2;
    c2 = yyinput();
    *(p_ann_end++) = c2;
    if ((p_ann_end - yytext) == (MAX_TOKEN_LENGTH-1)) {
       break;
    }
  }
  *(p_ann_end) = '\0';  // place the string terminator at end after "*}" suffix
  
  // Return '*}' token to the lexer  
  if ( c1 == '*' && c2 == '}' ) {
    *(p_ann_end-2) = '\0';
    yyunput(c2,yytext);
    yyunput(c1,yytext);
    
  }

  return p_ann_begin;
}

样品运行(只是相关的部分):

match1            <-- in ANN state,matched '{*'
Line:[58] {*
match3            <-- in ANN state,matched single character. run stiltok_grab_annotation()...
Line:[58] ......  <-- received 8K-1 characters.

appending to annotation     <-- successfully copied by yacc to string buffer
got here                    <-- lexer has gone back to IDENTIFIER state instead of remaining in ANN state
Line:[58]D_REG55_0_18_0     <-- trouble begins
-S- Parsing error detected in file: x [stilcomyacc_perror]
-T- Syntax Error [Line: 58] 

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)