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

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

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

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

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

Sign up to vote on this title
UsefulNot useful