Como eu implementaria algo semelhante à Diretiva Objective-C @Encode () Compiler no ANSI C?
-
20-09-2019 - |
Pergunta
A Diretiva @Encode retorna um const Char *, que é um descritor de tipo codificado dos vários elementos do tipo de dados que foi passado. Exemplo segue:
struct test
{ int ti ;
char tc ;
} ;
printf( "%s", @encode(struct test) ) ;
// returns "{test=ic}"
Eu podia ver usando o sizeof () para determinar os tipos primitivos - e se fosse um objeto completo, eu poderia usar os métodos de classe para fazer introspecção.
No entanto, como determina cada elemento de uma estrutura opaca?
Solução
@Lothars Answer pode ser "cínica", mas está bem perto da marca, infelizmente. Para implementar algo como @encode()
, você precisa de um analisador completo para extrair as informações do tipo. Bem, pelo menos para qualquer coisa que não seja "trivial" @encode()
declarações (ou seja, @encode(char *)
). Os compiladores modernos geralmente têm dois ou três componentes principais:
- A extremidade frontal.
- A extremidade intermediária (para alguns compiladores).
- O back -end.
O front -end deve analisar todo o código -fonte e basicamente converter o texto do código -fonte em um formulário interno "utilizável da máquina".
O back -end traduz o formulário interno "utilizável da máquina" para o código executável.
Os compiladores que possuem uma "extremidade intermediária" normalmente o fazem por causa de alguma necessidade: eles suportam vários "front finais", possivelmente compostos de idiomas completamente diferentes. Outro motivo é simplificar a otimização: toda a otimização passa funciona na mesma representação intermediária. o gcc
O Compiler Suite é um exemplo de compilador de "três estágios". llvm
Pode ser considerado um compilador de estágio "intermediário e back -end": a máquina virtual de baixo nível é a representação intermediária e toda a otimização ocorre nesta forma. llvm
Também capaz de mantê-lo nessa representação intermediária até o último segundo- isso permite "otimização do tempo de link". o clang
O compilador é realmente um "front end" que (efetivamente) saídas llvm
Representação intermediária.
Então, se você quiser adicionar @encode()
Funcionalidade para um compilador 'existente', você provavelmente precisaria fazê -lo como uma "fonte de origem" 'compilador / pré -processador'. Foi assim que os compiladores originais Objective-C e C ++ foram escritos- eles analisaram o texto da fonte de entrada e o converteram em "Plain C", que foi então alimentado com o compilador C padrão. Há algumas maneiras de fazer isso:
Role o seu próprio
- Usar
yacc
elex
para montar um analisador ANSI-C. Você precisará de uma gramática ANSI C Gramática (YACC) é um bom começo. Na verdade, para ficar claro, quando digoyacc
, Eu realmente quero dizer búfalo eflex
. E também, vagamente, os outros váriosyacc
elex
como ferramentas baseadas em C: limão, DPARSER, etc ... - Usar
perl
com Yapp ou Eyapp, que são pseudo-yacc
clones emperl
. Provavelmente melhor para prototipando rapidamente uma ideia em comparação com a base de Cyacc
elex
- Estáperl
Afinal: expressões regulares, matrizes associativas, nenhum gerenciamento de memória etc. - Construa seu analisador com Antlr. Não tenho nenhuma experiência com essa cadeia de ferramentas, mas é outra ferramenta "compilador compilador" que (parece) ser mais voltado para os desenvolvedores de Java. Parece haver gramáticas C e Objective-C disponíveis gratuitamente.
Hackear outra ferramenta
Observação: Não tenho experiência pessoal usando nenhuma dessas ferramentas para fazer algo como adicionar @encode()
, mas eu suspeito que eles seriam uma grande ajuda.
- CIL - Não há experiência pessoal com esta ferramenta, mas projetada para analisar o código -fonte C e depois "fazer coisas" com ela. Pelo que posso recolher dos documentos, essa ferramenta deve permitir extrair as informações de tipo que você precisa.
- Escasso - Vale a pena olhar, mas não tenho certeza.
- Clang - Não o usei para esse fim, mas supostamente um dos objetivos era torná -lo "facilmente hackeável" para esse tipo de coisa. Particularmente (e novamente, sem experiência pessoal) em fazer o "levantamento pesado" de toda a análise, permitindo que você se concentre na parte "interessante", que neste caso seria extrair contexto e sintaxe informações sensíveis ao tipo e depois converteria isso em para uma string c simples.
- Plugins GCC - Os plugins são um recurso GCC 4.5 (que é o recurso atual alfa/beta do compilador) e "pode" permitir que você conecte facilmente ao compilador para extrair as informações de tipo que você precisaria. Não faço ideia se a arquitetura do plug -in permite esse tipo de coisa.
Outros
- Coccinelle - Marcado recentemente para "olhar mais tarde". Isso "pode" ser capaz de fazer o que você deseja e "pode" ser capaz de fazê -lo sem muito esforço.
- Metac - Marcado este recentemente marcado recentemente. Não faço ideia de quão útil isso seria.
- mygcc - "pode" fazer o que você quiser. É uma ideia interessante, mas não é diretamente aplicável ao que você deseja. Na página da web: "O MYGCC permite que os programadores adicionem suas próprias verificações que levam em consideração a sintaxe, o fluxo de controle e as informações do fluxo de dados".
Links.
- Cocoadev Objective-C Parsing - Vale a pena olhar. Tem alguns links para Lexers e gramáticas.
Editar #1, os links de bônus.
@Lothar faz um bom ponto em seu comentário. Eu realmente pretendia incluir lcc
, mas parece que se perdeu ao longo do caminho.
- LCC - O
lcc
C compilador. Este é um compilador C que é particularmente pequeno, pelo menos em termos de tamanho do código -fonte. Isso também tem um livro, o que eu recomendo. - TCC - O
tcc
C compilador. Não tão pedagógico quantolcc
, mas definitivamente ainda vale a pena olhar. - poc - O
poc
Objective-C compilador. Esta é um compilador Objective-C "fonte para fonte". Ele analisa o código-fonte Objective-C e emite o código-fonte C, que ele passa paragcc
(bem, geralmentegcc
). Tem várias extensões / recursos objetivas-C que não estão disponíveis emgcc
. Definitivamente vale a pena olhar.
Outras dicas
Você implementaria isso implementando o compilador ANSI C primeiro e depois adicionaria alguns Pragmas e funções específicos de implementação a ele.
Sim, eu sei que essa é uma resposta cínica e aceito os votos.
Uma maneira de fazer isso seria escrever um pré -processador, que lê o código -fonte para as definições de tipo e também substitui @encode
... com a corda correspondente literal.
Outra abordagem, se o seu programa for compilado com -g
, seria escrever uma função que lê a definição de tipo das informações de depuração do programa em tempo de execução ou use gdb
ou outro programa para lê -lo para você e depois reformate -o conforme desejado. o gdb
ptype
O comando pode ser usado para imprimir a definição de um tipo específico (ou se isso é insuficiente, também existe maint print type
, que certamente imprimirá muito mais informações do que você poderia desejar).
Se você estiver usando um compilador que suporta plugins (por exemplo, GCC 4.5), também pode ser possível escrever um plug -in do compilador para isso. Seu plug -in pode então tirar proveito das informações de tipo que o compilador já analisou. Obviamente, essa abordagem seria muito específica do compilador.