Compartilhando memória entre arquivos YACC, Lex e C
-
19-09-2019 - |
Pergunta
Eu tenho uma gramática YACC (Bison), um tokenizer Lex (Flex) e um programa C entre os quais preciso compartilhar um struct
(ou realmente qualquer variável).Atualmente, declaro o objeto real no arquivo de gramática e extern
sempre que eu precisar (ou seja, meu arquivo de origem C), geralmente usando um ponteiro para manipulá-lo.Eu tenho um arquivo de cabeçalho (e implementação) compartilhado entre o arquivo C e o arquivo de gramática com funções úteis para manipular minha estrutura de dados.Isso funciona, mas é um pouco desconfortável.Existe uma maneira melhor de compartilhar memória entre a gramática e o programa?
Solução
Um arquivo de cabeçalho para compartilhar a declaração externa entre os arquivos de origem que precisam dele é o melhor caminho a percorrer, geralmente. A principal alternativa é fornecer 'acesso funcional' a ele - ou seja, algum tipo de função 'Get Value' e 'Set Value' (ou um conjunto de funções). Isso geralmente é um exagero. Certifique -se de incluir o cabeçalho na gramática (onde você define a variável), bem como no Lexer e no outro código, para que as inconsistências sejam vistas o mais rápido possível.
Outras dicas
Se você quiser seguir o lex/yacc padrão (POSIX), sua única opção é optar por variáveis/funções globais.Se você estiver satisfeito com o uso de extensões Bison e Flex, existem algumas maneiras de transmitir variáveis, que envolvem principalmente a adição de parâmetros extras a yyparse() e yylex().
No Bison, isso é feito por meio de% lex-param e% parse-param.
%parse-param { struct somestruct *mystruct }
%lex-param { struct somestruct *mystruct }
No Flex, existem dois mecanismos diferentes, dependendo se você deseja um lexer reentrante ou não.Supondo que você escolha a opção padrão (não reentrante), você desejará redefinir YY_DECL:
%{
#define YY_DECL int yylex(struct somestruct *mystruct)
%}
Em um lexer Flex reentrante, argumentos extras podem ser adicionados por meio da estrutura do scanner que o Flex carrega para manter seu estado.Você deseja definir YY_EXTRA_TYPE;os dados extras podem ser acessados através de yyget/set_extra().