Lex Yacc 解析器卡在 EOF

Lex Yacc parser stuck at EOF

几天来我一直被这个问题困扰,这个解析器也是如此。这个解析器的要点是解析 http 请求,它确实可以,但是当到达请求结束时,解析器进入无限循环。我已经找到了从 lex 文件生成的 C 文件中的点,但不知道如何解决这个问题。

我尝试了其他类似问题中建议的以下方法,但没有成功。

bison-end-of-file

lex-flex-scanning-for-the-eof-character

这是我的 lex 文件:

#undef YYLMAX
#define YYLMAX  4096

#include "ssoyacc.h"

#define yylval  ssolval
extern YYSTYPE  yylval;

#ifdef FLEX_SCANNER
#define YY_INPUT(buf, result, max_size) { int cc = sso_read(); result = (cc == -1) ? YY_NULL : (buf[0] = cc, 1);}
#else /* NO FLEX */
#undef input
#define input()         sso_read()
#define unput(cc)         sso_unput(cc)
#define yyless(cc)         sso_yyless(cc)
#endif /* FLEX */

%}

%p 30000
%n 4000
%e 2000
%a 30000
%k 2500
%o 50000

nondigit                [_a-zA-Z]
alfanum                 [_a-zA-Z0-9]
digit                   [0-9]
nonzero_digit           [1-9]
octal_digit             [0-7]
hexadecimal_digit       [0-9a-fA-F]

%start HTTP QUERY ARG XML TAG CDAT FORM_PARAM FORM_VALUE

%%

<INITIAL,HTTP>[ ]   {
            return SP;
        }
<INITIAL,HTTP>\r\n      {
            return CRLF;
        }
<HTTP>HTTP\/{digit}\.{digit}    {
            return HTTP_VERSION;
        }
<HTTP>OPTIONS       {
            return OPTIONS;
        }
<HTTP>GET   {
            return GET;
        }
.
.
.
other tags
.
.
.
<FORM_PARAM>\=  {
            BEGIN(FORM_VALUE);
            return IS;
        }
<FORM_VALUE>\&  {
            BEGIN(FORM_PARAM);
            return AMPERSAND;
        }
<FORM_VALUE>[0-9a-zA-Z\%\+\.\/]*    {
            if (yyleng < MAX_ARG_LEN)
            {
                char cc[3];
                int ii;
                int jj = 0;
                for (ii=0;ii<yyleng;ii++)
                {
                    if (yytext[ii] != '%')
                    {
                        if (yytext[ii] == '+')
                        {
                            yylval.sval[jj++] = ' ';
                        }
                        else
                        {
                            yylval.sval[jj++] = yytext[ii];
                        }
                    }
                    else
                    {
                        strncpy(cc, yytext+ii+1, 2);
                        cc[2] = 0;
                        yylval.sval[jj++] = strtol(cc, NULL, 16);
                        ii+=2;
                    }
                }
                yylval.sval[jj] = 0;
                return STRING;
            }
            else
            {
                return ERROR;
            }
        }
%%
int ssowrap(void)
{
        return 1;
}

void start_http()
{
    init_content(); /* initialize content count */
    BEGIN(HTTP);
}

void start_urlencoded()
{
    BEGIN(FORM_PARAM);
}

void start_xml()
{
    BEGIN(XML);
}


int sso_yyless(int count)
{
    int i;
    if (count>yyleng)
    {
        return 0;
    }
    for (i=0;i<yyleng-count;i++)
    {
        unput(yytext[yyleng-1-i]);
        yytext[yyleng-1-i] = '[=10=]';
    }
    return 0;
}

void allprint(wchar_t cc)
{
    if (isprint(cc))
    {
        fprintf(stdout, "'%c' 0x%x", cc, cc);
    }
    else
    {
        fprintf(stdout, "%x", cc);
    }
}

void sprint(wchar_t *pc)
{
    fprintf(stdout, "%s", pc);
}

执行卡在循环 while ( /*CONSTCOND*/1 ) 中,并在 case YY_END_OF_BUFFER: 中输入两次,然后在 ssolex.c 文件中的 case 126: 中输入一次。 case 126 中声明的行是 lex 文件中的行 %%

/** The main scanner function which does all the work.
 */
YY_DECL
{
    yy_state_type yy_current_state;
    char *yy_cp, *yy_bp;
    int yy_act;

    if ( !(yy_init) )
        {
        (yy_init) = 1;

#ifdef YY_USER_INIT
        YY_USER_INIT;
#endif

        if ( ! (yy_start) )
            (yy_start) = 1; /* first start state */

        if ( ! ssoin )
            ssoin = stdin;

        if ( ! ssoout )
            ssoout = stdout;

        if ( ! YY_CURRENT_BUFFER ) {
            ssoensure_buffer_stack ();
            YY_CURRENT_BUFFER_LVALUE =
                sso_create_buffer(ssoin,YY_BUF_SIZE );
        }

        sso_load_buffer_state( );
        }

    {
#line 44 "ssolex.l"


#line 1265 "<stdout>"

    while ( /*CONSTCOND*/1 )        /* loops until end-of-file is reached */
        {
        yy_cp = (yy_c_buf_p);

        /* Support of ssotext. */
        *yy_cp = (yy_hold_char);

        /* yy_bp points to the position in yy_ch_buf of the start of
         * the current run.
         */
        yy_bp = yy_cp;

        yy_current_state = (yy_start);
        yy_current_state += YY_AT_BOL();
yy_match:
        do
            {
            YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
            if ( yy_accept[yy_current_state] )
                {
                (yy_last_accepting_state) = yy_current_state;
                (yy_last_accepting_cpos) = yy_cp;
                }
            while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
                {
                yy_current_state = (int) yy_def[yy_current_state];
                if ( yy_current_state >= 802 )
                    yy_c = yy_meta[(unsigned int) yy_c];
                }
            yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
            ++yy_cp;
            }
        while ( yy_base[yy_current_state] != 1067 );

yy_find_action:
        yy_act = yy_accept[yy_current_state];
        if ( yy_act == 0 )
            { /* have to back up */
            yy_cp = (yy_last_accepting_cpos);
            yy_current_state = (yy_last_accepting_state);
            yy_act = yy_accept[yy_current_state];
            }

        YY_DO_BEFORE_ACTION;

do_action:  /* This label is used only to access EOF actions. */

打印的最后一件事是读取令牌:它在 yacc C 文件中,所以我认为问题一定是 lex 中的 EOF 处理。

/* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
if (yychar == YYEMPTY)
{
  YYDPRINTF ((stderr, "Reading a token: "));
  yychar = yylex ();
  printf("TOKEN %c, %d\n", yychar, yychar);
}

正如提到的那样,sso_read函数没有返回-1而是返回了0。此外,EOF也从未达到,因为tcp套接字仍处于打开状态。感谢 rici 和 Jon Bollinger 帮助解决这个问题!