Дополнительная правая скобка в выводе yacc

#c #yacc #lex

#c #yacc #лексический

Вопрос:

В моем файле lex есть:

 word [^{}"=,tn@\ ] 

{  {
    return(LBRACE);
}

}  {
    return(RBRACE);
}

{word}  {
     yylval = yytext; printf("WORD=%s",yytext); return(WORD);
}
  

Мой файл yacc имеет:

 phrase: LBRACE WORD RBRACE  {printf("LBRACE %s RBRACEn",$2);};
  

При вводе:

 {FooBar}
  

Я получаю:

 WORD=FooBar
LBRACE FooBar} RBRACE
  

Я не уверен, почему я получаю дополнительную правую скобку, хотя я печатаю всего 2 доллара, что должно быть идеально

Ответ №1:

Здесь:

 {word}  {
     yylval = yytext; printf("WORD=%s",yytext); return(WORD);
}
  

Значение yytext допустимо только при обработке этой лексемы. Как только вы переходите к следующей лексеме, содержимое буфера может быть перезаписано. Таким образом, сохранение указателя yytext не принесет вам никакой пользы. Вам нужно скопировать токен из буфера.

 {word}   {  yylval = (char*)calloc(yylen 1, sizeof(char));
            strncpy(yylval, yytext, yylen); // Remember you need to free this.
            return WORD;
         }
  

Комментарии:

1. Спасибо за ответ! Я думаю, вы имеете в виду глобальную переменную yyleng , верно? Кроме того, не должно ли strncpy быть больше yyleng 1 символов, чтобы получить завершающий null? Если strndup используется, это добавило бы завершающий null самостоятельно.

2. @crypto: Да, я имею в виду глобальный yylen, предоставленный lex. Вам не нужен strncpy для копирования yylen 1, потому что я использую calloc(), который гарантирует обнуление возвращаемой базовой памяти. Таким образом, не имеет значения, добавляет strncpy дополнительный » или нет, поскольку это все равно будет ‘ 0’.

Ответ №2:

Вам решать, сохранять значение yytext (через yylval ) в WORD рабочей среде. Это просто указатель на рабочее пространство lex. Вы видите изменение рабочего пространства после его синтаксического анализа RBRACE . Представьте себе правило yacc, подобное LBRACE WORD COMMA WORD LBRACE , и что бы там происходило.

Если вы не хотите создавать отдельное производство, я думаю, вы можете сделать LBRACE WORD { code to strdup yylval } RBRACE { ... }

Комментарии:

1. Почему существует разница в значении $2 amp; переданной yylval строке?

2. yylval это не «строка» как таковая, это указатель , который указывает на личные данные lex. Вы владеете yylval , но вы не владеете тем, на что это указывает. Она действительна только для данного терминального символа между моментом, который yylex() возвращается, и повторным вызовом. Попробуйте yylval = strdup(yytext) понять, что я имею в виду.

3. strdup небезопасен. Нет гарантии, что lex-буфер завершается ‘ 0’. Вам нужно использовать yylen для извлечения необходимой вам части буфера.