Compilador

866 views
781 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
866
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
21
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Compilador

  1. 1. CompiladorOrigem: Wikipédia, a enciclopédia livre.Ir para: navegação, pesquisa Nota: Compilação redireciona para este artigo. Se procura por compilação musical,veja Coletânea musical.Uma captura de tela do compilador GCC versão 4.0.2 rodando em uma janela xterm.Um programa simples está sendo compilado e então executadoUm compilador é um programa de computador (ou um grupo de programas) que, apartir de um código fonte escrito em uma linguagem compilada, cria um programasemanticamente equivalente, porém escrito em outra linguagem, código objeto.[1] Ele échamado compilador por razões históricas; nos primeiros anos da programaçãoautomática, existiam programas que percorriam bibliotecas de subrotinas e as reuniajuntas, ou compilava,[Nota 1] as subrotinas necessárias para executar uma determinadatarefa.[2][3]O nome "compilador" é usado principalmente para os programas que traduzem o códigofonte de uma linguagem de programação de alto nível para uma linguagem deprogramação de baixo nível (por exemplo, Assembly ou código de máquina). Contudoalguns autores citam exemplos de compiladores que traduzem para linguagens de altonível como C.[4] Para alguns autores um programa que faz uma tradução entrelinguagens de alto nível é normalmente chamado um tradutor, filtro[5] ou conversor delinguagem. Um programa que traduz uma linguagem de programação de baixo nívelpara uma linguagem de programação de alto nível é um descompilador.[6] Um programaque faz uma tradução entre uma linguagem de montagem e o código de máquina édenominado montador (assembler).[5] Um programa que faz uma tradução entre ocódigo de máquina e uma linguagem de montagem é denominado desmontador(disassembler).[6] Se o programa compilado pode ser executado em um computador cujaCPU ou sistema operacional é diferente daquele em que o compilador é executado, ocompilador é conhecido como um compilador cruzado.[7]Índice 1 História 2 Características 3 Fases da compilação o 3.1 Análise léxica o 3.2 Análise sintática
  2. 2. o 3.3 Análise semântica o 3.4 Geração de código intermediário o 3.5 Optimização de código o 3.6 Geração de código final 4 Tratamento de erros 5 Ver também 6 Notas 7 Referências 8 Bibliografia 9 Ligações externasHistóriaGrace Hopper em 1984Os softwares para os primeiros computadores foram escritos principalmente emlinguagem assembly por muitos anos. As linguagens de alto nível de programação nãoforam inventadas até que os benefícios de ser capaz de reutilizar software em diferentestipos de CPUs passassem a ser significativamente maiores do que o custo de se escreverum compilador. A capacidade de memória muito limitada capacidade dos primeiroscomputadores também criava muitos problemas técnicos na implementação de umcompilador.No final da década de 1950, as linguagens de programação independentes de máquinaforam propostas. Posteriormente, vários compiladores experimentais foramdesenvolvidos. O primeiro compilador foi escrito por Grace Hopper,[8] em 1952, para alinguagem de programação A-0.[9] Antes de 1957, foram desenvolvidos esforços evárias contribuições ao desenvolvimento de linguagens de alto nível foram feitas. Entreestes, o desenvolvimento da Short Code (UNIVAC), Speedcoding no IBM 701,[10][11] oWhirlwind, o BACAIC e o PRINT.[12] A equipe de desenvolvimento do FORTRANliderada por John Backus na IBM é geralmente creditada como tendo introduzido oprimeiro compilador completo em 1957 (embora tenha ocorrido simultaneamente odesenvolvimento do algebraic translator de Laning e Zierler[9]). O COBOL é umexemplo de uma linguagem da primeira geração que compilava em múltiplasarquiteturas, em 1960.[13]
  3. 3. Em muitos domínios de aplicação a idéia de usar uma linguagem de alto nívelrapidamente ganhou força. Por causa da funcionalidade de expansão apoiada porlinguagens de programação recentes e a complexidade crescente de arquiteturas decomputadores, os compiladores tornaram-se mais e mais complexos.Os primeiros compiladores foram escritos em linguagem assembly. O primeirocompilador de auto-hospedagem - capaz de compilar seu próprio código-fonte em umalinguagem de alto nível - foi criado para o Lisp por Tim Hart e Levin Mike no MIT em1962.[14]CaracterísticasO processo da compilaçãoNormalmente, 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 debaixo nível,[15] como uma sequência de instruções a ser executada pelomicroprocessador.O processo de compilação é composto de análise e síntese.[16] A análise tem comoobjetivo entender o código fonte e representá-lo em uma estrutura intermediária. Así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álisesemântica e geração de código intermediário. É também conhecida como front end.[16] Asíntese pode ter mais variações de um compilador a outro, podendo ser composta pelas
  4. 4. 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.[16]Classicamente, um compilador traduz um programa de uma linguagem textualfacilmente entendida por um ser humano para uma linguagem de máquina, específicapara um processador e sistema operacional. Atualmente, porém, são comunscompiladores que geram código para uma máquina virtual que é, depois, interpretadapor um interpretador.Em linguagens híbridas, o compilador tem o papel de converter o código fonte em umcódigo chamado de byte code, que é uma linguagem de baixo nível. Um exemplo destecomportamento é o do compilador da linguagem Java que, em vez de gerar código damáquina hospedeira (onde se está executando o compilador), gera código chamado JavaBytecode.[17]Um compilador é chamado de Just-in-time compiler (JIT) quando seu processo decompilação acontece apenas quando o código é chamado.[18] Um JIT pode fazerotimizações às instruções a medida que as compila.[18]Muitos compiladores incluem um pré-processador. Um pré-processador é um programaseparado, ativado pelo compilador antes do início do processo de tradução.[19]Normalmente é responsável por mudanças no código fonte destinadas de acordo comdecisões tomadas em tempo de compilação. Por exemplo, um programa em C permiteinstruções condicionais para o pré-processador que podem incluir ou não parte docódigo caso uma assertiva lógica seja verdadeira ou falsa, ou simplesmente um termoesteja definido ou não. Tecnicamente, pré-processadores são muito mais simples quecompiladores e são vistos, pelos desenvolvedores, como programas à parte, apesar dessavisão não ser necessariamente compartilhada pelo usuário.Outra parte separada do compilador que muitos usuários vêem como integrada é olinker, cuja função é unir vários programas já compilados de uma forma independente eunificá-los em um programa executável.[20] Isso inclui colocar o programa final em umformato compatível com as necessidades do sistema operacional para carregá-lo emmemória e colocá-lo em execução.Fases da compilaçãoAnálise léxica Ver artigo principal: Análise léxicaA análise léxica é a primeira fase do compilador.[21] A função do analisador léxico,também denominado scanner, é ler o código fonte, caracter a caracter, buscando aseparação e identificação dos elementos componentes do programa fonte, denominadossímbolos léxicos ou tokens.[22] É também de responsabilidade desta fase a eliminação deelementos "decorativos" do programa, tais como espaços em branco, marcas deformatação de texto e comentários.[23] Existem disponíveis uma série de geradoresautomáticos de analisadores léxicos, como por exemplo, o lex. O objetivo dos geradores
  5. 5. automáticos é limitar o esforço de programação de um analisador léxico especificando-se apenas os tokens a ser reconhecidos.[24]Análise sintática Ver artigo principal: Análise sintática (computação)A análise sintática, ou análise gramatical é o processo de se determinar se uma cadeia desímbolos léxicos pode ser gerada por uma gramática.[25] O analisador sintático é o cernedo compilador, responsável por verificar se os símbolos contidos no programa fonteformam um programa válido, ou não.[26] No caso de analisadores sintáticos top-down,temos a opção de escrevê-los à mão ou gerá-los de forma automática, mas osanalisadores bottom-up só podem ser gerados automaticamente.[27] A maioria dosmétodos de análise sintática, cai em uma dessas duas classes denominadas top-down ebottom-up.[28] Entre os métodos top-down os mais importantes são a análise sintáticadescendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos deanálise sintática bottom-up os mais importantes são a análise sintática de precedência deoperadores, análise sintática LR canônico, análise sintática LALR e análise sintáticaSLR.[25] Existem disponíveis uma série de geradores automáticos de analisadoressintáticos,[29] como por exemplo, o Yacc, o Bison e o JavaCC.Análise semântica Ver artigo principal: Análise semânticaAs análises léxica e sintática não estão preocupadas com o significado ou semântica dosprogramas que elas processam. O papel do analisador semântico é prover métodos pelosquais as estruturas construídas pelo analisador sintático possam ser avaliadas ouexecutadas.[30] As gramáticas livres de contexto não são suficientemente poderosas paradescrever uma série de construções das linguagens de programação, como por exemploregras de escopo, regras de visibilidade e consistência de tipos.[31] É papel do analisadorsemântico assegurar que todas as regras sensíveis ao contexto da linguagem estejamanalisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria doanalisador semântico é a checagem de tipos de variáveis em expressões.[32] Um dosmecanismos comumente utilizados por implementadores de compiladores é a Gramáticade Atributos, que consiste em uma gramática livre de contexto acrescentada de umconjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.[33]Geração de código intermediário
  6. 6. Exemplo de código de três endereços e um DAG correspondente para uma expressãoaritimética Ver artigo principal: Geração de códigoNa fase de geração de código intermediário, ocorre a transformação da árvore sintáticaem uma representação intermediária do código fonte. Esta linguagem intermediária émais próxima da linguagem objeto do que o código fonte, mas ainda permite umamanipulação mais fácil do que se código assembly ou código de máquina fosseutilizado.[34] Um tipo popular de linguagem intermediária é conhecido como código detrês endereços.[35] Neste tipo de código uma sentença típica tem a forma X := A op B,onde X, A e B são operandos e op uma operação qualquer. Uma forma prática derepresentar 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ódigointermediário é preferido por diversos compiladores, principalmente aqueles queexecutam extensivas otimizações de código, uma vez que o código intermediário podeser rearranjado de uma maneira conveniente com facilidade.[36]Outras representações decódigo intermediário comumente usadas são as triplas, (similares as quádruplas excetopelo fato de que os resultados não são nomeados explicitamente) as árvores, os grafosacíclicos dirigidos(DAG) e a notação polonesa.[37]Optimização de códigoA Otimização de código é a estratégia de examinar o código intermediário, produzidodurante a fase de geração de código com objetivo de produzir, através de algumastécnicas, um código que execute com bastante eficiência.[32] O nome optimizador devesempre ser encarado com cuidado, pois não se pode criar um programa que leia umprograma P e gere um programa P´ equivalente sendo melhor possível segundo ocritério adotado.[23] Várias técnicas e várias tarefas se reúnem sob o nome deOptimização. Estas técnicas consistem em detectar padrões dentro do código produzidoe substituí-los por códigos mais eficientes.[36] Entre as técnicas usadas estão asubstituição de expressões que podem ser avaliadas durante o tempo de compilaçãopelos seus valores calculados, eliminação de sub-expressões redundantes,desmembramento de laços, substituição de operações (multiplicação por shifts), entreoutras.[32] Uma das técnicas de optimização mais eficazes e independente de máquina éa otimização de laços, pois laços internos são bons candidatos para melhorias. Porexemplo, em caso de computações fixas dentro de laços, é possível mover estascomputações para fora dos mesmos reduzindo processamento.[38]Geração de código final Ver artigo principal: Geração de códigoA fase de geração de código final é a última fase da compilação. A geração de um bomcódigo objeto é difícil devido aos detalhes particulares das máquinas para os quais ocódigo é gerado. Contudo, é uma fase importante, pois uma boa geração de código podeser, por exemplo, duas vezes mais rápida que um algoritmo de geração de códigoineficiente.[36] Nem todas as técnicas de optimização são independentes da arquiteturada máquina-alvo. Optimizações dependentes da máquina necessitam de informações taiscomo os limites e os recursos especiais da máquina-alvo a fim de produzir um códigomais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos
  7. 7. recursos especiais de cada máquina-alvo.[32] Segundo Aho, o código objeto pode seruma sequência de instruções absolutas de máquina, uma sequência de instruções demáquina relocáveis, um programa em linguagem assembly ou um programa em outralinguagem.[39]Tratamento de errosTratamento de erro de execução em uma aplicação Java no EclipseO tratamento de erros está voltado a falhas devido a muitas causas: erros no compilador,erros na elaboração do programa a ser compilado, erros no ambiente (hardware, sistemaoperacional), dados incorretos, etc. As tarefas relacionadas ao tratamento de errosconsitem em detectar cada erro, reportá-lo ao usuário e possivelmente fazer algumreparo para que o processamento possa continuar.[40]Os erros podem ser classificados em erros léxicos, erros sintáticos, erros nãoindependentes de contexto (semânticos), erros de execução e erros de limite.[41] Os errosléxicos ocorrem quando um token identificado não pertence a gramática da linguagemfonte. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordocom a gramática, como por exemplo parênteses sem correspondência. Os erros nãoindependentes de contexto em geral são associados a não declaração de objetos comovariáveis e erros de tipos. Os erros de execução ocorrem após a compilação, quando oprograma já está sendo executado. Um exemplo típico é o da divisão por zero. Os errosde limite, ocorrem durante a execução e estão relacionados as características damáquina na qual o programa está sendo executado, como por exemplo, estouro depilha.[41]Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro errodo programa-fonte. Esta é uma política de fácil implementação. Compiladores maissofisticados, porém, detectam o maior número possível de erros visando diminuir onúmero de compilações.[42]A recuperação de erros em analisadores sintáticos top-down é mais fácil de implementardo que em analisadores bottom-up.[43] O problema é que diferente de um analisador top-down, este último não sabe quais símbolos são esperados na entrada, somente os que jáforam processados. Pode-se usar neste caso técnicas como, por exemplo, a técnica depanic-mode que procura em tabelas sintáticas em busca de símbolos válidos naentrada.[43] Nesta técnica se descartam símbolos da entrada até que um delimitador(como um ponto e vírgula, por exemplo) seja encontrado. O analisador apaga as
  8. 8. entradas da pilha até que encontre uma entrada que permita que o processo de análiseprossiga em diante.[44]Ver também

×