У меня есть грамматика YACC (Bison), токенизатор Lex (Flex) и программа на C, среди которых мне нужно разделить struct
(или любую переменную). В настоящее время я объявляю фактический объект в файле грамматики и extern
его везде, где он мне нужен (то есть в исходном файле C), обычно используя указатель для управления им. У меня есть общий файл заголовка (и реализации) между файлом C и файлом грамматики с функциями, полезными для управления моей структурой данных. Это работает, но немного неудобно. Есть ли лучший способ разделить память между грамматикой и программой?
Разделение памяти между файлами YACC, Lex и C
Ответы (2)
Файл заголовка для совместного использования объявления extern между исходными файлами, которым это необходимо, обычно является лучшим способом. Основной альтернативой является предоставление к нему «функционального доступа», т. е. своего рода функции «получения значения» и «установки значения» (или набора функций). Обычно это перебор. Убедитесь, что вы включили заголовок в грамматику (где вы определяете переменную), а также в лексер и другой код, чтобы несоответствия были обнаружены как можно скорее.
Если вы хотите придерживаться стандартного (POSIX) lex/yacc, то единственный вариант — использовать глобальные переменные/функции. Если вас устраивает использование расширений Bison и Flex, есть несколько способов передачи переменных, которые в основном включают добавление дополнительных параметров в yyparse() и yylex().
В Bison это достигается с помощью %lex-param и %parse-param.
%parse-param { struct somestruct *mystruct }
%lex-param { struct somestruct *mystruct }
Во Flex есть два разных механизма, в зависимости от того, нужен ли вам реентерабельный лексер или нет. Предполагая, что вы используете вариант по умолчанию (без повторного входа), вы захотите переопределить YY_DECL:
%{
#define YY_DECL int yylex(struct somestruct *mystruct)
%}
В реентерабельном лексере Flex дополнительные аргументы могут быть добавлены через структуру сканера, которую Flex переносит для сохранения своего состояния. Вы захотите определить YY_EXTRA_TYPE; доступ к дополнительным данным можно получить через yyget/set_extra().