Escolar Documentos
Profissional Documentos
Cultura Documentos
DEPARTAMENTO DE MAQUINAS
ENGENHARIA ELECTROMECÂNICA
Informática II
Compildores
Turma: 1ELM/2021
Discentes:
Fidal Sibia
Objectivo Geral
Objectivos Específicos
a) Adquirir uma visão geral sobre o Processo de Compilação sob o ponto de vista de
implementação.
b) Adquirir noções básicas sobre a Teoria das Linguagens Formais.
c) Saber especificar aspectos léxicos e sintáticos de linguagens através de autômatos e
gramáticas.
d) Conhecer critérios e características usados no projeto/avaliação de Linguagens de
Programação.
e) Conhecer as principais técnicas e ferramentas de apoio usadas na construção de
compiladores, sabendo usá-las na especificação e implementação de linguagens de
programação.
Indice
3. Linguagens de programação ....................................................................................................................... 7
5.1. Análise léxica .......................................................................................................................................... 11
5.2. Análise sintática .................................................................................................................................... 11
5.3. Análise semântica................................................................................................................................... 12
5.4. Geração de código intermediário........................................................................................................... 12
5.5. Otimização de código ............................................................................................................................. 13
5.6. Geração de código final.......................................................................................................................... 13
6. Tipos de compiladores ................................................................................................................................. 13
6.1. Compilador cruzado ............................................................................................................................... 13
6.2. Compilador Source-to-source ................................................................................................................ 14
6.3. Compilador Just-in-time (JIT) ................................................................................................................. 14
7. Ferramentas de construção dos compiladores ........................................................................................... 15
a. Scanner generators .................................................................................................................................... 15
b. Mecanismos de tradução de sintaxe.......................................................................................................... 15
c. Geradores de analisador ............................................................................................................................ 15
d. Geradores de código automáticos ............................................................................................................. 15
e. Mecanismos de fluxo de dados .................................................................................................................. 15
8. Diferenças entre compilador e interpretador ............................................................................................ 15
8.1. Vantagens e desvantagens dos compiladores ....................................................................................... 16
Vantagens e desvantagens dos interpretadores................................................................................................ 17
Indice de Figuras
Os softwares para os primeiros computadores foram escritos principalmente em linguagem assembly por
muitos anos. As linguagens de alto nível de programação não foram inventadas até que os benefícios de ser
capaz de reutilizar software em diferentes tipos de CPUs passassem a ser significativamente maiores do que
o custo de se escrever um compilador. A capacidade de memória muito limitada dos primeiros
computadores também criava muitos problemas técnicos na implementação de um compilador.
Em muitos domínios de aplicação a ideia de usar uma linguagem de alto nível rapidamente ganhou força.
Por causa da funcionalidade de expansão apoiada por linguagens de programação recentes e a complexidade
crescente de arquiteturas de computadores, os compiladores tornaram-se mais e mais complexos. Os
primeiros compiladores foram escritos em linguagem assembly.
O primeiro compilador de auto-hospedagem - capaz de compilar seu próprio código-fonte em uma
linguagem de alto nível - foi criado para o Lisp por Tim Hart e Levin Mike no MIT (Massachusetts Institute
of Technology) em 1962.
2. Compiladores
Um compilador é um programa de computador (ou um grupo de programas) que, a partir de um código
fonte escrito em uma linguagem compilada, cria um programa semanticamente equivalente, porém escrito
em outra linguagem, código objeto. Classicamente, um compilador traduz um programa de uma linguagem
textual facilmente entendida por um ser humano para uma linguagem de máquina, específica para um
processador e sistema operacional. Atualmente, porém, são comuns compiladores que geram código para
uma máquina virtual que é, depois, interpretada por um interpretador. Ele é chamado compilador por razões
históricas; nos primeiros anos da programação automática, existiam programas que percorriam bibliotecas
de sub-rotinas e as reunia, ou compilava, as subrotinas necessárias para executar uma determinada tarefa.
O nome "compilador" é usado principalmente para os programas que traduzem o código fonte de uma
linguagem de programação de alto nível para uma linguagem de programação de baixo nível (por exemplo,
Assembly ou código de máquina). Contudo alguns autores citam exemplos de compiladores que traduzem
para linguagens de alto nível como C. Para alguns autores um programa que faz uma tradução entre
linguagens de alto nível é normalmente chamado um tradutor, filtro ou conversor de linguagem. Um
programa que traduz uma linguagem de programação de baixo nível para uma linguagem de programação
de alto nível é um descompilador. Um programa que faz uma tradução entre uma linguagem de montagem
e o código de máquina é denominado montador (assembler). Um programa que faz uma tradução entre o
código de máquina e uma linguagem de montagem é denominado desmontador (disassembler).
Se o programa compilado pode ser executado em um computador cuja CPU ou sistema operacional é
diferente daquele em que o compilador é executado, o compilador é conhecido como um compilador
cruzado.
3. Linguagens de programação
Podemos definir uma linguagem comumente chamada de língua ou idioma como um meio de
comunicação entre pessoas. Em programação definimos a linguagem como o meio de comunicação entre
o pensamento humano e as ações de um computador.
Todo o software executado em um computador foi escrito em alguma linguagem e antes que ele possa
executar instruções diretamente no processador, um outro programa deve ser utilizado para traduzir essa
linguagem em um formato que possa ser entendido e executado pelo computador, esse programa é
chamado de compilador.
As linguagens de programação são projetadas para permitir que seres humanos expressem processos
computacionais em uma sequência de operações, tal como ler um arquivo e imprimir o seu conteúdo em
algum dispositivo, numa impressora por exemplo.
Os programas executados no computador são sequências de 0 e 1 que representam valores inteiros, ponto
flutuante, strings, etc., ou ainda instruções que indicam o que o computador deve fazer. A memória do
computador é dividida em partes que possuem endereços únicos, todo o programa armazenado na
memória é executado pela CPU que possui registradores que guardam dados temporários utilizados em
operações.
Pense na seguinte situação: para somar o número armazenado no endereço de memória $000011 com o
número armazenado no endereço de memória $000012 é necessário:
copiar o conteúdo da memória $000011 para um registrador A;
copiar o conteúdo da memória $000012 para um registrado B;
somar o conteúdo de A e B e copiar o resultado para o endereço de memória $000013.
Esse processo certamente é muito mais complexo do que simplesmente executar o comando c = a + b em
uma determinada linguagem de programação.
Uma linguagem de programação é considera de alto nível quando sua representação está próxima do
domínio da aplicação e do problema a ser resolvido. Os computadores por sua vez possuem sua própria
linguagem denominada de baixo nível ou linguagem de máquina.
O processo de tradução de uma linguagem de alto nível para linguagem de baixo nível é feito atra vés de
softwares conhecidos como compiladores e tem como entrada uma linguagem fonte, alto nível, e como
saída uma linguagem-objeto, baixo nível.
Na imagem acima podemos ver um diagrama que representa o processo de compilação, onde a entrada
é um programa fonte e a saída é um programa objeto. Posteriormente, outros processos estão envolvidos
na compilação, como por exemplo, o Ligador e o Carregador que criam o programa executável e
auxiliam a sua execução.
As linguagens de programação podem ser classificadas em 5 gerações:
1ª linguagens de máquina – baixo nível.
2ª linguagens simbólicas ou montagem (Assembly) – baixo nível.
3ª linguagens orientadas a usuário – alto nível.
4ª linguagens orientadas a aplicação – alto nível.
5ª linguagens de conhecimento – alto nível.
Cada vez mais os compiladores e as linguagem de programação assumem tarefas que antes eram de
responsabilidade do programador, como por exemplo, gerenciamento de memória, verificação de tipos
e execução paralela.
Através das linguagens de programação, consegue-se:
Facilidades para se escrever programas;
Diminuição do problema de diferenças entre máquina;
Facilidade de depuração e manutenção de programas;
Melhoria da interface homem/máquina;
Redução no custo e tempo necessário para o desenvolvimento de programas;
Os primeiros passos para tornar a linguagem mais inteligível por humanos ocorreu na década de 50 com
o desenvolvimento de linguagens simbólicas ou assembly. As instruções em Assembly representavam
mnemônicos das instruções de máquina, mais tarde surgiram ferramentas conhecidas como macro
assemblers que permitiam abreviaturas parametrizadas de uma sequência de instruções Assembly.
O surgimento das linguagens de programação como o FORTRAM e Cobol influenciaram o
desenvolvimento de compiladores pois permitiam que construções de alto nível fossem possíveis de
serem escritas de forma mais fácil. Posteriormente, com o surgimento de novas linguagem de
programação com recursos cada vez mais inovadores, os compiladores se tornaram ferramentas muito
mais sofisticadas.
Os programadores que utilizam linguagem de baixo nível têm mais controle sobre a execução de seus
programas e podem produzir um código mais eficiente, mas esses programas são difíceis de serem
escritos e executados em outras máquinas.
Com a evolução dos compiladores os programas escritos em linguagens de alto nível puderam ser
otimizados para que fossem tão eficientes quanto programas escritos em linguagens de baixo nível.
Linguagens de alto nível possuem recursos como laços, tipos de dados, controle de fluxo, etc. que
facilitam a escrita de programas. Esses recursos são traduzidos para linguagens de baixo nível e
executadas diretamente nos processadores através de instruções de máquina.
A criação de uma linguagem de programação depende do domínio da aplicação a que ela se propõe e
isso também é um motivador para o surgimento de novas linguagens. Embora muitas tenham surgido
com propósitos específicos, é comum uma linguagem ter muitas características e ser empregada em
vários domínios de aplicação.
4. Caracteristicas das Linguagens de Programação
Normalmente, o código fonte é escrito em uma linguagem de programação de alto nível, com grande
capacidade de abstração, e o código objeto é escrito em uma linguagem de baixo nível, como uma sequência
de instruções a ser executada pelo microprocessador.
O processo de compilação é composto de análise e síntese. A análise tem como objetivo entender o código
fonte e representá-lo em uma estrutura intermediária. A síntese constrói o código objecto a partir desta
representação intermediária.
A análise pode ser subdividida ainda em análise léxica, análise sintática, análise semântica e geração de
código intermediário. É também conhecida como front end. A síntese pode ter mais variações de um
compilador a outro, podendo ser composta pelas etapas de optimização de código e geração de código final
(ou código de máquina), sendo somente esta última etapa é obrigatória. É também conhecida como back
end.
Em linguagens híbridas, o compilador tem o papel de converter o código fonte em um código chamado
de byte code, que é uma linguagem de baixo nível. Um exemplo deste comportamento é o do compilador
da linguagem Java que, em vez de gerar código da máquina hospedeira (onde se está executando o
compilador), gera código chamado Java Bytecode.
Um compilador é chamado de Just-in-time compiler (JIT) quando seu processo de compilação acontece
apenas quando o código é chamado. Um JIT pode fazer otimizações às instruções a medida que as compila.
Muitos compiladores incluem um pré-processador. Que é um programa separado, ativado pelo compilador
antes do início do processo de tradução. Normalmente é responsável por mudanças no código fonte
destinadas de acordo com decisões tomadas em tempo de compilação. Por exemplo, um programa
em C permite instruções condicionais para o pré-processador que podem incluir ou não parte do código
caso uma assertiva lógica seja verdadeira ou falsa, ou simplesmente um termo esteja definido ou não.
Tecnicamente, pré-processadores são muito mais simples que compiladores e são vistos, pelos
desenvolvedores, como programas à parte, apesar dessa visão não ser necessariamente compartilhada pelo
usuário.
Outra parte separada do compilador que muitos usuários vêem como integrada é o linker, cuja função é unir
vários programas já compilados de uma forma independente e unificá-los em um programa executável. Isso
inclui colocar o programa final em um formato compatível com as necessidades do sistema operacional
para carregá-lo em memória e colocá-lo em execução.
5. Fazes da compilacao
operandos e op uma operação qualquer. Uma forma prática de representar sentenças de três endereços é
através do uso de quádruplas (operador, argumento 1, argumento 2 e, resultado). Este esquema de
representação de código intermediário é preferido por diversos compiladores, principalmente aqueles que
executam extensivas otimizações de código, uma vez que o código intermediário pode ser rearranjado de
uma maneira conveniente com facilidade. Outras representações de código intermediário comumente
usadas são as triplas, (similares as quádruplas exceto pelo fato de que os resultados não são nomeados
explicitamente) as árvores, os grafos acíclicos dirigidos(DAG) e a notação polonesa.
6. Tipos de compiladores
6.1. Compilador cruzado
É um compilador que consegue criar códigos executáveis para plataformas diferentes da que está sendo
executado. Um exemplo disso seria a criação de um APK (formato de arquivo padrão do android) a partir
de um programa no Windows 10. Existem também outros pontos positivos desse método:
criação de programas para sistemas embutidos, já que eles não tem muitos recursos. Um exemplo
disso seria um microondas que contém um computador com pouco processamento e contém uma
série de equipamentos como um touchpad, sensor na porta, um alto falante, uma tela digital para
mostrar o tempo e o controlador da máquina de esquentar a comida. Tudo isso deve ser controlado
por um pequeno computador que não é muito poderoso para conter todo um ambiente de
desenvolvimento, logo, é mais simples utilizar a compilação cruzada nesses casos;
compilação para várias máquinas. Por exemplo, para uma empresa que precisa de suporte para
várias versões de um sistema operacional ou até mesmo vários sistemas operacionais.
\
Figura 4 - Diferenças entre compilador e interpretador
Um compilador é um programa que traduz o código escrito em uma linguagem de alto nível para
código de máquina. Em resumo, traduz o código legível para os seres humanos e converte para a linguagem
binária que o processador entende. Além disso, o compilador deve obedecer as regras de sintaxe da
linguagem, no caso, se ocorrer algum erro você deve corrigi-los.
Alguns exemplos de linguagens que utilizam compiladores:
Java;
C++;
Switch;
C#;
Rust.
O interpretador também é um programa, porém, ele não tem o processo de traduzir todo o programa
em um arquivo para conseguir rodar, e sim, ele inclui cada instrução da sua linguagem de alto nível
no código de máquina. Com isso, o papel de tradução é feito de uma maneira muito mais dinâmica e que
consegue incluir alguns tipos de código, tais como, scripts, códigos pré-compilados e o próprio código
fonte.