História da continuação: Compilador de Pascal para Windows a partir do zero

As boas-vindas inesperadamente calorosas fornecidas pelo público Habr ao meu post sobre o compilador caseiro XD Pascal para MS-DOS me fizeram pensar. Não é irritante que o projeto amador, para o qual dei muita energia, tenha sido um peso morto para mim desde o momento em que a máquina virtual do DOS desapareceu completamente do Windows? O resultado das reflexões foi o compilador XD Pascal para Windows . Talvez ele tenha perdido um pouco do charme nostálgico e tenha perdido a possibilidade de um trabalho ingênuo com gráficos através de interrupções no BIOS. No entanto, a transição para o Windows deu nova vida ao projeto e abriu caminho para um sonho de longa data - a autocompilação.

Como antes, eu não usei nenhuma ferramenta auxiliar para geração automática de compilador. Essa teimosia pode parecer estranha, mas o projeto tinha um único objetivo - meu próprio prazer, e ferramentas adicionais serviriam apenas como um obstáculo. Nesse sentido, o compilador foi desenvolvido do zero.



Cinco etapas para a autocompilação no Windows


Vale a pena dizer algumas palavras sobre as principais tarefas que precisaram ser resolvidas no caminho do DOS para o Windows:

Formação de cabeçalhos e seções do arquivo executável. Além da descrição oficial do formato Executável portátil, o artigo Criando o menor executável PE possível tornou-se uma excelente ajuda nesse estágio. Como os cabeçalhos e as seções requerem endereços exatos de procedimentos e variáveis, e só podem ser encontrados após o cálculo do tamanho do código e dos dados globais, a compilação teve que ser feita em três passagens. Na primeira passagem, um gráfico de chamadas de procedimento é construído e os procedimentos "mortos" são marcados; no segundo, endereços, código e tamanho dos dados são calculados, cabeçalhos são preenchidos; no terceiro, um código é gerado. Esse kunshtuk é muito inesgotável, especialmente considerando que a cada passo todos os estágios de compilação são repetidos novamente, começando com a análise lexical. No entanto, isso leva a um código-fonte muito conciso para o compilador e não requer nenhuma representação intermediária do programa. Adendo: a geração de código realocável está atualmente implementada, a compilação é feita de passagem única.

Novo gerador de código. A compilação para Windows exigiu a substituição de pares de registros de deslocamento de segmento por registros de deslocamento de 32 bits, bem como a remoção (e adição de locais) de prefixos para alterar o comprimento do operando (66h) e o comprimento do endereço (67h).

Diretiva para declarar funções externas da API do Windows. Todos os nomes de funções declarados com a diretiva external são inseridos nas tabelas da seção de importação do arquivo executável. Como essas funções exigem a passagem de argumentos da direita para a esquerda, tivemos que inverter manualmente a ordem dos argumentos na declaração e nas chamadas de todas essas funções. Portanto, a necessidade de inversão por meio do compilador não é mais necessária. Por uma questão de simplicidade, todos os argumentos para procedimentos e funções no XD Pascal são passados ​​como valores de 32 bits; felizmente, essa regra também é válida para funções da API do Windows; portanto, a interação com as bibliotecas do sistema não complicou o mecanismo de transmissão de argumentos. Adição: a inversão da ordem dos argumentos das funções importadas agora é realizada automaticamente.

Removendo conjuntos e operações de cadeia de caracteres infix do código-fonte. Este requisito está relacionado à tarefa de auto-compilação. O cálculo de qualquer expressão no XD Pascal é projetado para que todos os resultados intermediários tenham 32 bits e sejam armazenados na pilha. Para seqüências e conjuntos de caracteres Pascal, essa abordagem não é aceitável. Mais precisamente, teria permitido que conjuntos tivessem até 32 elementos de tamanho, mas esses conjuntos teriam sido praticamente inúteis. Adição: agora é implementado o suporte para operações de string e configurações de até 256 elementos em tamanho.

