Как передать yytext из файла lex в yacc?

Пожалуйста, я столкнулся с простой проблемой ... вот проблема. В моем файле lex есть что-то похожее на:

char *ptr_String;

"name = "  { BEGIN sName; }

<sName>.+   {
          ptr_String = (char *)calloc(strlen(yytext)+1, sizeof(char));
              strcpy(ptr_String, yytext);
              yylval.sValue = ptr_String;
              return NAME;
    }

Теперь в моем файле Yacc есть что-то похожее на:

stmt_Name:
    NAME
    {
        /*Now here i need to get the matched string of <sName>.+ and measure it's length. */
        /*The aim is simply outputing the name to the screen and storing the length in a global variable.
    }
    ;

Пожалуйста, какие-нибудь предложения? Большое спасибо за ваше время и помощь.


person CompilingCyborg    schedule 22.12.2010    source источник
comment
См. Почти повторяющийся вопрос (спрашивают о yyleng вместо yytext).   -  person Jonathan Leffler    schedule 23.12.2010


Ответы (1)


Исправленный вопрос

Значение в стеке Yacc контролируется YYSTYPE или %union. Используйте YYSTYPE, если информация о типе проста; используйте %union, когда это сложно.

Одна из моих грамматик содержит:

struct Token
{
    int      toktype;
    char    *start;
    char    *end;
};
typedef struct Token Token;

#define YYSTYPE Token

По ряду причин (не обязательно хороших) в моей грамматике вместо Lex используется созданный вручную лексический анализатор.

В правилах грамматики вы ссылаетесь на такие элементы, как NAME, в вашем примере как $1 (где фактическое число зависит от того, где находится токен в списке токенов или терминалов, составляющих правило).

Например (та же грамматика):

disconnect
    :   K_DISCONNECT K_CURRENT
        { conn->ctype = CONN_CURRENT; }
    |   K_DISCONNECT K_ALL
        { conn->ctype = CONN_ALL; }
    |   K_DISCONNECT K_DEFAULT
        { conn->ctype = CONN_DEFAULT; }
    |   K_DISCONNECT string
        { conn->ctype = CONN_STRING;
          set_connection(conn, $2.start, $2.end);
        }
    ;

А также:

load
    :   K_LOAD K_FROM opt_file_pipe string load_opt_list K_INSERT
        {
            set_string("load file", load->file, sizeof(load->file),
                       $4.start, $4.end);
            load->stmt = $6.start;
        }
    ;

Я не знаю, помогает ли набросок ручной работы yylex(); в грамматике это функция в том же файле, что и yyparse().

static const char *c_token;     /* Where to start next token search */

static int yylex(void)
{
    char        buffer[MAX_LEXTOKENLENGTH];
    const char *start;

    if (c_token == 0)
        abort();

    if (bare_filename_ok)
        start = scan_for_filename(c_token, &c_token);
    else
        start = sqltoken(c_token, &c_token);

    yylval.start = CONST_CAST(char *, start);
    yylval.end = CONST_CAST(char *, c_token);
    if (*start == '\0')
    {
        yylval.toktype = 0;
        return yylval.toktype;
    }
    set_token(buffer, sizeof(buffer), start, c_token);
#ifdef YYDEBUG
    if (YYDEBUGVAR > 1)
        printf("yylex(): token = %s\n", buffer);
#endif /* YYDEBUG */

    /* printf("yylex(): token = %s\n", buffer); */
    if (isalpha((unsigned char)buffer[0]) || buffer[0] == '_')
    {
        Keyword  kw;
        Keyword *p;
        kw.keyword = buffer;
        p = (Keyword *)bsearch(&kw, keylist, DIM(keylist), sizeof(Keyword),
                                kw_compare);    /*=C++=*/
        if (p == 0)
            yylval.toktype = S_IDENTIFIER;
        else
            yylval.toktype = p->token;
    }
    else if (buffer[0] == '\'')
    {
        yylval.toktype = S_SQSTRING;
    }
    else if (buffer[0] == '"')
    {
        yylval.toktype = S_DQSTRING;
    }
    else if (isdigit((unsigned char)buffer[0]))
    {
        yylval.toktype = S_NUMBER;
    }
    else if (buffer[0] == '.' && isdigit((unsigned char)buffer[1]))
    {
        yylval.toktype = S_NUMBER;
    }

... распознаются различные односимвольные символы ...

    else if (buffer[0] == ':')
    {
        assert(buffer[1] == '\0');
        yylval.toktype = C_COLON;
    }
    else
    {
        yylval.toktype = S_ERROR;
    }
    return yylval.toktype;
}

Исходный вопрос

Переменная обычно является глобальной переменной - ваш код Yacc использует одно из двух возможных объявлений:

extern char *yytext;    /* Correct for Flex */
extern char yytext[];   /* Correct for traditional Lex */

Какой из них правильный, зависит от того, как это определяется вашей версией Lex.

Если вы хотите добавить длину (возможно, yytextlen), вы можете определить такую ​​переменную и получать каждый возврат от yylex(), чтобы убедиться, что yytextlen установлено. В качестве альтернативы вы можете сделать так, чтобы ваша грамматика вызывала wwlex(), а ваш wwlex() просто делает:

int wwlex(void)
{
    int rc = yylex();
    yytextlen = strlen(yytext);
    return rc;
}

Или вы можете сделать так, чтобы Lex сгенерировал код с переименованием, и Yacc продолжил бы вызывать yylex(), а вы предоставили приведенный выше код как yylex() и заставили его вызывать переименованную функцию Lex. В любом случае работает.

person Jonathan Leffler    schedule 22.12.2010
comment
Спасибо за ваш ответ! пожалуйста, взгляните на мою отредактированную версию? - person CompilingCyborg; 23.12.2010
comment
Вы можете избежать использования strlen (yytext), потому что lex и flex определяют yyleng, который является длиной строки yytext. - person VGE; 23.12.2010
comment
@VGE: о, спасибо. Я забыл эту деталь. В этом случае, конечно, не нужно ухаживать за именами функций. - person Jonathan Leffler; 23.12.2010