Я смотрел только на указанное вами действие. Если вы сделаете те же ошибки в другом месте, я уверен, что вы сможете их найти.
Вот действие "<"{HTML_TAG}
с моими комментариями:
{
int yytextlen = yyleng;
Какой смысл этой переменной? yyleng
не собирается менять свое значение во время выполнения этого действия. Просто используйте его.
char tagName[yytextlen - 1];
Вы хотите сохранить тэг, чьи символы yyleng - 1
(так как yyleng
включает <
.) Это означает, что вам нужна временная строка, размер которой yyleng - 1 + 1
(или yyleng
для краткости), потому что вам нужно NUL-завершить копию. За исключением того, что вам действительно не нужна эта копия. Но мы вернемся к этому позже.
printf("tagName: %s, tagName length: %lu\n", tagName, strlen(tagName));
Я знаю, что вы планируете скопировать yytext
в tagName
, но вы еще этого не сделали. Так что на данный момент это неинициализированное хранилище. Попытка напечатать это неопределенное поведение. Попытка получить его длину с strlen
- Неопределенное Поведение. Очевидно, это собирается напечатать мусор. (В любом случае, зачем вам вычислять strlen
? Вы точно знаете, как долго эта строка будет: yyleng - 1
.)
strncpy(tagName, yytext + 1, yytextlen - 1);
В какой-то момент я ' Я собираюсь отказаться от этого аргумента, но это отличная иллюстрация того, почему вы не должны использовать strncpy
(за исключением редкого случая использования, для которого он был разработан: поля базы данных фиксированной длины, которые не требуют завершения NUL) , Кажется, люди думают, что strncpy
"безопаснее", чем strcpy
, потому что в его имени есть n
. Но на самом деле это крайне небезопасно, даже менее безопасно, чем strcpy
, потому что не завершает NUL-копию . Как мы видели выше, вы также не оставили достаточно места для терминатора NUL, поэтому, если бы вы использовали strcpy
, который завершает NUL, то он записал бы терминатор NUL вне буфера. Но если бы вы сделали буфер достаточно большим, strcpy
было бы совершенно правильно.
Кроме того, в случае, когда исходная строка в strncpy
короче цели, strncpy
заполняет остальную часть цели значениями NUL. Все это. Это почти всегда пустая трата циклов (за исключением случаев, подобных этому, когда он вообще не записывает NUL и выдает неопределенное поведение).
Если вы действительно хотите сделать копию строки, ограниченную максимальной длиной , используйте strndup
(если она есть в вашей библиотеке C, что большинство делает в наши дни). strndup
копирует строку с ограничением длины. И это NUL-прекращает копирование. И динамически распределяет достаточно места для копии. Если вам нужен безопасный интерфейс, используйте его.
Но почему вы чувствуете, что вам нужно сделать копию здесь? Если вы планируете передать токен парсеру, то вам действительно понадобится копия, но локальный массив переменной длины не является той копией, которая вам понадобится, поскольку время жизни локального массива заканчивается, как только действие завершается, что задолго до того, как копия может быть использована. Если вам нужна копия, вам понадобится динамически распределяемая копия. И это именно то, что strndup
дал бы вам.
printf("An html tag { yytext: %s, yyleng: %zu, text: %s, len: %lu }\n",
yytext, yyleng, tagName, strlen(tagName));
Итак, теперь вы сделали свою копию. Но вы сделали это с помощью библиотечной функции, которая не завершает NUL, так что все еще остается неопределенным поведение использовать копию, как если бы она была строкой. Это была бы только строка, если бы она была завершена NUL. И все еще не определено поведение - передавать копию в strlen
, как если бы она была строкой.
С другой стороны, распечатка yytext
и yyleng
в порядке.
printf("\n\n");
}
На этом действие заканчивается. tagName
больше не существует. Его жизнь подошла к концу. yytext
все еще в порядке, но ненадолго: как только сканер начинает искать следующий токен (который сразу же, так как ваше действие не return
токен для его вызывающего), он вернет контроль над yytext
, изменяя его содержимое непредсказуемым образом. Поэтому, если бы вам потребовалась копия строки для возврата с типом токена, вы должны были бы уже сделать копию, которая была еще жива.
Надеюсь, что все поможет.