Tradutores e Compiladores
Um tradutor é um programa que recebe como dado de entrada um programa escrito em uma linguagem de programação (a linguagem fonte) e produz como saída de seu processamento um programa escrito em outra linguagem (a linguagem objeto).
Se a linguagem fonte é uma linguagem de alto nível (Fortran, Pascal, C, etc), e a linguagem objeto é uma linguagem de baixo nível (Montagem ou de máquina), o tradutor é chamado de compilador.
Tradutores e Compiladores
Por esse enfoque, a execução de um programa escrito em linguagem de programação de alto nível é basicamente um processo de dois passos:– O programa fonte deve primeiro ser compilado, isto é,
traduzido para a linguagem objeto;
– Em seguida deve ser carregado na memória e executado.
Tradutores e Compiladores
Outros Tradutores:
Interpretadores– Certos tipos de tradutores transformam uma
linguagem de programação em uma linguagem simplificada, chamada de código intermediário, que pode ser diretamente “executado” por um programa chamado interpretador. Por exemplo, Basic, Prolog e Java, são freqüentemente interpretadas.
Tradutores e Compiladores
Outros Tradutores:
Interpretadores– Interpretadores são, em geral, menores que
compiladores e facilitam a implementação de construções complexas em linguagens de programação.
– Entretanto, o tempo de execução de um programa interpretado é geralmente maior que o tempo de execução desse mesmo programa compilado.
Tradutores e Compiladores
Outros Tradutores:
Pré-processadores– Pré-processadores traduzem programas escritos em
linguagens de alto nível em outros programas escritos também em linguagens de alto nível (p.ex. o pré-processador da linguagem C).
Compiladores
Logo, compilador é um programa que lê um programa escrito numa linguagem, a linguagem fonte, e o traduz num programa equivalente numa outra linguagem, a linguagem objeto ou alvo.
– Ou seja, um compilador traduz a linguagem fonte para a linguagem objeto.
Além disso, ele relata a seu usuário a presença de erros no programa fonte.
Compiladores
CompiladorPrograma fonte
Programa Alvo
Mensagem de Erro
Um Compilador
Compiladores
A variedade de compiladores pode parecer assustadora.
– Grande quantidade de linguagens fonte ( Fortran, Pascal, etc.).
– As linguagens alvo podem ser a linguagem de montagem ou uma linguagem de máquina de uma arquitetura qualquer.
Dependendo como tenham sido construídos ou qual a sua função, os compiladores podem receber as seguintes classificações:
Compiladores
– Compiladores de uma pasagem, de passagens múltiplas, otimizantes, etc.
Apesar da aparente complexidade, as tarefas básicas que qualquer compilador precisa realizar são essencialmente as mesmas. – Logo, pode-se construir compiladores para uma
ampla variedade de linguagens fonte e máquinas alvo, usando as mesmas técnicas básicas.
Compiladores
Os primeiros compiladores surgiram no início dos anos 50. – Muitos dos trabalhos iniciais lidavam com a tradução
de fórmulas aritméticas em código de máquina.
Ao longo dos anos 50 foram considerados programas difíceis de escrever.
Compiladores
A evolução tecnológica (novas linguagens de programação, ferramentas de software etc.) e a adoção de técnicas sistemáticas para o tratamento das principais tarefas facilitaram o desenvolvimento de compiladores.
Compiladores
O Modelo de Compilação de Análise e Síntese.
Existem duas partes na compilação: a análise e a síntese.
Na Análise:O programa fonte é dividido em suas partes constituintes e é criado uma representação
intermediária do mesmo.
Compiladores
Na Síntese:
O programa alvo desejado é construído a partir da representação intermediária.
Requer as técnicas mais especializadas.
Compiladores
AnálisePrograma fonte
Programa AlvoMensagem de Erro
Um Compilador – Análise e Síntese
SínteseRepresentaçãoIntermediária
Compilador
Compiladores
Durante a análise as operações implicadas pelo programa fonte são determinadas e registradas numa estrutura hierárquica, chamada de árvore.
– Freqüentemente, é utilizado um tipo especial de árvore, chamado árvore sintática, na qual cada nó representa uma operação e o filho de um nó representa o argumento da operação.
Qual seria a árvore sintática para a expressão abaixo?
Montante := depósito_inicial + taxa_de_juros * 60
Compiladores
:=
montante +
depósito_inicial *
taxa_de_juros 60
Árvore sintática para montante := depósito_inicial + taxa_de_juros * 60
Compiladores
Muitas ferramentas de software que manipulam programas fonte realizam primeiro algum tipo de análise. – Exemplos: editores de estruturas, verificadores
estáticos, interpretadores, etc.
Na interpretação, em lugar de produzir um programa alvo como resultado da tradução, um interpretador realiza as operações especificadas pelo programa fonte.
Compiladores
Tradicionalmente, pensamos num compilador como um programa que transforma uma linguagem fonte, como Fortran, numa linguagem de montagem ou na linguagem de máquina de algum computador.
Há algumas áreas onde a tecnologia de compiladores é regularmente utilizada.– Por exemplo, a parte de análise é similar àquela de um
compilador convencional nos formatadores de texto, linguagens de consulta a banco de dados etc.
Compiladores
O Contexto de um Compilador
Adicionalmente ao compilador, vários outros programas podem ser necessários para se criar um programa alvo executável.
– Um programa pode ser dividido em módulos armazenados em arquivos distintos. A tarefa de coletar esses módulos é, algumas vezes, confiada a um programa distinto, chamado de pré-processador.
Compiladores
Numa compilação típica o programa alvo criado pelo compilador pode exigir processamento posterior antes que possa ser executado.
– O compilador cria um código de montagem que é traduzido no de máquina por um montador e, então, ligado a algumas rotinas de biblioteca, formando o código que é efetivamente executado em máquina.
Compiladores
pré-processador
compilador
montador
carregador
Esqueleto do programa fonte
Programa fonte
Programa alvo em linguagem de montagem
Código de máquina relocável
Código de máquina absoluto
Bibliotecas, arquivos objetos relocáveis
Uma Compilação Típica
Análise do Programa Fonte
Na compilação, a Análise consiste de em três fases:
Análise Linear ou Léxica Análise Hierárquica ou Sintática e Análise Semântica.
Análise do Programa Fonte
Análise Linear ou Léxica Num compilador, a análise linear é chamada de
análise léxica ou esquadrinhamento (scanning).– É a primeira fase de um compilador.– Nessa fase, o trabalho é feito por um módulo
chamado analisador léxico (scanner).
Nela um fluxo de caracteres constituindo um programa é lido da esquerda para a direita e agrupado em tokens, que são sequências de caracteres tendo um significado coletivo (grupos de símbolos).
Análise do Programa Fonte
Análise Linear ou Léxica
Ou seja, os caracteres de um programa fonte são lidos e agrupados num fluxo de tokens, onde cada token representa uma sequência de caracteres logicamente coesiva – Exemplo: nomes (identificadores) de variáveis e
procedimentos (X, SOMA), palavras-chave (if, while, etc), caracteres de pontuação ou operadores, tais como +, * e :=.
A seguência de caracteres que formam um token é chamada o lexema para aquele token.
Análise do Programa Fonte
Análise Linear ou Léxica
Dado o enunciado de atribuição abaixo:
Os seus caracteres poderiam ser agrupados nos seguintes tokens:
Montante := depósito_inicial + taxa_de_juros * 60
Análise do Programa Fonte
Análise Linear ou Léxica– O identificador montante.– O símbolo de atribuição :=– O identificador depósito_inicial.– O sinal de adição.– O identificador taxa_de_juros.– O sinal de multiplicação.– O número 60.
Os espaços que separam os caracteres desses tokens são eliminados.
Análise do Programa Fonte
Análise Linear ou Léxica
Certos tokens serão enriquecidos por um valor léxico.
Quando um identificador, como taxa_de_juros, é encontrado, o analisador léxico não somente gera um token, mas, também, instala o lexema taxa_de_juros em uma estrutura de dados conhecida como tabela de símbolos, se já não estiver lá.– O valor léxico do token gerado é a entrada na tabela de
símbolos que aponta para taxa_de_juros.
Análise do Programa Fonte
Análise Linear ou Léxica
A sequência de tokens (sequência de símbolos) produzida pela análise léxica será utilizada como entrada para o analisador sintático.
Os tokens são geralmente representados por códigos (valores inteiros).
Análise do Programa Fonte
Análise Hierárquica ou Sintática
A análise hierárquica é chamada de análise gramatical ou análise sintática.
Nessa fase, o analisador sintático (passer) agrupa os símbolos (tokens) recebidos do analisador léxico em estruturas sintáticas.– Os três símbolos representando A + B poderiam ser
agrupados em uma estrutura sintática chamada expressão. Expressões poderiam ser posteriormente agrupadas para formar comandos, e assim por diante.
Análise do Programa Fonte
Análise Hierárquica ou Sintática
Dessa forma, nessa fase os tokens são agrupados hierarquicamente em coleções aninhadas utilizando, para isso, estruturas representadas por meio de árvores sintáticas.
Análise do Programa Fonte
Análise Semântica
A análise semântica verifica se as estruturas sintáticas criadas pelo analisador sintático, embora corretas sintaticamente, têm significado admissível na linguagem. – Por exemplo, A + B pode ser uma expressão
sintaticamente correta, mas pode não ter significado em muitas linguagens se A for inteiro e B for caracter.
Análise do Programa Fonte
Análise Semântica
Assim, a fase de análise semântica verifica os erros semânticos no programa fonte e captura as informações de tipo para a fase subseqüente de geração de código.
Essa fase utiliza a estrutura hierárquica determinada pela fase de análise sintática, a fim de identificar os operadores e operandos das expressões e enunciados.
Análise do Programa Fonte
Análise Semântica
Um importante componente da análise semântica é a verificação de tipos.– O compilador checa se cada operador recebe os
operandos que são permitidos pela especificação da linguagem fonte.
Exemplos: – Relato de erro se número real for utilizado para
indexar arrays.– Pode haver permissão para coerção de operandos. Na
soma de inteiro e real, o número inteiro é convertido para real.
As Fases de Um Compilador
A compilação é um processo complexo que não é razoável, do ponto de vista lógico e de implementação, considerá-lo como sendo desenvolvido em um único passo. – Por essa razão, é costume partir o processo de
compilação em uma série de subprocessos chamados fases.
Uma fase é uma operação que toma como entrada uma representação do programa fonte e produz como saída uma outra representação.
As Fases de Um Compilador
Logo, conceitualmente, um compilador opera em fases, cada uma das quais transforma o programa fonte de uma representação para outra.
As Fases de Um
Compilador
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Na prática algumas das fases podem ser agrupadas e a representação intermediária entre as mesmas não precisa ser explicitamente construída.
As três primeiras fases (Análise Léxica, Sintática e Semântica) forma o núcleo da parte de Análise.
Duas outras atividades, o gerenciamento da tabela de símbolos e a manipulação de erros, são mostradas interagindo com todas as fases.– Informalmente essas atividades são também
chamadas de fases.
As Fases de Um Compilador
Gerenciamento da Tabela de Símbolos
Uma função essencial do compilador é registrar os identificadores usados no programa fonte e coletar as informações sobre os seus diversos atributos.
Esses atributos podem providenciar informações sobre:– Memória reservada para o identificador, seu tipo,
escopo (onde é valido no programa);
As Fases de Um Compilador
Gerenciamento da Tabela de Símbolos No caso de nomes de procedimentos, coisas
tais como o número e os tipos de seus argumentos, o método de transmissão de cada um (valor ou referência por exemplo) e o tipo retornado, se algum.
O módulo de gerência de tabela de símbolos tem por função guardar informações a respeito de todos os nomes usados pelo programa e registrar informações importantes associadas a cada um, tais como seu tipo (inteiro, real, etc.), tamanho, escopo, etc.
As Fases de Um Compilador
Gerenciamento da Tabela de Símbolos
A estrutura de dados usada para registrar essas informações é chamada tabela de símbolos.
Essa tabela contém um registro para cada identificador, com os campos contendo os atributos do identificador.
As Fases de Um Compilador
Gerenciamento da Tabela de Símbolos Quando o analisador léxico detecta um
identificador no programa fonte, ele instala-o na tabela de símbolos.
Nessa fase, os atributos não podem ser normalmente determinados. Ex:
var montante, deposito_inicial, taxa_de_juros: real;
As Fases de Um Compilador
Gerenciamento da Tabela de Símbolos As fases remanescentes colocam informações
sobre os identificadores na tabela de símbolos e em seguida as usam de várias maneiras.
As Fases de Um Compilador
Detecção de Erros e Geração de Relatórios
Cada fase pode encontrar erros.– É preciso que o compilador lide com eles para que a
compilação continue.
O manipulador de erros é ativado sempre que for detectado um erro no programa fonte.
Ele deve avisar o programador da ocorrência do erro emitindo uma mensagem, e ajustar-se novamente à informação sendo passada de fase a fase de modo a poder completar o processo de compilação.
As Fases de Um Compilador
Detecção de Erros e Geração de Relatórios Mesmo que não seja mais possível gerar código
objeto, a análise léxica e sintática deve prosseguir até o fim.
As fases de análise sintática e semântica tratam usualmente de uma ampla fatia dos erros detectáveis pelo compilador.
A fase de análise léxica pode detectá-los quando os caracteres na entrada não formem qualquer token da linguagem.
As Fases de Um Compilador
Detecção de Erros e Geração de Relatórios Os erros, onde o fluxo de tokens viole as regras
estruturais (sintaxe) da linguagem, são determinados pela fase de análise sintática.
Durante a análise semântica, o compilador tenta detectar as construções que possuam a estrutura sintática correta
As Fases de Um Compilador
À medida que a tradução progride, a representação interna do compilador para o programa fonte muda. Ex: seja o enunciado:
Vamos examinar essa representação após cada fase:
Montante := depósito_inicial + taxa_de_juros * 60
As Fases de Um Compilador
À medida que a tradução progride, a representação interna do compilador para o programa fonte muda. Ex: seja o enunciado:
Vamos examinar essa representação após cada fase:
var montante, deposito_inicial, taxa_de_juros: real;
Análise Léxica
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Análise Léxica:
Geração dos tokens. Digamos: id1, id2, ... , idn.
Quando um identificador como taxa_de_juros é encontrado, um token é gerado (id3) e o lexema correspondente é instalado na tabela de símbolos.
Montante := depósito_inicial + taxa_de_juros * 60
id1 := id2 + id3 * 60
As Fases de Um Compilador
Análise Léxica:
A representação interna de um identificador é diferente da sequência de caracteres que formam o identificador.
11 montante ...
22 Depósito_inicial ...
33 Taxa_de_juros ...44
Tabela de Símbolos
Análise Sintática
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Análise Sintática: A análise sintática impõe um estrutura
hierárquica ao fluxo de tokens através de árvores sintáticas.
id1 := id2 + id3 * 60
:= id1 + id2 * id3 60
As Fases de Um Compilador
Análise Sintática:
Uma estrutura de dados típica para a árvore sintática seria:
::==
++
**
idid 11
idid 22
idid 33 numnum 6060
Análise Semântica
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Análise Semântica: Entre outras coisas, a análise semântica verifica
os tipos. := id1 + id2 * id3 60
:= id1 + id2 * id3 inttoreal 60
Geração de Código
Intermediário
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Geração de Código Intermediário: O gerador de código intermediário usa as
estruturas produzidas pelo analisador sintático e verificadas pelo analisador semântico para criar uma seqüência de instruções simples dita código intermediário.– está entre a linguagem de alto nível e a linguagem de
baixo nível.
Podemos pensar dessa representação intermediária como um programa para uma máquina abstrata.
As Fases de Um Compilador
Geração de Código Intermediário: A representação intermediária pode ter uma
variedade de formas. – Ex: pode-se utilizar uma sequência de instruções
onde cada uma possui no máximo três operandos (Código de três endereços).
As Fases de Um Compilador
Geração de Código Intermediário: := id1 + id2 * id3 inttoreal 60
temp1 := inttoreal(60)temp2 := id3 * temp1temp3 := id2 + temp2Id1 := temp3
As Fases de Um Compilador
Geração de Código Intermediário: Propriedades da forma intermediária:
– Cada instrução de três endereços possui, no máximo, um operador, além do de atribuição.
Ao gerar essas instruções, o compilador precisa decidir sobre a ordem em que as mesmas devam ser realizadas.
– O computador precisa gerar um nome temporário para receber o valor computado em cada instrução.
– Algumas instruções de três endereços possuem menos do que três operandos.
Otimizador de Código
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Otimizador de Código: O otimizador de código (independente de
máquina) é um módulo opcional (presente na grande maioria dos compiladores) que objetiva melhorar o código intermediário de modo que o programa objeto produzido ao fim da compilação seja menor (ocupe menos espaço de memória) e/ou mais rápido (tenha tempo de execução menor).
A saída do otimizador de código é um novo código intermediário.
As Fases de Um Compilador
Geração de Código Intermediário:
temp1 := inttoreal(60)temp2 := id3 * temp1temp3 := id2 + temp1Id1 := temp3
temp1 := id3 * 60,0Id1 := id2 + temp1
As Fases de Um Compilador
Otimizador de Código: Existe uma grande variação na quantidade de
otimizações de código que cada compilador executa. Naqueles que mais a realizam chamamos de “compiladores otimizantes”, uma porção significativa de seus tempos é gasta nesta fase.
Geração de Código
Analisador Léxico
Analisador Sintático
Analisador Semántico
Gerador de Código Intermediário
Otimizador de Código
Gerador de Código
Programa Alvo
Programa Fonte
Tratador de ErrosGerenciador da Tabela de Símbolos
As Fases de Um Compilador
Geração de Código: O gerador de código produz o código objeto
final(código de máquina ou código de montagem), tomando decisões com relação à:– Alocação de espaço para os dados do programa,
seleção da forma de acessá-los, definição de quais registradores da UCP serão usados, etc.
Projetar um gerador de código que produza programas objeto verdadeiramente eficientes é uma das tarefas mais difíceis no projeto de um compilador.
As Fases de Um Compilador
Geração de Código:
temp1 := id3 * 60,0Id1 := id2 + temp1
MOVF id3, R2MULF #60,0, R2MOVF id2, R1ADDF R2, R1MOVF R1, id1
As Fases de Um Compilador
Gerador de Código:
Nessa fase as localizações de memória são selecionadas para cada uma das variáveis. Então as instruções intermediárias são traduzidas numa sequência de instruções de máquina que realizam a mesma tarefa.
Um aspecto crucial é a atribuição das variáveis aos registradores.
As Fases de Um Compilador
Gerador de Código:
Nessa fase as localizações de memória são selecionadas para cada uma das variáveis. Então as instruções intermediárias são traduzidas numa sequência de instruções de máquina que realizam a mesma tarefa.
Um aspecto crucial é a atribuição das variáveis aos registradores.
As Fases de Um Compilador
Gerador de Código:
A maioria dos compiladores atuais tem, como parte integrante de seu gerador de código, um módulo adicional de otimização de código dependente de máquina que tem por objetivo melhorar o código de máquina produzido para melhor aproveitar os recursos específicos da arquitetura para a qual foi gerado.
Top Related