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, caracter a caracter, 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 léxica - A fase de análise léxica (varredora) tem por objetivo ler o programa fonte e transformar seqüências de caracteres em uma representação interna, denominada itens léxicos. A saída é um fluxo do símbolo. As expressões regulares são usadas para definir o símbolo reconhecido por um varredor (ou pelo analisador lexical). Por exemplo, suponha a expressão abaixo, descrita em Pascal: Exp := (A + B) * 1.5; Os itens léxicos contidos nesta expressão, são: Exp, :=, (, A, +, B, ), *, 1.5 e ;. Os itens léxicos a serem reconhecidos pelo analisador léxico são determinados pela gramática da linguagem-fonte. Deste modo, caso um item léxico não seja definido por esta gramática, um erro léxico é gerado. Por exemplo, suponhamos que uma linguagem só suporte valores inteiros. Então o valor 1.5 iria ocasionar um erro, o qual deverá ser tratado.

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 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

Uma das tarefas mais importantes é a verificação de tipos.[32] Um dos mecanismos comumente utilizados por implementadores de compiladores é a Gramática de Atributos. Se você escreve writeln. ou análise de contexto. a ausência de declarações de variáveis.[25] Existem disponíveis uma série de geradores automáticos de analisadores sintáticos. seu programa passará pela análise léxica (writeln e identificador existem). como por exemplo regras de escopo. e um identificador.[33] A análise semântica . regras de visibilidade e consistência de tipos. mas não passará pela análise sintática. 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.[29] como por exemplo. os conflitos entre tipos.analisa a árvore sintática para a informação context-sensitive. funções e procedimentos. e descobrir a relação de uns com os outros. um espaço. O papel do analisador semântico é prover métodos pelos quais as estruturas construídas pelo analisador sintático possam ser avaliadas ou executadas. análise sintática LALR e análise sintática SLR.[31] É papel do analisador semântico assegurar que todas as regras sensíveis ao contexto da linguagem estejam analisadas e verificadas quanto à sua validade. Geração de código intermediário Exemplo de código de três endereços e um DAG correspondente para uma expressão aritimética Ver artigo principal: Geração de código .[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. o Yacc. Análise Sintática . 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. o Bison e o JavaCC. que informa a necessidade de um abre-parênteses logo após esta procedure. Um exemplo de tarefa própria do analisador semântico é a checagem de tipos de variáveis em expressões. 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. por exemplo. gerada pelo analisador sintático em busca de inconsistências semânticas.mais importantes são a análise sintática descendente recursiva e a análise sintática preditiva não-recursiva. análise sintática LR canônico.responsabiliza-se por traduzir os Tokens. É nesta fase que são detectadas.

em caso de computações fixas dentro de laços. os grafos acíclicos dirigidos(DAG) e a notação polonesa. onde X.[38] A fase de otimização . produzido durante a fase de geração de código com objetivo de produzir.[34] Um tipo popular de linguagem intermediária é conhecido como código de três endereços. Esta forma intermediária não é executada diretamente pela máquina alvo.[23] Várias técnicas e várias tarefas se reúnem sob o nome de Optimização. eliminação de sub-expressões redundantes. .[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. principalmente aqueles que executam extensivas otimizações de código.[32] O nome optimizador deve sempre ser encarado com cuidado.Na fase de geração de código intermediário. mas ainda permite uma manipulação mais fácil do que se código assembly ou código de máquina fosse utilizado. Por exemplo. Esta linguagem intermediária é mais próxima da linguagem objeto do que o código fonte.[35] Neste tipo de código uma sentença típica tem a forma X := A op B. normalmente em código de três endereços. Uma forma prática de representar sentenças de três endereços é através do uso de quádruplas (operador. resultado). usando as réguas que denotam a semântica da linguagem-fonte. Optimização de código A Otimização de código é a estratégia de examinar o código intermediário. ocorre a transformação da árvore sintática em uma representação intermediária do código fonte. um código que execute com bastante eficiência.[32] Uma das técnicas de optimização mais eficazes e independente de máquina é a otimização de laços. é possível mover estas computações para fora dos mesmos reduzindo processamento. Estas técnicas consistem em detectar padrões dentro do código produzido e substituí-los por códigos mais eficientes. entre outras.[37] A fase de geração de código intermediário . argumento 2 e. (similares as quádruplas exceto pelo fato de que os resultados não são nomeados explicitamente) as árvores. argumento 1. Uma das tarefas executadas pelo otimizador é a detecção e a eliminação de movimento de dados redundantes e a repetição de operações dentro de um mesmo bloco de programa. desmembramento de laços. pois laços internos são bons candidatos para melhorias. através de algumas técnicas.analisa o código no formato intermediário e tenta melhorá-lo de tal forma que venha a resultar um código de máquina mais rápido em tempo de execução. 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.[36]Outras representações de código intermediário comumente usadas são as triplas. Este esquema de representação de código intermediário é preferido por diversos compiladores. substituição de operações (multiplicação por shifts). uma vez que o código intermediário pode ser rearranjado de uma maneira conveniente com facilidade. A e B são operandos e op uma operação qualquer.permite a geração de instruções para uma máquina abstrata. mais adequadas a fase de otimização.

como por exemplo parênteses sem correspondência. erros sintáticos. Os erros de execução ocorrem após a compilação. as instruções intermediárias são. sistema operacional). Tratamento de erros Tratamento de erro de execução em uma aplicação Java no Elipse O tratamento de erros está voltado a falhas devido a muitas causas: erros no compilador. erros não independentes de contexto (semânticos). pois uma boa geração de código pode ser.[41] Os erros léxicos ocorrem quando um token identificado não pertence a gramática da linguagem fonte. 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. Um exemplo típico é o da divisão por zero. por exemplo. erros na elaboração do programa a ser compilado. O código produzido pelo compilador deve se aproveitar dos recursos especiais de cada máquinaalvo. Os erros sintáticos ocorrem quando alguma estrutura de frase não está de acordo com a gramática. traduzidas numa seqüência de instruções de máquina que realizam a mesma tarefa. Os erros não indepenentes de contexto em geral são associados a não declaração de objetos como variáveis e erros de tipos. Normalmente este código objeto é um código de máquina relocável ou um código de montagem.[39] A fase de geração de código .[36] Nem todas as técnicas de optimização são independentes da arquitetura da máquina-alvo. As tarefas relacionadas ao tratamento de erros consitem em detectar cada erro. cada uma. erros de execução e erros de limite. erros no ambiente (hardware. reportá-lo ao usuário e possivelmente fazer algum reparo para que o processamento possa continuar. quando o programa já está sendo executado. 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 objeto pode ser uma sequência de instruções absolutas de máquina.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. Contudo é uma fase importante.[32] Segundo Aho. dados incorretos.tem como objetivo analisar o código já otimizado é a gerar o um código objeto definitivo para uma máquina alvo. Nesta etapa as localizações de memória são selecionadas para cada uma das variáveis usadas pelo programa. Então. uma sequência de instruções de máquina relocáveis. Os erros de limite. um programa em linguagem assembly ou um programa em outra linguagem. ocorrem durante a execução e estão .[40] Os erros podem ser classificados em erros léxicos. duas vezes mais rápida que um algoritmo de geração de código ineficiente. etc.

somente os que já foram processados.[43] Nesta técnica se descartam símbolos da entrada até que um delimitador (como um ponto e vírgula. detectam o maior número possível de erros visando diminuir o número de compilações. Esta é uma política de fácil implementação.[44] . por exemplo.[42] A recuperação de erros em analisadores sintáticos top-down é mais fácil de implementar do que em analisadores bottom-up.relacionados as características da máquina na qual o programa está sendo executado. este último não sabe quais símbolos são esperados na entrada. a técnica de panic-mode que procura em tabelas sintáticas em busca de símbolos válidos na entrada. Compiladores mais sofisticados. O analisador apaga as entradas da pilha até que encontre uma entrada que permita que o processo de análise prossiga em diante.[41] Alguns compiladores encerram o processo de tradução logo ao encontrar o primeiro erro do programa-fonte. estouro de pilha. Pode-se usar neste caso técnicas como. por exemplo) seja encontrado.[43] O problema é que diferente de um analisador top-down. como por exemplo. porém.

Sign up to vote on this title
UsefulNot useful