Invólucros para alguns procedimentos. A idéia de auto-compilação levou ao empacotamento de chamadas para algumas rotinas na biblioteca padrão. A assinatura do wrapper é a mesma para os casos de compilação por um compilador externo (Delphi / Free Pascal) e auto-compilação; procedimentos embrulhados variam. Assim, todas as especificidades do método de compilação estão localizadas em vários wrappers. Pascal está repleto de procedimentos que, após uma análise mais detalhada, se torna impossível de implementar de acordo com as regras do próprio Pascal: Read , Write , Move , etc. Para os procedimentos mais comuns, incluindo Read e Write , fiz uma exceção e os implementei atípicos para a gramática da linguagem, mas familiares a qualquer conhecedor de Pascal. Para a maioria dos outros procedimentos não típicos, eram necessários invólucros. Portanto, o XD Pascal não é totalmente compatível com o Delphi ou o Free Pascal, mas isso não é grande coisa, já que o próprio Free Pascal no modo de compatibilidade com o Delphi permanece incompatível. Adição: suporte para argumentos de variáveis ​​formais sem tipo agora está implementado. Isso permitiu tornar os procedimentos BlockRead , BlockWrite , Move , FillChar compatíveis com Delphi e Free Pascal, reduzindo radicalmente o número de wrappers necessários.

Compilando programas com uma GUI


A tarefa de autocompilação, apesar de seu significado simbólico, permanece limitada: o compilador é um programa de console e, portanto, não parece um habitante de pleno direito do mundo Windows. Foram necessárias mais algumas inovações no caminho para compilar programas com uma interface de janela:

Diretiva para o compilador para definir o tipo de interface. O tipo de interface (console ou gráfico) deve ser especificado em um campo de cabeçalho separado do arquivo executável. Como você sabe, em Delphi e Free Pascal para isso existe uma diretiva $APPTYPE . Uma diretiva $A A semelhante apareceu no XD Pascal.

A operação de tomar o endereço de procedimentos e funções. No Pascal clássico, não há indicadores completos de procedimentos e funções - eles são substituídos, em certa medida, por um tipo de procedimento. Este tipo não é implementado no XD Pascal. Seja como for, ainda me parecia inútil aplicar a operação @ aos procedimentos em meu modesto projeto. No entanto, o processamento de eventos da API do Windows é baseado em retornos de chamada, e aqui a transferência do endereço do procedimento do manipulador chamado subitamente se tornou uma necessidade urgente. Adição: o XD Pascal agora adiciona suporte completo ao tipo de procedimento.

Especificando explicitamente os nomes das bibliotecas vinculadas. Para programas de console, a importação das funções da API do Windows da biblioteca KERNEL32.DLL foi suficiente. Programas com uma GUI puxada USER32.DLL , GDI32.DLL , etc. Foi necessário expandir a sintaxe da diretiva external adicionando o nome da biblioteca lá.


Demonstração da GUI

Qual é o resultado


O resultado é um compilador de autocompilação muito simples para Windows. É improvável compará-lo corretamente com projetos coletivos poderosos, como o Free Pascal. Em vez disso, ele se enquadra na categoria de peso do famoso amador BeRo Tiny Pascal . Comparado a ele, o XD Pascal tem vantagens visíveis: a gramática de Pascal é mais rigorosamente observada e os erros são controlados, há entrada / saída de arquivo completa, aritmética de número de ponto flutuante é suportada, não há dependência de montador externo, é permitida a compilação de programas com uma interface de janela.

Em seguida, tenho que lidar com os falsos positivos de alguns antivírus - um novo problema que não pensei no pequeno e acolhedor mundo do MS-DOS. Se você tiver sorte, o XD Pascal será apresentado, juntamente com o BeRo Tiny Pascal, em um workshop de laboratório sobre o curso de design de compiladores no MSTU. N.E. Bauman.

Source: https://habr.com/ru/post/pt462889/


All Articles