Я пользуюсь бизоном & Согните в течение 1 месяца более или менее, так что извините, если я не вижу ничего очевидного (но я не думаю, что это так).
У меня проблема с освобождением памяти с помощью Flex Bison. Вот как выглядит мой код:
parser.l
{DATE} { yylval.str= strdup(yytext);
pair<string,string> newpair = make_pair("DATE",yytext);
myvector.push_back(newpair);
return TOKEN_DATE ;}
Это один из примеров моего .l файла. Я копирую значение yytext в yylval.str. Затем я создаю новую пару с этим содержимым (собственно ключ / значение), а затем возвращаю дату токена для бизона.
Мой парсер .y не более чем yyparse; и когда что-то ловится, оно просто печатает это.
Я попытался запустить valgrind на этом, и у меня есть несколько ошибок, касающихся strdup. Я знаю, что эта функция использует malloc, но я понятия не имею, ГДЕ и КОГДА использовать БЕСПЛАТНО.
Я, наверное, думаю, это в .y файле, но где?
test:
TOKEN_DATE { cout << $1 << endl; // here ? and what to free ?}
Я действительно не понимаю всего этого, я был бы очень признателен за простое и четкое объяснение.
Заранее спасибо,
РЕДАКТИРОВАТЬ:
Я пробовал несколько вещей, таких как:
test:
TOKEN_DATE TOKEN_TOTO TOKEN_BLABLA { cout << $1 << endl; free($1); free($2);}
| TOKEN_DATE test { cout << $1 << endl, free($1); }
Кажется, что он компилируется и выполняется хорошо, но valgrind все еще говорит мне, что есть проблема с malloc, содержащимся в функции strdup. Но я не могу написать free (yylval.str) внутри файла flex, иначе bison не будет знать о значении (если я правильно понял, я попытался, это не работает). Я действительно понятия не имею, как устранить эту проблему.
Вам нужно освободить скопированную строку, когда она вам больше не нужна. В вашем довольно простом случае вы можете освободить (1 доллар) после его распечатки, но часто случается, что анализатор вставляет скопированную строку в некоторую структуру данных, и в этом случае эта структура данных становится владельцем хранилища malloc’d, и Звонок на бесплатный будет выполнен в деструкторе.
Это не очень отличается от любой другой проблемы управления ресурсами; вам всегда нужно четко понимать, кто является владельцем выделенного ресурса, потому что владелец несет ответственность за освобождение ресурса, когда он больше не нужен.
Что происходит внутри, так это bison
поддерживает стек семантических значений, каждое из которых имеет тип YYSTYPE
(т.е. «семантический тип»), который также является типом yylval
, Когда токен перемещается в стек, bison
копии yylval
на вершину стека. Перед выполнением действия, соответствующего производству, bison
организует семантические значения каждого терминала и нетерминала в производстве, которые будут известны как $1
, $2
и т. д. (Это не копия; различные $x
символы заменяются ссылкой на местоположение на bison
стек.)
Нетерминалы также имеют семантические значения, потому что каждое действие сохраняет значение в псевдопеременной $$
, (Если действие не делает этого, значение $$
непредсказуемо, но все еще существует.) После завершения действия зубр удаляет $1
, $2
… значения из верхней части стека, а затем копирует псевдо-переменную $$
на вершину стека. Он ничего не делает со значениями, которые были вытолкнуты, поэтому, если они должны быть освобождены или иным образом уничтожены, действие должно сделать это само.
Поскольку семантические значения копируются наивно, семантический тип не должен содержать какой-либо объект C ++, который нетривиально копируется.
Если вы используете %union
объявление, то семантический тип YYSTYPE
это union
объект, и вам нужно сказать bison
какой тег объединения применяется к каждому терминалу и нетерминалу. В таком случае, $$
и все $n
иметь правильный .tag
автоматически добавляются к ним, и действия становятся более безопасными для типов.
Из руководства по флексам:
21.3 Примечание о yytext и памяти
Когда flex находит совпадение, yytext указывает на первый символ
совпадение во входном буфере. Сама строка является частью ввода
буфер, и НЕ выделяется отдельно. Значение yytext будет
перезаписывается при следующем вызове yylex (). Короче говоря, ценность
yytext действителен только внутри действия соответствующего правила.
Следовательно, make_pair не должен быть следующим?
pair<string,string> newpair = make_pair("DATE",yylval.str);
если так, то строка должна быть освобождена при очистке памяти пар.
Простой ответ: это зависит. Вы должны освободить память, когда вы закончите использовать ее, когда бы это ни было.
Более полезный ответ: попробуйте использовать как можно меньше памяти. Если ты никогда malloc
любая память, вам никогда не придется free
любая память. В приведенном вами примере вы соответствуете шаблону на дату. Обычно даты соответствуют формату и имеют некоторую верхнюю границу длины; например, формат «гггг / мм / дд» содержит 10 символов. Если вы можете ожидать этого, вместо создания новой строки для хранения даты, вы можете просто поместить массив символов статического размера в yylval
, такие как char date[10];
,