𝖂𝖎ƙ𝖎𝖊

Compilador: mudanças entre as edições

imported>Marquinhos
m (Desfeita(s) uma ou mais edições de 105.168.14.205, com Reversão e avisos.)
imported>Gremista.32
Sem resumo de edição
 
(45 revisões intermediárias por 28 usuários não estão sendo mostradas)
Linha 1: Linha 1:
{{Execução de Programa}}
{{Ver desambig|redir=Compilação|prefixo=Se procura|por compilação musical|Coletânea musical}}
{{Ver desambig|redir=Compilação|prefixo=Se procura|por compilação musical|Coletânea musical}}
[[Imagem:GCC-4.0.2-screenshot.png|thumb|300px|Uma captura de tela do compilador [[GNU Compiler Collection|GCC]] versão 4.0.2 rodando em uma janela [[xterm]]. Um programa simples está sendo compilado e então executado.]]
[[Imagem:GCC-4.0.2-screenshot.png|thumb|300px|Uma captura de tela do compilador [[GNU Compiler Collection|GCC]] versão 4.0.2 rodando em uma janela [[xterm]]. Um programa simples está sendo compilado e então executado.]]


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]].<ref>{{Citar livro|último=[[Alfred Aho|Aho]]|primeiro=Alfred V.|coautor=Ullman, Jeffrey D.|título=Principles of Compiler Design|subtítulo=|língua3=en|edição=|local=Reading, Massachusetts, EUA|editora=Addison-Wesley|ano=1977|páginas=604|página=1|volumes=|volume=|isbn= 0-201-00022-9}}</ref> Classicamente, um compilador traduz um programa de uma linguagem textual
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]].<ref>{{Citar livro|último=[[Alfred Aho|Aho]]|primeiro=Alfred V.|coautor=Ullman, Jeffrey D.|título=Principles of Compiler Design|língua=en|local=Reading, Massachusetts, EUA|editora=Addison-Wesley|ano=1977|páginas=604|página=1|isbn= 0-201-00022-9}}</ref> Classicamente, um compilador traduz um programa de uma linguagem textual
<nowiki> </nowiki>facilmente entendida por um ser humano para uma linguagem de máquina,  
facilmente entendida por um ser humano para uma [[linguagem de máquina]] ,
específica para um processador e sistema operacional. Atualmente, porém,
específica para um processador e sistema operacional. Atualmente, porém,
<nowiki> </nowiki>são comuns compiladores que geram código para uma máquina virtual que  
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 juntas, ou compilava,<ref group=Nota>Em [[Língua portuguesa|português]], "''compilar''" significa, por exemplo: reunir obras literárias, documentos, escritos de vários autores, entre outros, compondo uma obra com esse material. {{Citar livro|Autor = Larousse|título= Dicionário da Língua Portuguesa|língua3=en|Editora = Nova Cultural|Ano = 1992|isbn= 85-85222-23-9}}</ref> as subrotinas necessárias para executar uma determinada tarefa.<ref>{{Citar livro|último=Parsons|primeiro=Thomas W.|título=Introduction to Compiler Construction|subtítulo=|língua3=en|edição=|local=Nova Iorque, EUA|editora=Computer Science Press|ano=1992|páginas=359|página=1|volumes=|volume=|isbn= 0-7167-8261-8}}</ref><ref>{{Citar livro|último= Appel|primeiro=Andrew W.|título=Modern Compiler Implementation in Java|url=http://www.cs.princeton.edu/~appel/modern/java/|local=Cambridge|Editora = Cambridge University Press|Ano = 1998|língua3=en|páginas=548|página=3|isbn= 0-521-58388-8}}</ref>
é, 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,<ref group=Nota>Em [[Língua portuguesa|português]], "''compilar''" significa, por exemplo: reunir obras literárias, documentos, escritos de vários autores, entre outros, compondo uma obra com esse material. {{Citar livro|autor= Larousse|título= Dicionário da Língua Portuguesa|língua=en|editora= Nova Cultural|ano= 1992|isbn= 85-85222-23-9}}</ref> as subrotinas necessárias para executar uma determinada tarefa.<ref>{{Citar livro|último=Parsons|primeiro=Thomas W.|título=Introduction to Compiler Construction|língua=en|local=Nova Iorque, EUA|editora=Computer Science Press|ano=1992|páginas=359|página=1|isbn= 0-7167-8261-8}}</ref><ref>{{Citar livro|último= Appel|primeiro=Andrew W.|título=Modern Compiler Implementation in Java|url=http://www.cs.princeton.edu/~appel/modern/java/|local=Cambridge|editora= Cambridge University Press|ano= 1998|língua=en|páginas=548|página=3|isbn= 0-521-58388-8}}</ref>


O nome "compilador" é usado principalmente para os programas que [[Tradutor#Computação|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 (linguagem de programação)|C]].<ref>{{Citar livro|último= Cooper|primeiro=Torczon|título= Engineering a Compiler|local=San Francisco|Editora = Morgan Kaufmann|Ano = 2003|língua3=en|página=2|isbn= 1-55860-698-X}}</ref> Para alguns autores um programa que faz uma tradução entre linguagens de alto nível é normalmente chamado um tradutor, filtro<ref name="joaojose">{{Citar livro|último=Neto|primeiro=João José|título=Introdução à Compilação|subtítulo=|língua3=pt|edição=|local=Rio de Janeiro|editora=LTC|ano=1987|páginas=222|volumes=|volume=|isbn=978-85-216-0483-9}}</ref> 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|descompilador]].<ref name=watt> {{Citar livro|último=Watt|primeiro=David A.; Brown, Deryck F.|título=Programming Language Processors in Java|subtítulo=|língua3=en|edição=|local=Harlow, England|editora=Prentice Hall|ano=2000|páginas=436|página=27|volumes=|volume=|isbn= 0-130-25786-9}}</ref> Um programa que faz uma tradução entre uma linguagem de montagem e o código de máquina é denominado [[montador]] (''assembler'').<ref name="joaojose"/> Um programa que faz uma tradução entre o código de máquina e uma linguagem de montagem é denominado [[desmontador]] (''disassembler'').<ref name=watt /> 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]].<ref>{{Citar livro|último=Elder|primeiro=John|título=Compiler Conctruction|subtítulo=A Recursive Descent Model|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1994|páginas=437|página=7-8|volumes=|volume=1|isbn= 0-13-291139-6}}</ref>
O nome "compilador" é usado principalmente para os programas que [[Tradutor#Computação|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 (linguagem de programação)|C]].<ref>{{Citar livro|último= Cooper|primeiro=Torczon|título= Engineering a Compiler|local=San Francisco|editora= Morgan Kaufmann|ano= 2003|língua=en|página=2|isbn= 1-55860-698-X}}</ref> Para alguns autores um programa que faz uma tradução entre linguagens de alto nível é normalmente chamado um tradutor, filtro<ref name="joaojose">{{Citar livro|último=Neto|primeiro=João José|título=Introdução à Compilação|local=Rio de Janeiro|editora=LTC|ano=1987|páginas=222|isbn=978-85-216-0483-9}}</ref> 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]].<ref name=watt>{{Citar livro|último=Watt|primeiro=David A.; Brown, Deryck F.|título=Programming Language Processors in Java|língua=en|local=Harlow, England|editora=Prentice Hall|ano=2000|páginas=436|página=27|isbn= 0-130-25786-9}}</ref> Um programa que faz uma tradução entre uma linguagem de montagem e o código de máquina é denominado [[montador]] (''assembler'').<ref name="joaojose"/> Um programa que faz uma tradução entre o código de máquina e uma linguagem de montagem é denominado [[desmontador]] (''disassembler'').<ref name=watt /> 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]].<ref>{{Citar livro|último=Elder|primeiro=John|título=Compiler Conctruction|subtítulo=A Recursive Descent Model|língua=en|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1994|páginas=437|página=7-8|volume=1|isbn= 0-13-291139-6}}</ref>


== História ==
== História ==
Linha 15: Linha 17:
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 [[CPU]]s 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.
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 [[CPU]]s 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.


No final da década de 1950, as linguagens de programação independentes de máquina foram propostas. Posteriormente, vários compiladores experimentais foram desenvolvidos. O primeiro compilador foi escrito por [[Grace Hopper]],<ref>{{Citar livro|último=Lemone|primeiro=Karen A.|título=Fundamentals of Compilers|subtítulo=An Introduction to Computer Language Translation|língua3=en|edição=|local=Boca Raton|editora=CRC|ano=1992|páginas=184|volumes=|volume=|isbn= 0-8493-7341-7}}</ref> em 1952, para a linguagem de programação [[Sistema A-0|A-0]].<ref name=wexel>{{Citar livro|autor=Wexelblat, Richard L.(Editor)|título=History of Programming Languages|subtítulo=|idioma=|edição=|local=New York|editora=Academic Press|ano=1981|páginas=758|página=6-15|volumes=|volume=|isbn= 0-12-745040-8}}</ref> Antes de 1957, foram desenvolvidos esforços e várias contribuições ao desenvolvimento de linguagens de alto nível foram feitas. Entre estes, o desenvolvimento da [[Short Code]] ([[UNIVAC]]), [[Speedcoding]] no [[IBM 701]],<ref name="ibm">{{Referência a livro|autor=Bashe, Charles J.; Johnson, Lyle R.; Palmer, John H.; Pugh, Emerson W.|título=IBM´s Early Computers|subtítulo=|idioma=|edição=|local=Cambridge|editora=MIT Press|ano=1986|páginas=716|página=333|volumes=|volume=|isbn= 0-262-02225-7}}</ref><ref name="ieee">{{citar jornal | ultimo = McClelland| primeiro = William F | coautores = | ano = 1983| mes = abril| titulo = Programming | jornal = Annals of The History of Computing | volume = 5 | numero = 2 | paginas = 135-139 | editora = American Federation of Information Processing Societies | local = Arlington, VA | issn = 1058-6180 | idioma = ingles }}</ref> o Whirlwind, o BACAIC e o PRINT.<ref>{{Citar livro|autor=Sammet, Jean E|título=Programming Languages: History and Fundamentals|subtítulo=|idioma=|edição=|local=Englewood Cliffs, New Jersey|editora=Prentice Hall|ano=1969|páginas=785|página=5|volumes=|volume=|isbn= 0-13-729988-5}}</ref> A equipe de desenvolvimento do [[FORTRAN]] liderada por [[John Backus]] na [[IBM]] é geralmente creditada como tendo introduzido o primeiro compilador completo em 1957 (embora tenha ocorrido simultaneamente o desenvolvimento do ''algebraic translator'' de Laning e Zierler<ref name=wexel />). O [[COBOL]] é um exemplo de uma linguagem da primeira geração que compilava em múltiplas arquiteturas, em 1960.<ref>{{citar web |url=http://www.interesting-people.org/archives/interesting-people/199706/msg00011.html |título=IP: Os primeiros compiladores COBOL do mundo |data=12 de Junho de 1997 |publicado=interesting-people.org}}</ref>
No final da década de 1950, as linguagens de programação independentes de máquina foram propostas. Posteriormente, vários compiladores experimentais foram desenvolvidos. O primeiro compilador foi escrito por [[Grace Hopper]],<ref>{{Citar livro|último=Lemone|primeiro=Karen A.|título=Fundamentals of Compilers|subtítulo=An Introduction to Computer Language Translation|língua=en|local=Boca Raton|editora=CRC|ano=1992|páginas=184|isbn= 0-8493-7341-7}}</ref> em 1952, para a linguagem de programação [[Sistema A-0|A-0]].<ref name=wexel>{{Citar livro|autor=Wexelblat, Richard L.(Editor)|título=History of Programming Languages|local=New York|editora=Academic Press|ano=1981|páginas=758|página=6-15|isbn= 0-12-745040-8}}</ref> Antes de 1957, foram desenvolvidos esforços e várias contribuições ao desenvolvimento de linguagens de alto nível foram feitas. Entre estes, o desenvolvimento da [[Short Code]] ([[UNIVAC]]), [[Speedcoding]] no [[IBM 701]],<ref name="ibm">{{citar livro|autor=Bashe, Charles J.; Johnson, Lyle R.; Palmer, John H.; Pugh, Emerson W.|título=IBM´s Early Computers|local=Cambridge|editora=MIT Press|ano=1986|páginas=716|página=333|isbn= 0-262-02225-7}}</ref><ref name="ieee">{{citar jornal | ultimo = McClelland| primeiro = William F | data = abril 1983| titulo = Programming | jornal = Annals of The History of Computing | volume = 5 | numero = 2 | paginas = 135-139 | editora = American Federation of Information Processing Societies | local = Arlington, VA | issn = 1058-6180 | idioma = en}}</ref> o Whirlwind, o BACAIC e o PRINT.<ref>{{Citar livro|autor=Sammet, Jean E|título=Programming Languages: History and Fundamentals|local=Englewood Cliffs, New Jersey|editora=Prentice Hall|ano=1969|páginas=785|página=5|isbn= 0-13-729988-5}}</ref> A equipe de desenvolvimento do [[FORTRAN]] liderada por [[John Backus]] na [[IBM]] é geralmente creditada como tendo introduzido o primeiro compilador completo em 1957 (embora tenha ocorrido simultaneamente o desenvolvimento do ''algebraic translator'' de Laning e Zierler<ref name=wexel />). O [[COBOL]] é um exemplo de uma linguagem da primeira geração que compilava em múltiplas arquiteturas, em 1960.<ref>{{citar web |url=http://www.interesting-people.org/archives/interesting-people/199706/msg00011.html |título=IP: Os primeiros compiladores COBOL do mundo |data=12 de Junho de 1997 |publicado=interesting-people.org |acessodata=2011-12-21 |arquivourl=https://web.archive.org/web/20120220002430/http://www.interesting-people.org/archives/interesting-people/199706/msg00011.html |arquivodata=2012-02-20 |urlmorta=yes }}</ref>


Em muitos domínios de aplicação a idéia de usar uma linguagem de alto nível rapidamente ganhou força. Por causa da funcionalidade de expansão apoiada por [[linguagem de programação|linguagens de programação]] recentes e a complexidade crescente de arquiteturas de computadores, os compiladores tornaram-se mais e mais complexos.
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 [[linguagem de programação|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 [[Massachusetts Institute of Technology|MIT]] em 1962.<ref>{{citar web |url=ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-039.pdf |autor=T. Hart and M. Levin |título=O novo compilador, AIM-39 - CSAIL Digital Archive - Artificial Intelligence Laboratory Series |publicado=publications.ai.mit.edu}}</ref>
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 [[Massachusetts Institute of Technology|MIT]] em 1962.<ref>{{citar web |url=ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-039.pdf |autor=T. Hart and M. Levin |título=O novo compilador, AIM-39 - CSAIL Digital Archive - Artificial Intelligence Laboratory Series |publicado=publications.ai.mit.edu}}{{Ligação inativa|1={{subst:DATA}} }}</ref>


== Características ==
== Características ==
[[Imagem:Nt-compilador.png|thumb|esquerda|120px|O processo da compilação.]]
[[Imagem:Nt-compilador.png|thumb|esquerda|120px|O processo da compilaçã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,<ref>{{Citar livro|último=Mak|primeiro=Ronald|título=Writing Compilers and Interpreters|subtítulo=An Applied Approach Using C++|língua3=en|edição=|local=Nova Iorque|editora=John Wiley and Sons|ano=1996|páginas=838|página=1|volumes=|volume=|isbn= 0-471-11353-0}}</ref> como uma sequência de instruções a ser executada pelo [[microprocessador]].
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,<ref>{{Citar livro|último=Mak|primeiro=Ronald|título=Writing Compilers and Interpreters|subtítulo=An Applied Approach Using C++|língua=en|local=Nova Iorque|editora=John Wiley and Sons|ano=1996|páginas=838|página=1|isbn= 0-471-11353-0}}</ref> como uma sequência de instruções a ser executada pelo [[microprocessador]].


O processo de compilação é composto de análise e síntese.<ref name=holmes>{{Citar livro|último=Holmes|primeiro=Jim|título=Object-Oriented Compiler Construction|subtítulo=|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey|editora=Prentice Hall|ano=1995|páginas=483|página=2-3|volumes=|volume=|isbn= 0-13-630740-X}}</ref> 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.
O processo de compilação é composto de análise e síntese.<ref name=holmes>{{Citar livro|último=Holmes|primeiro=Jim|título=Object-Oriented Compiler Construction|língua=en|local=Englewood Cliffs, Nova Jersey|editora=Prentice Hall|ano=1995|páginas=483|página=2-3|isbn= 0-13-630740-X}}</ref> 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 (computação)|análise sintática]], [[análise semântica]] e [[geração de código]] intermediário. É também conhecida como ''front end''.<ref name=holmes /> 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''.<ref name=holmes />
A análise pode ser subdividida ainda em [[análise léxica]], [[Análise sintática (computação)|análise sintática]], [[análise semântica]] e [[geração de código]] intermediário. É também conhecida como ''front end''.<ref name=holmes /> 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''.<ref name=holmes />


Em [[Linguagem de programação|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 (linguagem de programação)|Java]] que, em vez de gerar código da máquina hospedeira (onde se está executando o compilador), gera código chamado ''Java [[Bytecode]]''.<ref>{{Citar livro|último=Sebesta|primeiro=Robert|título=Conceitos de Linguagens de Programação|subtítulo=|língua3=pt|edição=9ª|local=Porto Alegre|editora=Bookman|ano=2010|páginas=792|página=49-50|volumes=|volume=|isbn= 978-85-7780-791-8}}</ref>
Em [[Linguagem de programação|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 (linguagem de programação)|Java]] que, em vez de gerar código da máquina hospedeira (onde se está executando o compilador), gera código chamado ''Java [[Bytecode]]''.<ref>{{Citar livro|último=Sebesta|primeiro=Robert|título=Conceitos de Linguagens de Programação|edição=9ª|local=Porto Alegre|editora=Bookman|ano=2010|páginas=792|página=49-50|isbn= 978-85-7780-791-8}}</ref>


Um compilador é chamado de ''[[JIT|Just-in-time compiler]]'' (JIT) quando seu processo de compilação acontece apenas quando o código é chamado.<ref name=jit>{{Citar livro|último=Engel|primeiro=Joshua|título=Programming for the Java Virtual Machine|subtítulo=|língua3=en|edição=|local=Reading, Massachusetts|editora=Addison & Wesley|ano=1999|páginas=488|página=355|volumes=|volume=|isbn=0-201-30972-6}}</ref> Um JIT pode fazer otimizações às instruções a medida que as compila.<ref name=jit />
Um compilador é chamado de ''[[JIT|Just-in-time compiler]]'' (JIT) quando seu processo de compilação acontece apenas quando o código é chamado.<ref name=jit>{{Citar livro|último=Engel|primeiro=Joshua|título=Programming for the Java Virtual Machine|língua=en|local=Reading, Massachusetts|editora=Addison & Wesley|ano=1999|páginas=488|página=355|isbn=0-201-30972-6}}</ref> Um JIT pode fazer otimizações às instruções a medida que as compila.<ref name=jit />


Muitos compiladores incluem um [[pré-processador]]. Um pré-processador é um programa separado, ativado pelo compilador antes do início do processo de tradução.<ref>{{Citar livro|último=Louden|primeiro=Kenneth C.|título=Compiladores|subtítulo=Princípios e Práticas|língua3=pt|edição=|local=São Paulo|editora=Pioneira Thompson Learning|ano=2004|páginas=569|página=5|volumes=|volume=|isbn= 85-221-0422-0}}</ref> 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 (linguagem de programação)|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.
Muitos compiladores incluem um [[pré-processador]]. Que é um programa separado, ativado pelo compilador antes do início do processo de tradução.<ref>{{Citar livro|último=Louden|primeiro=Kenneth C.|título=Compiladores|subtítulo=Princípios e Práticas|local=São Paulo|editora=Pioneira Thompson Learning|ano=2004|páginas=569|página=5|isbn= 85-221-0422-0}}</ref> 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 (linguagem de programação)|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.<ref>{{Citar livro|último=Levine|primeiro=John R.|título=Linkers & Loaders|subtítulo=|língua3=en|edição=|local=San Francisco|editora=Morgan Kaufmann Publishers|ano=2000|páginas=256|página=1-3|volumes=|volume=|isbn= 1-55860-496-0}}</ref> 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.
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.<ref>{{Citar livro|último=Levine|primeiro=John R.|título=Linkers & Loaders|língua=en|local=San Francisco|editora=Morgan Kaufmann Publishers|ano=2000|páginas=256|página=1-3|isbn= 1-55860-496-0}}</ref> 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.


== Fases da compilação ==
== Fases da compilação ==
Linha 41: Linha 43:
{{Artigo principal|Análise léxica}}
{{Artigo principal|Análise léxica}}


A análise léxica é a primeira fase do compilador.<ref name=ahoparsing>{{Citar livro|último=[[Alfred Aho|Aho]]|primeiro=Alfred V.|coautor=Ullman, Jeffrey D.|título=The Theory of Parsing, Translation, and Compiling, Vol. 1, Parsing|subtítulo=|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1972|páginas=542|página=59|volumes=2|volume=1|isbn=0-13-914556-7}}</ref> A função do analisador léxico, também denominado ''scanner'', é ler o código fonte, caracter a caracter, buscando a separação e identificação dos elementos componentes do programa fonte, denominados símbolos léxicos ou ''tokens''.<ref name="anaprice">{{Citar livro|autor=Price, Ana M. A.; Toscano, Simão Sirineo|título=Implementação de Linguagens de Programação: Compiladores|subtítulo=Série de Livros Didáticos Número 9|língua3=pt|edição=|local=Porto Alegre|editora=Sagra Luzzatto|ano=2000|páginas=195|volumes=|volume=|isbn= 978-85-241-0639-2}}</ref> É também de responsabilidade desta fase a eliminação de elementos "decorativos" do programa, tais como espaços em branco, marcas de formatação de texto e comentários.<ref name="rangel">{{citar web|url=http://www-di.inf.puc-rio.br/~rangel/comp.html|titulo=Compiladores - Página de José Lucas Mourão Rangel Netto|publicado=PUC-Rio|língua3=pt|acessodata=21 de junho de 2009}}</ref> Existem disponíveis uma série de geradores automáticos de analisadores léxicos, como por exemplo, o [[lex]]. O objetivo dos geradores automáticos é limitar o esforço de programação de um analisador léxico especificando-se apenas os [[Token|''tokens'']] a ser reconhecidos.<ref>{{Citar livro|último=Fischer|primeiro=Charles N.; LeBlanc, Jr, Richard J.|título=Crafting a Compiler with C|subtítulo=|língua3=en|edição=|local=Redwood City, California|editora=Benjamin Cummings Publishing|ano=1991|páginas=812|página=50|volumes=|volume=|isbn=0-8053-2166-7}}</ref>
A análise léxica é a primeira fase do compilador.<ref name=ahoparsing>{{Citar livro|último=[[Alfred Aho|Aho]]|primeiro=Alfred V.|coautor=Ullman, Jeffrey D.|título=The Theory of Parsing, Translation, and Compiling, Vol. 1, Parsing|língua=en|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1972|páginas=542|página=59|volume=1|isbn=0-13-914556-7}}</ref> A função do analisador léxico, também denominado ''scanner'', é ler o código-fonte, caractere a caractere, buscando a separação e identificação dos elementos componentes do programa-fonte, denominados símbolos léxicos ou ''tokens''.<ref name="anaprice">{{Citar livro|autor=Price, Ana M. A.; Toscano, Simão Sirineo|título=Implementação de Linguagens de Programação: Compiladores|subtítulo=Série de Livros Didáticos Número 9|local=Porto Alegre|editora=Sagra Luzzatto|ano=2000|páginas=195|isbn= 978-85-241-0639-2}}</ref> É também de responsabilidade desta fase a eliminação de elementos "decorativos" do programa, tais como espaços em branco, marcas de formatação de texto e comentários.<ref name="rangel">{{citar web|url=http://www-di.inf.puc-rio.br/~rangel/comp.html|titulo=Compiladores - Página de José Lucas Mourão Rangel Netto|publicado=PUC-Rio|acessodata=21 de junho de 2009|arquivourl=https://web.archive.org/web/20090412162502/http://www-di.inf.puc-rio.br/~rangel/comp.html|arquivodata=2009-04-12|urlmorta=yes}}</ref> Existem disponíveis uma série de geradores automáticos de analisadores léxicos, como por exemplo, o [[lex]]. O objetivo dos geradores automáticos é limitar o esforço de programação de um analisador léxico especificando-se apenas os ''[[token]]s'' a ser reconhecidos.<ref>{{Citar livro|último=Fischer|primeiro=Charles N.; LeBlanc, Jr, Richard J.|título=Crafting a Compiler with C|língua=en|local=Redwood City, California|editora=Benjamin Cummings Publishing|ano=1991|páginas=812|página=50|isbn=0-8053-2166-7}}</ref>


=== Análise sintática ===
=== Análise sintática ===
{{Artigo principal|Análise sintática (computação)}}
{{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 de símbolos léxicos pode ser gerada por uma [[Gramática formal|gramática]].<ref name="aho">{{Citar livro|Autor = Aho, Alfred V.; Sethi, Ravi; Ullman, Jeffrey D.|título= [[:en:Compilers: Principles, Techniques, and Tools|Compilers: Principles, Techniques and Tools]]|local=Reading, Massachusetts, EUA|Editora = Addison-Wesley|Ano = 1986|língua3=en|páginas=796|isbn=978-0-201-10088-4}}</ref> O analisador sintático é o cerne do compilador, responsável por verificar se os símbolos contidos no programa fonte formam um programa válido, ou não.<ref name=delamaro>{{Citar livro|último= Delamaro|primeiro=Marcio|url=http://www.novateceditora.com.br/livros/compilador/|título= Como Construir um Compilador Utilizando Ferramentas Java|língua3=pt|local=São Paulo|Editora = Novatec|Ano = 2004|página=4|páginas=308|isbn= 85-7522-055-1}}</ref> 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 os analisadores ''bottom-up'' só podem ser gerados automaticamente.<ref name="grune">{{Citar livro|último= Grune|primeiro=Dick|coautor=Bal, Henri E.; Jacobs, Ceriel J. H.; Langendoen, Koen G|título=Projeto Moderno de Compiladores|local=Rio de Janeiro|Editora = Campus|Ano=2001|língua3=pt|isbn=978-85-352-0876-4}}</ref> A maioria dos métodos de análise sintática, cai em uma dessas duas classes denominadas ''top-down'' e ''bottom-up''.<ref name="lewis">{{Citar livro|último= Lewis II |primeiro=P. M.|coautor=Rosenkrantz, D,J.; Stearns, R.E.|título=Compiler Design Theory|local=Reading, Massachusetts|Editora = Addison-Wesley|Ano=1978|página=227|páginas=647|língua3=en|isbn=0-201-14455-7}}</ref> Entre os métodos ''top-down'' os mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos de análise sintática ''bottom-up'' os mais importantes são a análise sintática de precedência de operadores, análise sintática LR canônico, análise sintática LALR e análise sintática SLR.<ref name="aho"/> Existem disponíveis uma série de geradores automáticos de analisadores sintáticos,<ref>{{Citar livro|último=Alblas|primeiro=Henk; Nymeyer, Albert|título=Practice and Principles of Compiler Building with C|subtítulo=|língua3=en|edição=|local=London|editora=Prentice Hall|ano=1996|páginas=427|página=30|volumes=|volume=|isbn= 0-13-349267-2}}</ref> como por exemplo, o [[Yacc]], o [[Bison]] e o [[JavaCC]].
A análise sintática, ou análise gramatical é o processo de se determinar se uma cadeia de símbolos léxicos pode ser gerada por uma [[Gramática formal|gramática]].<ref name="aho">{{Citar livro|autor= Aho, Alfred V.; Sethi, Ravi; Ullman, Jeffrey D.|título= [[:en:Compilers: Principles, Techniques, and Tools|Compilers: Principles, Techniques and Tools]]|local=Reading, Massachusetts, EUA|editora= Addison-Wesley|ano= 1986|língua=en|páginas=796|isbn=978-0-201-10088-4}}</ref> O analisador sintático é o cerne do compilador, responsável por verificar se os símbolos contidos no programa fonte formam um programa válido, ou não.<ref name=delamaro>{{Citar livro|último= Delamaro|primeiro=Marcio|url=http://www.novateceditora.com.br/livros/compilador/|título= Como Construir um Compilador Utilizando Ferramentas Java|local=São Paulo|editora= Novatec|ano= 2004|página=4|total-páginas=308|isbn= 85-7522-055-1}}</ref> 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 os analisadores ''bottom-up'' só podem ser gerados automaticamente.<ref name="grune">{{Citar livro|último= Grune|primeiro=Dick|coautor=Bal, Henri E.; Jacobs, Ceriel J. H.; Langendoen, Koen G|título=Projeto Moderno de Compiladores|local=Rio de Janeiro|editora= Campus|ano=2001|isbn=978-85-352-0876-4}}</ref> A maioria dos métodos de análise sintática, cai em uma dessas duas classes denominadas ''top-down'' e ''bottom-up''.<ref name="lewis">{{Citar livro|último= Lewis II |primeiro=P. M.|coautor=Rosenkrantz, D,J.; Stearns, R.E.|título=Compiler Design Theory|local=Reading, Massachusetts|editora= Addison-Wesley|ano=1978|página=227|total-páginas=647|língua=en|isbn=0-201-14455-7}}</ref> Entre os métodos ''top-down'' os mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos de análise sintática ''bottom-up'' os mais importantes são a análise sintática de precedência de operadores, análise sintática LR canônico, análise sintática LALR e análise sintática SLR.<ref name="aho"/> Existem disponíveis uma série de geradores automáticos de analisadores sintáticos,<ref>{{Citar livro|último=Alblas|primeiro=Henk; Nymeyer, Albert|título=Practice and Principles of Compiler Building with C|língua=en|local=London|editora=Prentice Hall|ano=1996|páginas=427|página=30|isbn= 0-13-349267-2}}</ref> como por exemplo, o [[Yacc]], o [[Bison]] e o [[JavaCC]].


=== Análise semântica ===
=== Análise semântica ===
{{Artigo principal|Análise semântica}}
{{Artigo principal|Análise semântica}}


As análises léxica e sintática não estão preocupadas com o significado ou semântica dos programas que elas processam. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas.<ref name="watson">{{Citar livro|último=Watson|primeiro=Des|título=High-Level Languages and Their Compilers|subtítulo=|língua3=en|edição=|local=Wokingham, Reino Unido|editora=Addison-Wesley|ano=1989|páginas=337|volumes=|volume=|isbn= 0-201-18489-3}}</ref> As gramáticas livres de contexto não são suficientemente poderosas para descrever uma série de construções das linguagens de programação, como por exemplo regras de escopo, regras de visibilidade e consistência de tipos.<ref name="wilhelm">{{Citar livro|autor=Wilhelm, Reinhard; Maurer, Dieter|título=Compiler Design|subtítulo=|língua3=en|edição=|local=Harlow, England|editora=Addison-Wesley|ano=1995|páginas=606|volumes=|volume=|isbn= 0-201-42290-5}}</ref> É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões.<ref name="tremblay">{{Citar livro|autor=Tremblay, Jean-Paul; Sorenson, Paul G.|título=The Theory and Practice of Compiler Writing|subtítulo=|língua3=en|edição=|local=Nova Iorque|editora=McGraw-Hill|ano=1989|páginas=796|volumes=|volume=|isbn= 0-07-065161-2}}</ref> Um dos mecanismos comumente utilizados por implementadores de compiladores é a [[Gramática de Atributos]], que consiste em uma [[Gramática formal|gramática]] livre de contexto acrescentada de um conjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.<ref name="pittman">{{Citar livro|autor=Pittman, Thomas; Peters, James|título=The Art of Compiler Design|subtítulo=Theory and Practice|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1992|páginas=419|volumes=|volume=|isbn= 0-13-048190-4}}</ref>
As análises léxica e sintática não estão preocupadas com o significado ou semântica dos programas que elas processam. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas.<ref name="watson">{{Citar livro|último=Watson|primeiro=Des|título=High-Level Languages and Their Compilers|língua=en|local=Wokingham, Reino Unido|editora=Addison-Wesley|ano=1989|páginas=337|isbn= 0-201-18489-3}}</ref> As gramáticas livres de contexto não são suficientemente poderosas para descrever uma série de construções das linguagens de programação, como por exemplo regras de escopo, regras de visibilidade e consistência de tipos.<ref name="wilhelm">{{Citar livro|autor=Wilhelm, Reinhard; Maurer, Dieter|título=Compiler Design|língua=en|local=Harlow, England|editora=Addison-Wesley|ano=1995|páginas=606|isbn= 0-201-42290-5}}</ref> É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões.<ref name="tremblay">{{Citar livro|autor=Tremblay, Jean-Paul; Sorenson, Paul G.|título=The Theory and Practice of Compiler Writing|língua=en|local=Nova Iorque|editora=McGraw-Hill|ano=1989|páginas=796|isbn= 0-07-065161-2}}</ref> Um dos mecanismos comumente utilizados por implementadores de compiladores é a [[Gramática de Atributos]], que consiste em uma [[Gramática formal|gramática]] livre de contexto acrescentada de um conjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.<ref name="pittman">{{Citar livro|autor=Pittman, Thomas; Peters, James|título=The Art of Compiler Design|subtítulo=Theory and Practice|língua=en|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1992|páginas=419|isbn= 0-13-048190-4}}</ref>


=== Geração de código intermediário ===
=== Geração de código intermediário ===
Linha 57: Linha 59:
{{Artigo principal|Geração de código}}
{{Artigo principal|Geração de código}}


Na fase de geração de código intermediário, ocorre a transformação da árvore sintática em 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 uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado.<ref>{{Citar livro|último=Pyster|primeiro=Arthur B.|título=Compiler Design and Construction|subtítulo=Tools and Techniques|língua3=en|edição=|local=Nova Iorque, EUA|editora=Van Nostrand Reinhold Company|ano=1988|páginas=267|página=8|volumes=|volume=|isbn= 0-442-27536-6}}</ref> Um tipo popular de linguagem intermediária é conhecido como [[código de três endereços]].<ref>{{Citar livro|último= Crespo|primeiro=Rui Gustavo|título= Processadores de Linguagens|subtítulo=da Concepção à Implementação|local=Lisboa, Portugal|Editora = IST Press|Ano = 1998|língua3=pt|páginas=435|página=247|isbn= 972-8469-01-2}}</ref> Neste tipo de código uma sentença típica tem a forma <code>X := A op B</code>, onde ''X'', ''A'' e ''B'' são 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.<ref name="aho pcd">{{Citar livro|autor=Aho, Alfred V.; Ullman, Jeffrey D.|título=Principles of Compiler Design|subtítulo=|língua3=en|edição=|local=Reading, Massachusetts, EUA|editora=Addison-Wesley|ano=1977|páginas=604|volumes=|volume=|isbn= 0-201-00022-9}}</ref>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]].<ref>{{Citar livro|último=Muchnick|primeiro=Steven S.|título=Advanced Compiler Design Implementation|subtítulo=|língua3=en|edição=|local=San Francisco, California|editora=Morgan Kaufmann Publishers|ano=1997|páginas=856|página=96|volumes=|volume=|isbn= 1-55860-320-4}}</ref>
Na fase de geração de código intermediário, ocorre a transformação da árvore sintática em 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 uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado.<ref>{{Citar livro|último=Pyster|primeiro=Arthur B.|título=Compiler Design and Construction|subtítulo=Tools and Techniques|língua=en|local=Nova Iorque, EUA|editora=Van Nostrand Reinhold Company|ano=1988|páginas=267|página=8|isbn= 0-442-27536-6}}</ref> Um tipo popular de linguagem intermediária é conhecido como [[código de três endereços]].<ref>{{Citar livro|último= Crespo|primeiro=Rui Gustavo|título= Processadores de Linguagens|subtítulo=da Concepção à Implementação|local=Lisboa, Portugal|editora= IST Press|ano= 1998|páginas=435|página=247|isbn= 972-8469-01-2}}</ref> Neste tipo de código uma sentença típica tem a forma <code>X := A op B</code>, onde ''X'', ''A'' e ''B'' são 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.<ref name="aho pcd">{{Citar livro|autor=Aho, Alfred V.; Ullman, Jeffrey D.|título=Principles of Compiler Design|língua=en|local=Reading, Massachusetts, EUA|editora=Addison-Wesley|ano=1977|páginas=604|isbn= 0-201-00022-9}}</ref> 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]].<ref>{{Citar livro|último=Muchnick|primeiro=Steven S.|título=Advanced Compiler Design Implementation|língua=en|local=San Francisco, California|editora=Morgan Kaufmann Publishers|ano=1997|páginas=856|página=96|isbn= 1-55860-320-4}}</ref>


=== Optimização de código ===
=== Otimização de código ===
<!--{{Artigo principal|Optimização de código}}-->
<!--{{Artigo principal|Optimização de código}}-->


A Otimização de código é a estratégia de examinar o código intermediário, produzido durante a fase de geração de código com objetivo de produzir, através de algumas técnicas, um código que execute com bastante eficiência.<ref name="tremblay"/> O nome optimizador deve sempre ser encarado com cuidado, pois não se pode criar um programa que leia um programa P e gere um programa P´ equivalente sendo melhor possível segundo o critério adotado.<ref name="rangel"/> Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes.<ref name="aho pcd"/> Entre as técnicas usadas estão a substituição de expressões que podem ser avaliadas durante o tempo de compilação pelos seus valores calculados, eliminação de sub-expressões redundantes, desmembramento de laços, substituição de operações (multiplicação por ''shifts''), entre outras.<ref name="tremblay"/> 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. Por exemplo, em caso de computações fixas dentro de laços, é possível mover estas computações para fora dos mesmos reduzindo processamento.<ref>{{Citar livro|último=Kakde|primeiro=O. G.|título=Algorithms for Compiler Design|subtítulo=|língua3=en|edição=|local=Hingham|editora=Charles River media|ano=2003|páginas=334|volumes=|volume=|isbn= 81-7008-100-6}}</ref>
A otimização de código é a estratégia de examinar o código intermediário, produzido durante a fase de geração de código com objetivo de produzir, através de algumas técnicas, um código que execute com bastante eficiência.<ref name="tremblay"/> O nome optimizador deve sempre ser encarado com cuidado, pois não se pode criar um programa que leia um programa P e gere um programa P´ equivalente sendo melhor possível segundo o critério adotado.<ref name="rangel"/> Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes.<ref name="aho pcd"/> Entre as técnicas usadas estão a substituição de expressões que podem ser avaliadas durante o tempo de compilação pelos seus valores calculados, eliminação de subexpressões redundantes, desmembramento de laços, substituição de operações (multiplicação por ''shifts''), entre outras.<ref name="tremblay"/> 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. Por exemplo, em caso de computações fixas dentro de laços, é possível mover estas computações para fora dos mesmos reduzindo processamento.<ref name=Kakde>{{Citar livro|último=Kakde|primeiro=O. G.|título=Algorithms for Compiler Design|língua=en|local=Hingham|editora=Charles River media|ano=2003|páginas=334|isbn=1-58450100-6}}</ref>


=== Geração de código final ===
=== Geração de código final ===
{{Artigo principal|Geração de código}}
{{Artigo principal|Geração de código}}


A fase de geração de código final é a última fase da compilação. A geração de um bom código objeto é difícil devido aos detalhes particulares das máquinas para os quais o código é gerado. Contudo, é uma fase importante, pois uma boa geração de código pode ser, por exemplo, duas vezes mais rápida que um algoritmo de geração de código ineficiente.<ref name="aho pcd"/> Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. Optimizações dependentes da máquina necessitam de informações tais como os limites e os recursos especiais da máquina-alvo a fim de produzir um código mais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquina-alvo.<ref name="tremblay"/> Segundo Aho, o código objeto pode ser uma sequência de instruções absolutas de máquina, uma sequência de instruções de máquina relocáveis, um programa em linguagem assembly ou um programa em outra linguagem.<ref>{{Citar livro|autor=[[Alfred Aho|Aho, Alfred V.]]; Ullman, Jeffrey D.|título=The Theory of Parsing, Translation, and Compiling, Vol. 2, Compiling|subtítulo=|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1972|páginas=|página=720|volumes=2|volume=2|isbn=0-201-914564-8}}</ref>
A fase de geração de código final é a última fase da compilação. A geração de um bom código objeto é difícil devido aos detalhes particulares das máquinas para os quais o código é gerado. Contudo, é uma fase importante, pois uma boa geração de código pode ser, por exemplo, duas vezes mais rápida que um algoritmo de geração de código ineficiente.<ref name="aho pcd"/> Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. Optimizações dependentes da máquina necessitam de informações tais como os limites e os recursos especiais da máquina-alvo a fim de produzir um código mais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquina-alvo.<ref name="tremblay"/> Segundo Aho, o código objeto pode ser uma sequência de instruções absolutas de máquina, uma sequência de instruções de máquina relocáveis, um programa em linguagem assembly ou um programa em outra linguagem.<ref>{{Citar livro|autor=[[Alfred Aho|Aho, Alfred V.]]; Ullman, Jeffrey D.|título=The Theory of Parsing, Translation, and Compiling, Vol. 2, Compiling|língua=en|local=Englewood Cliffs, Nova Jersey, EUA|editora=Prentice Hall|ano=1972|página=720|volume=2|isbn=0-13914564-8}}</ref>


== Tratamento de erros ==
== Tratamento de erros ==
[[Imagem:Erro de execução.png|thumb|esquerda|300px|Tratamento de erro de execução em uma aplicação [[Java (linguagem de programação)|Java]] no [[Eclipse (software)|Eclipse]].]]
[[Imagem:Erro de execução.png|thumb|esquerda|300px|Tratamento de erro de execução em uma aplicação [[Java (linguagem de programação)|Java]] no [[Eclipse (software)|Eclipse]].]]
O 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, sistema operacional), dados incorretos, etc. As tarefas relacionadas ao tratamento de erros consitem em detectar cada erro, reportá-lo ao usuário e possivelmente fazer algum reparo para que o processamento possa continuar.<ref>{{Citar livro|último=Waite|primeiro=William M.; Goos, Gerhard|título=Compiler Construction|subtítulo=|língua3=pt|edição=|local=Nova Iorque|editora=Springer-Verlag|ano=1984|páginas=446|página=302|volumes=|volume=|isbn= 0-387-90821-8}}</ref>
O 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, sistema operacional), dados incorretos, etc. As tarefas relacionadas ao tratamento de erros consistem em detectar cada erro, reportá-lo ao usuário e possivelmente fazer algum reparo para que o processamento possa continuar.<ref>{{Citar livro|último=Waite|primeiro=William M.; Goos, Gerhard|título=Compiler Construction|local=Nova Iorque|editora=Springer-Verlag|ano=1984|páginas=446|página=302|isbn= 0-387-90821-8}}</ref>


Os erros podem ser classificados em erros léxicos, erros sintáticos, erros não independentes de contexto (semânticos), erros de execução e erros de limite.<ref name=hunter>{{Citar livro|último=Hunter|primeiro=Robin|título=Compiladores|subtítulo=Sua Concepção e Programação em Pascal|língua3=pt|edição=|local=Lisboa|editora=Presença|ano=1987|páginas=323|página=259-275|volumes=|volume=|id=Depósito legal nº 16057/87}}</ref> Os erros léxicos ocorrem quando um [[token]] identificado não pertence a gramática da linguagem fonte. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordo com a gramática, como por exemplo parênteses sem correspondência. Os erros não independentes de contexto em geral são associados a não declaração de objetos como variáveis e erros de tipos. Os erros de execução ocorrem após a compilação, quando o programa já está sendo executado. Um exemplo típico é o da divisão por zero. Os erros de limite, ocorrem durante a execução e estão relacionados as características da máquina na qual o programa está sendo executado, como por exemplo, estouro de pilha.<ref name=hunter />
Os erros podem ser classificados em erros léxicos, erros sintáticos, erros não independentes de contexto (semânticos), erros de execução e erros de limite.<ref name=hunter>{{Citar livro|último=Hunter|primeiro=Robin|título=Compiladores|subtítulo=Sua Concepção e Programação em Pascal|local=Lisboa|editora=Presença|ano=1987|páginas=323|página=259-275|id=Depósito legal nº 16057/87}}</ref> Os erros léxicos ocorrem quando um [[token]] identificado não pertence a gramática da linguagem fonte. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordo com a gramática, como por exemplo parênteses sem correspondência. Os erros não independentes de contexto em geral são associados a não declaração de objetos como variáveis e erros de tipos. Os erros de execução ocorrem após a compilação, quando o programa já está sendo executado. Um exemplo típico é o da divisão por zero. Os erros de limite, ocorrem durante a execução e estão relacionados as características da máquina na qual o programa está sendo executado, como por exemplo, estouro de pilha.<ref name=hunter />


Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro erro do programa-fonte. Esta é uma política de fácil implementação. Compiladores mais sofisticados, porém, detectam o maior número possível de erros visando diminuir o número de compilações.<ref>{{Citar livro|último=Kowaltowski|primeiro=Tomasz|autorlink=Tomasz Kowaltowski|título= Implementação de Linguagens de Programação|língua3=pt|local=Rio de Janeiro|Editora= Guanabara Dois|Ano = 1983|páginas=189|página=170-171|isbn= 85-7030-009-3}}</ref>
Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro erro do programa-fonte. Esta é uma política de fácil implementação. Compiladores mais sofisticados, porém, detectam o maior número possível de erros visando diminuir o número de compilações.<ref>{{Citar livro|último=Kowaltowski|primeiro=Tomasz|autorlink=Tomasz Kowaltowski|título= Implementação de Linguagens de Programação|local=Rio de Janeiro|editora= Guanabara Dois|ano= 1983|páginas=189|página=170-171|isbn= 85-7030-009-3}}</ref>


A recuperação de erros em analisadores sintáticos ''top-down'' é mais fácil de implementar do que em analisadores ''bottom-up''.<ref name=holub>{{Citar livro|último=Holub|primeiro=Allen I.|título=Compiler Design in C|subtítulo=|língua3=en|edição=|local=Englewood Cliffs, Nova Jersey|editora=Prentice Hall|ano=1990|páginas=924|página=201;348|volumes=|volume=|isbn= 0-13-155045-4}}</ref> 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 de ''panic-mode'' que procura em tabelas sintáticas em busca de símbolos válidos na entrada.<ref name=holub /> 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 entradas da pilha até que encontre uma entrada que permita que o processo de análise prossiga em diante.<ref>{{Citar livro|último=Kakde|primeiro=O. G.|título=Algorithms for Compiler Design|subtítulo=|língua3=en|edição=|local=Hingham|editora=Charles River media|ano=2003|páginas=334|página=261|volumes=|volume=|isbn= 81-7008-100-6}}</ref>
A recuperação de erros em analisadores sintáticos ''top-down'' é mais fácil de implementar do que em analisadores ''bottom-up''.<ref name=holub>{{Citar livro|último=Holub|primeiro=Allen I.|título=Compiler Design in C|língua=en|local=Englewood Cliffs, Nova Jersey|editora=Prentice Hall|ano=1990|páginas=924|página=201;348|isbn= 0-13-155045-4}}</ref> 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 de ''panic-mode'' que procura em tabelas sintáticas em busca de símbolos válidos na entrada.<ref name=holub /> 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 entradas da pilha até que encontre uma entrada que permita que o processo de análise prossiga em diante.<ref>{{Citar livro|último=Kakde|primeiro=O. G.|título=Algorithms for Compiler Design|língua=en|local=Hingham|editora=Charles River media|ano=2003|páginas=334|página=261|isbn= 1-58450100-6}}</ref>
 
== Notas ==
<references group="Nota"/>


{{Referências|col=2}}


== Ver também ==
== Ver também ==
Linha 91: Linha 89:
* [[Interpretador]]
* [[Interpretador]]
* [[Linker]]
* [[Linker]]
== Notas ==
<references group="Nota"/>
{{Referências|col=2}}


== Bibliografia ==
== Bibliografia ==
* {{Citar livro|último= Appel|primeiro=Andrew W.|título= Modern Compiler Implementation in C|subtítulo=Basic Techiques|Editora = Cambridge University Press|Ano = 1997|língua3=en|páginas=398|isbn= 0-521-58653-4}}
* {{Citar livro|último= Appel|primeiro=Andrew W.|título= Modern Compiler Implementation in C|subtítulo=Basic Techiques|editora= Cambridge University Press|ano= 1997|língua=en|páginas=398|isbn= 0-521-58653-4}}
* {{Citar livro|último=Brown|primeiro=P. J.|título=Writing Interactive Compilers and Interpreters|subtítulo=|língua3=en|edição=|local=Chichester|editora=John Wiley & Sons|ano=1979|páginas=265|volumes=|volume=|isbn= 0-471-27609-X}}
* {{Citar livro|último=Brown|primeiro=P. J.|título=Writing Interactive Compilers and Interpreters|língua=en|local=Chichester|editora=John Wiley & Sons|ano=1979|páginas=265|isbn= 0-471-27609-X}}
* {{Citar livro|último=Kaplan|primeiro=Randy M.|título=Constructing Language Processors for Little Languages|subtítulo=|língua3=en|edição=|local=Nova Iorque|editora=John Wiley & Sons|ano=1994|páginas=452|volumes=|volume=|isbn= 0-471-59754-6}}
* {{Citar livro|último=Kaplan|primeiro=Randy M.|título=Constructing Language Processors for Little Languages|língua=en|local=Nova Iorque|editora=John Wiley & Sons|ano=1994|páginas=452|isbn= 0-471-59754-6}}
* {{Citar livro|último=Lee|primeiro=John A. N.|título=The Anatomy of a Compiler|subtítulo=|língua3=en|edição=|local=Nova Iorque|editora=Reinhold Publishing Company|ano=1967|páginas=275|volumes=|volume=|id=Library of Congress Catalog Card Number: 67-29207}}
* {{Citar livro|último=Lee|primeiro=John A. N.|título=The Anatomy of a Compiler|língua=en|local=Nova Iorque|editora=Reinhold Publishing Company|ano=1967|páginas=275|id=Library of Congress Catalog Card Number: 67-29207}}
* {{Citar livro|último=Metsker|primeiro=Steven John|título=Building Parsers with Java|subtítulo=|língua3=en|edição=|local=Boston|editora=Addison-Wesley|ano=2001|páginas=371|volumes=|volume=|isbn= 0-201-71962-2}}
* {{Citar livro|último=Metsker|primeiro=Steven John|título=Building Parsers with Java|língua=en|local=Boston|editora=Addison-Wesley|ano=2001|páginas=371|isbn= 0-201-71962-2}}
* {{Citar livro|último=Ricarte|primeiro=Ivan|título=Introdução à Compilação|subtítulo=|língua3=pt|edição=|local=Rio de Janeiro|editora=Campus, Elsevier|ano=2008|páginas=264|volumes=|volume=|isbn= 978-85-352-3067-3}}
* {{Citar livro|último=Ricarte|primeiro=Ivan|título=Introdução à Compilação|local=Rio de Janeiro|editora=Campus, Elsevier|ano=2008|páginas=264|isbn= 978-85-352-3067-3}}
* {{Citar livro|último=Terry|primeiro=Patrick D.|título=Programming Language Translation|subtítulo=A Practical Approach|língua3=en|edição=|local=Wokingham|editora=Addison-Wesley|ano=1986|páginas=443|volumes=|volume=|isbn= 0-201-18040-5}}
* {{Citar livro|último=Terry|primeiro=Patrick D.|título=Programming Language Translation|subtítulo=A Practical Approach|língua=en|local=Wokingham|editora=Addison-Wesley|ano=1986|páginas=443|isbn= 0-201-18040-5}}
* {{Citar livro|último=Wirth|primeiro=Niklaus|autorlink=Niklaus Wirth|título= Compiler Construction|url=http://www.cs.inf.ethz.ch/~wirth/books/CompilerConstruction|língua3=en|Editora = Addison-Wesley|Ano = 1996|isbn= 0-201-40353-6}}
* {{Citar livro|último=Wirth|primeiro=Niklaus|autorlink=Niklaus Wirth|título=Compiler Construction|url=http://www.cs.inf.ethz.ch/~wirth/books/CompilerConstruction|língua=en|editora=Addison-Wesley|ano=1996|isbn=0-201-40353-6|acessodata=2007-03-17|arquivourl=https://web.archive.org/web/20070205031012/http://www.cs.inf.ethz.ch/~wirth/books/CompilerConstruction/|arquivodata=2007-02-05|urlmorta=yes}}


== Ligações externas ==
== Ligações externas ==
Linha 107: Linha 110:
|wikilivros      = Construção de compiladores
|wikilivros      = Construção de compiladores
}}
}}
* {{Link|pt|http://www-di.inf.puc-rio.br/~rangel/comp.html|Página com material de compiladores}}
 
* {{Link|pt|http://verto.sf.net|Compilador Educativo Verto}}
* {{Link|pt|http://verto.sf.net|Compilador Educativo Verto}}
* {{Link|en|http://www.thefreecountry.com/compilers/index.shtml|Compiladores livres}}
* {{Link|en|http://www.thefreecountry.com/compilers/index.shtml|Compiladores livres}}

Edição atual tal como às 03h15min de 13 de março de 2022

Predefinição:Execução de Programa

Disambig grey.svg 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 executado.

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.[1] 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,[Nota 1] as subrotinas necessárias para executar uma determinada tarefa.[2][3]

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.[4] Para alguns autores um programa que faz uma tradução entre linguagens de alto nível é normalmente chamado um tradutor, filtro[5] 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.[6] Um programa que 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 o código de máquina e uma linguagem de montagem é denominado desmontador (disassembler).[6] 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.[7]

História

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.

No final da década de 1950, as linguagens de programação independentes de máquina foram propostas. Posteriormente, vários compiladores experimentais foram desenvolvidos. O primeiro compilador foi escrito por Grace Hopper,[8] em 1952, para a linguagem de programação A-0.[9] Antes de 1957, foram desenvolvidos esforços e várias contribuições ao desenvolvimento de linguagens de alto nível foram feitas. Entre estes, o desenvolvimento da Short Code (UNIVAC), Speedcoding no IBM 701,[10][11] o Whirlwind, o BACAIC e o PRINT.[12] A equipe de desenvolvimento do FORTRAN liderada por John Backus na IBM é geralmente creditada como tendo introduzido o primeiro compilador completo em 1957 (embora tenha ocorrido simultaneamente o desenvolvimento do algebraic translator de Laning e Zierler[9]). O COBOL é um exemplo de uma linguagem da primeira geração que compilava em múltiplas arquiteturas, em 1960.[13]

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 em 1962.[14]

Características

O processo da compilaçã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,[15] como uma sequência de instruções a ser executada pelo microprocessador.

O processo de compilação é composto de análise e síntese.[16] 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.[16] 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.[16]

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.[17]

Um compilador é chamado de Just-in-time compiler (JIT) quando seu processo de compilação acontece apenas quando o código é chamado.[18] Um JIT pode fazer otimizações às instruções a medida que as compila.[18]

Muitos compiladores incluem um pré-processador. Que é um programa separado, 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 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.[20] 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.

Fases da compilação

Análise léxica

Ver artigo principal: Análise léxica

A 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, caractere a caractere, buscando a separação e identificação dos elementos componentes do programa-fonte, denominados símbolos léxicos ou tokens.[22] É também de responsabilidade desta fase a eliminação de elementos "decorativos" do programa, tais como espaços em branco, marcas de formatação de texto e comentários.[23] Existem disponíveis uma série de geradores automáticos de analisadores léxicos, como por exemplo, o lex. O objetivo dos geradores 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

A análise sintática, ou análise gramatical é o processo de se determinar se uma cadeia de símbolos léxicos pode ser gerada por uma gramática.[25] O analisador sintático é o cerne do compilador, responsável por verificar se os símbolos contidos no programa fonte formam 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 os analisadores bottom-up só podem ser gerados automaticamente.[27] A maioria dos métodos de análise sintática, cai em uma dessas duas classes denominadas top-down e bottom-up.[28] Entre os métodos top-down os mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. Entre os métodos de análise sintática bottom-up os mais importantes são a análise sintática de precedência de operadores, análise sintática LR canônico, análise sintática LALR e análise sintática SLR.[25] Existem disponíveis uma série de geradores automáticos de analisadores sintáticos,[29] como por exemplo, o Yacc, o Bison e o JavaCC.

Análise semântica

Ver artigo principal: Análise semântica

As análises léxica e sintática não estão preocupadas com o significado ou semântica dos programas que elas processam. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas.[30] As gramáticas livres de contexto não são suficientemente poderosas para descrever uma série de construções das linguagens de programação, como por exemplo regras de escopo, regras de visibilidade e consistência de tipos.[31] É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões.[32] Um dos mecanismos comumente utilizados por implementadores de compiladores é a Gramática de Atributos, que consiste em uma gramática livre de contexto acrescentada de um conjunto finito de atributos e um conjunto finito de predicados sobre estes atributos.[33]

Geração de código intermediário

Exemplo de código de três endereços e um DAG correspondente para uma expressão aritmética.
Ver artigo principal: Geração de código

Na fase de geração de código intermediário, ocorre a transformação da árvore sintática em 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 uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado.[34] Um tipo popular de linguagem intermediária é conhecido como código de trê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 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.[36] 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.[37]

Otimização de código

A otimização de código é a estratégia de examinar o código intermediário, produzido durante a fase de geração de código com objetivo de produzir, através de algumas técnicas, um código que execute com bastante eficiência.[32] O nome optimizador deve sempre ser encarado com cuidado, pois não se pode criar um programa que leia um programa P e gere um programa P´ equivalente sendo melhor possível segundo o critério adotado.[23] Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes.[36] Entre as técnicas usadas estão a substituição de expressões que podem ser avaliadas durante o tempo de compilação pelos seus valores calculados, eliminação de subexpressões redundantes, desmembramento de laços, substituição de operações (multiplicação por shifts), entre outras.[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. Por exemplo, em caso de computações fixas dentro de laços, é possível mover estas computações para fora dos mesmos reduzindo processamento.[38]

Geração de código final

Ver artigo principal: Geração de código

A fase de geração de código final é a última fase da compilação. A geração de um bom código objeto é difícil devido aos detalhes particulares das máquinas para os quais o código é gerado. Contudo, é uma fase importante, pois uma boa geração de código pode ser, por exemplo, duas vezes mais rápida que um algoritmo de geração de código ineficiente.[36] Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. Optimizações dependentes da máquina necessitam de informações tais como os limites e os recursos especiais da máquina-alvo a fim de produzir um código mais compacto e eficiente. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquina-alvo.[32] Segundo Aho, o código objeto pode ser uma sequência de instruções absolutas de máquina, uma sequência de instruções de máquina relocáveis, um programa em linguagem assembly ou um programa em outra linguagem.[39]

Tratamento de erros

Tratamento de erro de execução em uma aplicação Java no Eclipse.

O 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, sistema operacional), dados incorretos, etc. As tarefas relacionadas ao tratamento de erros consistem em detectar cada erro, reportá-lo ao usuário e possivelmente fazer algum reparo para que o processamento possa continuar.[40]

Os erros podem ser classificados em erros léxicos, erros sintáticos, erros não independentes de contexto (semânticos), erros de execução e erros de limite.[41] Os erros léxicos ocorrem quando um token identificado não pertence a gramática da linguagem fonte. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordo com a gramática, como por exemplo parênteses sem correspondência. Os erros não independentes de contexto em geral são associados a não declaração de objetos como variáveis e erros de tipos. Os erros de execução ocorrem após a compilação, quando o programa já está sendo executado. Um exemplo típico é o da divisão por zero. Os erros de limite, ocorrem durante a execução e estão relacionados as características da máquina na qual o programa está sendo executado, como por exemplo, estouro de pilha.[41]

Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro erro do programa-fonte. Esta é uma política de fácil implementação. Compiladores mais sofisticados, porém, detectam o maior número possível de erros visando diminuir o número de compilações.[42]

A recuperação de erros em analisadores sintáticos top-down é mais fácil de implementar do 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 de panic-mode que procura em tabelas sintáticas em busca de símbolos válidos na entrada.[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 entradas da pilha até que encontre uma entrada que permita que o processo de análise prossiga em diante.[44]


Ver também

Notas

  1. Em português, "compilar" significa, por exemplo: reunir obras literárias, documentos, escritos de vários autores, entre outros, compondo uma obra com esse material. Larousse (1992). Dicionário da Língua Portuguesa (em English). [S.l.]: Nova Cultural. ISBN 85-85222-23-9 

Referências

  1. Aho, Alfred V.; Ullman, Jeffrey D. (1977). Principles of Compiler Design (em English). Reading, Massachusetts, EUA: Addison-Wesley. p. 1. 604 páginas. ISBN 0-201-00022-9 
  2. Parsons, Thomas W. (1992). Introduction to Compiler Construction (em English). Nova Iorque, EUA: Computer Science Press. p. 1. 359 páginas. ISBN 0-7167-8261-8 
  3. Appel, Andrew W. (1998). Modern Compiler Implementation in Java (em English). Cambridge: Cambridge University Press. p. 3. 548 páginas. ISBN 0-521-58388-8 
  4. Cooper, Torczon (2003). Engineering a Compiler (em English). San Francisco: Morgan Kaufmann. p. 2. ISBN 1-55860-698-X 
  5. 5,0 5,1 Neto, João José (1987). Introdução à Compilação. Rio de Janeiro: LTC. 222 páginas. ISBN 978-85-216-0483-9 
  6. 6,0 6,1 Watt, David A.; Brown, Deryck F. (2000). Programming Language Processors in Java (em English). Harlow, England: Prentice Hall. p. 27. 436 páginas. ISBN 0-130-25786-9 
  7. Elder, John (1994). Compiler Conctruction. A Recursive Descent Model (em English). 1. Englewood Cliffs, Nova Jersey, EUA: Prentice Hall. p. 7-8. 437 páginas. ISBN 0-13-291139-6 
  8. Lemone, Karen A. (1992). Fundamentals of Compilers. An Introduction to Computer Language Translation (em English). Boca Raton: CRC. 184 páginas. ISBN 0-8493-7341-7 
  9. 9,0 9,1 Wexelblat, Richard L.(Editor) (1981). History of Programming Languages. New York: Academic Press. p. 6-15. 758 páginas. ISBN 0-12-745040-8 
  10. Bashe, Charles J.; Johnson, Lyle R.; Palmer, John H.; Pugh, Emerson W. (1986). IBM´s Early Computers. Cambridge: MIT Press. p. 333. 716 páginas. ISBN 0-262-02225-7 
  11. McClelland, William F (abril 1983). «Programming». Annals of The History of Computing (em English). 5 (2). Arlington, VA: American Federation of Information Processing Societies. pp. 135–139. ISSN 1058-6180 
  12. Sammet, Jean E (1969). Programming Languages: History and Fundamentals. Englewood Cliffs, New Jersey: Prentice Hall. p. 5. 785 páginas. ISBN 0-13-729988-5 
  13. «IP: Os primeiros compiladores COBOL do mundo». interesting-people.org. 12 de Junho de 1997. Consultado em 21 de dezembro de 2011. Arquivado do original em 20 de fevereiro de 2012 
  14. T. Hart and M. Levin. «O novo compilador, AIM-39 - CSAIL Digital Archive - Artificial Intelligence Laboratory Series» (PDF). publications.ai.mit.edu [ligação inativa]
  15. Mak, Ronald (1996). Writing Compilers and Interpreters. An Applied Approach Using C++ (em English). Nova Iorque: John Wiley and Sons. p. 1. 838 páginas. ISBN 0-471-11353-0 
  16. 16,0 16,1 16,2 Holmes, Jim (1995). Object-Oriented Compiler Construction (em English). Englewood Cliffs, Nova Jersey: Prentice Hall. p. 2-3. 483 páginas. ISBN 0-13-630740-X 
  17. Sebesta, Robert (2010). Conceitos de Linguagens de Programação 9ª ed. Porto Alegre: Bookman. p. 49-50. 792 páginas. ISBN 978-85-7780-791-8 
  18. 18,0 18,1 Engel, Joshua (1999). Programming for the Java Virtual Machine (em English). Reading, Massachusetts: Addison & Wesley. p. 355. 488 páginas. ISBN 0-201-30972-6 
  19. Louden, Kenneth C. (2004). Compiladores. Princípios e Práticas. São Paulo: Pioneira Thompson Learning. p. 5. 569 páginas. ISBN 85-221-0422-0 
  20. Levine, John R. (2000). Linkers & Loaders (em English). San Francisco: Morgan Kaufmann Publishers. p. 1-3. 256 páginas. ISBN 1-55860-496-0 
  21. Aho, Alfred V.; Ullman, Jeffrey D. (1972). The Theory of Parsing, Translation, and Compiling, Vol. 1, Parsing (em English). 1. Englewood Cliffs, Nova Jersey, EUA: Prentice Hall. p. 59. 542 páginas. ISBN 0-13-914556-7 
  22. Price, Ana M. A.; Toscano, Simão Sirineo (2000). Implementação de Linguagens de Programação: Compiladores. Série de Livros Didáticos Número 9. Porto Alegre: Sagra Luzzatto. 195 páginas. ISBN 978-85-241-0639-2 
  23. 23,0 23,1 «Compiladores - Página de José Lucas Mourão Rangel Netto». PUC-Rio. Consultado em 21 de junho de 2009. Arquivado do original em 12 de abril de 2009 
  24. Fischer, Charles N.; LeBlanc, Jr, Richard J. (1991). Crafting a Compiler with C (em English). Redwood City, California: Benjamin Cummings Publishing. p. 50. 812 páginas. ISBN 0-8053-2166-7 
  25. 25,0 25,1 Aho, Alfred V.; Sethi, Ravi; Ullman, Jeffrey D. (1986). Compilers: Principles, Techniques and Tools (em English). Reading, Massachusetts, EUA: Addison-Wesley. 796 páginas. ISBN 978-0-201-10088-4 
  26. Delamaro, Marcio (2004). Como Construir um Compilador Utilizando Ferramentas Java. São Paulo: Novatec. p. 4. 308 páginas. ISBN 85-7522-055-1 
  27. Grune, Dick; Bal, Henri E.; Jacobs, Ceriel J. H.; Langendoen, Koen G (2001). Projeto Moderno de Compiladores. Rio de Janeiro: Campus. ISBN 978-85-352-0876-4 
  28. Lewis II, P. M.; Rosenkrantz, D,J.; Stearns, R.E. (1978). Compiler Design Theory (em English). Reading, Massachusetts: Addison-Wesley. p. 227. 647 páginas. ISBN 0-201-14455-7 
  29. Alblas, Henk; Nymeyer, Albert (1996). Practice and Principles of Compiler Building with C (em English). London: Prentice Hall. p. 30. 427 páginas. ISBN 0-13-349267-2 
  30. Watson, Des (1989). High-Level Languages and Their Compilers (em English). Wokingham, Reino Unido: Addison-Wesley. 337 páginas. ISBN 0-201-18489-3 
  31. Wilhelm, Reinhard; Maurer, Dieter (1995). Compiler Design (em English). Harlow, England: Addison-Wesley. 606 páginas. ISBN 0-201-42290-5 
  32. 32,0 32,1 32,2 32,3 Tremblay, Jean-Paul; Sorenson, Paul G. (1989). The Theory and Practice of Compiler Writing (em English). Nova Iorque: McGraw-Hill. 796 páginas. ISBN 0-07-065161-2 
  33. Pittman, Thomas; Peters, James (1992). The Art of Compiler Design. Theory and Practice (em English). Englewood Cliffs, Nova Jersey, EUA: Prentice Hall. 419 páginas. ISBN 0-13-048190-4 
  34. Pyster, Arthur B. (1988). Compiler Design and Construction. Tools and Techniques (em English). Nova Iorque, EUA: Van Nostrand Reinhold Company. p. 8. 267 páginas. ISBN 0-442-27536-6 
  35. Crespo, Rui Gustavo (1998). Processadores de Linguagens. da Concepção à Implementação. Lisboa, Portugal: IST Press. p. 247. 435 páginas. ISBN 972-8469-01-2 
  36. 36,0 36,1 36,2 Aho, Alfred V.; Ullman, Jeffrey D. (1977). Principles of Compiler Design (em English). Reading, Massachusetts, EUA: Addison-Wesley. 604 páginas. ISBN 0-201-00022-9 
  37. Muchnick, Steven S. (1997). Advanced Compiler Design Implementation (em English). San Francisco, California: Morgan Kaufmann Publishers. p. 96. 856 páginas. ISBN 1-55860-320-4 
  38. Kakde, O. G. (2003). Algorithms for Compiler Design (em English). Hingham: Charles River media. 334 páginas. ISBN 1-58450100-6 
  39. Aho, Alfred V.; Ullman, Jeffrey D. (1972). The Theory of Parsing, Translation, and Compiling, Vol. 2, Compiling (em English). 2. Englewood Cliffs, Nova Jersey, EUA: Prentice Hall. p. 720. ISBN 0-13914564-8 
  40. Waite, William M.; Goos, Gerhard (1984). Compiler Construction. Nova Iorque: Springer-Verlag. p. 302. 446 páginas. ISBN 0-387-90821-8 
  41. 41,0 41,1 Hunter, Robin (1987). Compiladores. Sua Concepção e Programação em Pascal. Lisboa: Presença. p. 259-275. 323 páginas. Depósito legal nº 16057/87 
  42. Kowaltowski, Tomasz (1983). Implementação de Linguagens de Programação. Rio de Janeiro: Guanabara Dois. p. 170-171. 189 páginas. ISBN 85-7030-009-3 
  43. 43,0 43,1 Holub, Allen I. (1990). Compiler Design in C (em English). Englewood Cliffs, Nova Jersey: Prentice Hall. p. 201;348. 924 páginas. ISBN 0-13-155045-4 
  44. Kakde, O. G. (2003). Algorithms for Compiler Design (em English). Hingham: Charles River media. p. 261. 334 páginas. ISBN 1-58450100-6 

Bibliografia

  • Appel, Andrew W. (1997). Modern Compiler Implementation in C. Basic Techiques (em English). [S.l.]: Cambridge University Press. 398 páginas. ISBN 0-521-58653-4 
  • Brown, P. J. (1979). Writing Interactive Compilers and Interpreters (em English). Chichester: John Wiley & Sons. 265 páginas. ISBN 0-471-27609-X 
  • Kaplan, Randy M. (1994). Constructing Language Processors for Little Languages (em English). Nova Iorque: John Wiley & Sons. 452 páginas. ISBN 0-471-59754-6 
  • Lee, John A. N. (1967). The Anatomy of a Compiler (em English). Nova Iorque: Reinhold Publishing Company. 275 páginas. Library of Congress Catalog Card Number: 67-29207 
  • Metsker, Steven John (2001). Building Parsers with Java (em English). Boston: Addison-Wesley. 371 páginas. ISBN 0-201-71962-2 
  • Ricarte, Ivan (2008). Introdução à Compilação. Rio de Janeiro: Campus, Elsevier. 264 páginas. ISBN 978-85-352-3067-3 
  • Terry, Patrick D. (1986). Programming Language Translation. A Practical Approach (em English). Wokingham: Addison-Wesley. 443 páginas. ISBN 0-201-18040-5 
  • Wirth, Niklaus (1996). Compiler Construction (em English). [S.l.]: Addison-Wesley. ISBN 0-201-40353-6. Consultado em 17 de março de 2007. Arquivado do original em 5 de fevereiro de 2007 

Ligações externas

Outros projetos Wikimedia também contêm material sobre este tema:
Wikcionário Definições no Wikcionário
Wikilivros Livros e manuais no Wikilivros


talvez você goste