Subido por Paulo Nicolau

Resumo Compilação

Anuncio
Resumo da UC de Compilação
Introdução
Sintática: uma linguagem de programação é uma notação utilizado pelo programador para
especificar ações a serem executadas por um computador.
Semântica: uma linguagem de programação compreende um conjunto de conceitos que um
programador usa para resolver problemas de programação.
Paradigmas de Linguagens de Programação
•
•
•
Imperativas: C, Pascal, Fortan, cobol, etc...
Declarativas:
◦ Funcionais: LISP, ML, Haskell, etc...
◦ Lógicas: Prolog
Orientadas a Objetos: Smalltack, Java, etc...
Diferenças entre Compilador e Interpretador
Interpretador: Programa que interpreta as instruções (código-fonte) diretamente na máquina, sem
passar por uma fase de compilação.
Compilador: Programa que traduz código escrito numa determinada linguagem (código-fonte), em
código escrito noutra linguagem (código-objeto)
Estrutura de um Compilador
Figura 1: Fonte: vídeos UNIVESP de Linguagens e Compiladores
Paulo Nicolau
1/6
Resumo da UC de Compilação
Análise Léxica
Fase em que o código é convertido em tokens que são guardados numa tabela de símbolos de modo
a que as restantes fases do compilador possam analisar o código.
Tabela de Símbolos: tabela onde são armazenados todos os símbolos (lexemas) utilizados no
código que está a ser analisado no compilador (é comum a todas as fases do compilador).
Léxico: é o conjunto de palavras de um determinado idioma
linguagem)
(conjunto de objetos de uma
Analisador Léxico: recebe uma string como entrada gerando tokens ao retirar símbolos sem valor
sintático/semântico.
Token: representação dos lexemas (objetos léxicos da linguagem) sob a forma de uma estrutura de
dados <classe, valor>.
Classe: indicação da classificação que pode ter (número, identificador, palavra-reservada, etc...)
Valor: o valor do próprio token (“12” [caso seja classe numérica], “if” [caso seja classe palavrareservada]);
Classes de Tokens
• Palavras-reservadas
• Operadores
• Identificadores
• Números
• Literais
• Símbolos de pontuação
Figura 2: Fonte: vídeos UNIVESP de Linguagens e Compiladores
Paulo Nicolau
2/6
Resumo da UC de Compilação
Linguagens Regulares: conjunto de linguagens que podem ser geradas por gramáticas regulares,
reconhecidas por autómatos finitos e facilmente descritas por expressões regulares
Reconhecedores de linguagem: São dispositivos conceituais compostos por texto de entrada
(cadeia de símbolos), cursor de leitura, controlo (máquina de estados finita) que podem usar uma
memória auxiliar, e que aceitam uma determinada linguagem.
Análise Sintática
Árvore Sintática: Forma esquemática que mostra a sequência de derivações realizadas, de forma a
formar uma palavra.
Gramáticas Livre de Contexto
As linguagens com que os compiladores funcionam são geradas por gramáticas que geram todas as
instruções aceites pela linguagem de programação.
Para o compilador, desde que a gramática permita gerar a instrução ela será utilizada por ele, de
forma a validar a instrução. No entanto as gramáticas podem ser derivadas mais à esquerda primeiro
ou mais à direita primeiro, o que pode levar a situações onde existem duas árvore sintáticas que
permitem gerar a mesma instrução, o que torna a gramática ambígua.
A existência de duas árvores diferentes gera o problema de o compilador poder executar primeiro
operações que não são válidas, como por exemplo na gramática G→ E+ E | E∗E | id temos as
seguintes árvores sintáticas para formar a instrução 5+2∗3 :
Na primeira árvores o resultado final será o valor 11 enquanto na segunda o valor será 21, pois a
soma é realizado antes da multiplicação (devido a estar num nível da árvore mais baixo), o que do
ponto de vista matemático está incorreto, logo o compilador não deveria poder executar esta árvore.
No entanto para o compilador ambas as árvores são válidas e ele poderá executar tanto uma como a
outra.
Paulo Nicolau
3/6
Resumo da UC de Compilação
Assim será necessário remover a ambiguidade da gramática, para que este problema não exista.
Remover ambiguidades das gramáticas
Associatividade: propriedade dos operadores binários que garante que o resultado é idêntico seja
qual for a ordem dos operadores. No caso de existência de múltiplos operadores do mesmo tipo, a
associatividade é realizada mais à esquerda primeiro. Na árvore de derivação estará relacionado
com a recursividade (à esquerda).
Precedência: propriedade que indica quais operadores necessitam ser executados primeiro que
outros. Na árvore de derivação estará relacionado com os níveis da árvore.
Para remover as ambiguidades de uma gramática é necessário modificar a gramática de forma a
garantir as propriedades associatividade e precedência.
Para garantir a precedência é necessário garantir na nova gramática que as operações que possuem
maior precedência se encontram num nível mais inferior da árvore, ou seja, que a sua derivação
aconteça por último, de forma a que sejam estas a ser calculadas primeiro devido às características
das árvores.
Já para garantir a associatividade, é necessário utilizar na nova gramática símbolos (variáveis)
diferentes de cada lado do operador, sendo que no lado esquerdo ficará o símbolo da própria
produção. (No entanto esta não será a melhor solução).
Eliminar Recursão à Esquerda
Permite tornar uma recursão à esquerda em recursão à direita, pois alguns algoritmos não
funcionam bem com este tipo de recursão.
Recursão à esquerda: A → A α | β Recursão à direita: A → α A | β
α pode conter variáveis e símbolosterminais
β pode ter variáveis e símbolos terminais , menos o símbolo A
Processo de eliminação:
• Na variável com recursão manter apenas o símbolo base seguido de uma nova variável
• Na nova variável adicionar o símbolo que repete seguido da própria variável
• Adicionar uma produção vazia na nova variável
Exemplo: A → A α | β ficará com recursão à direita na seguinte forma A → β A '
, produzindo
A '→α A ' |λ
a mesma linguagem.
Paulo Nicolau
4/6
Resumo da UC de Compilação
Na análise sintática pretende-se ter gramáticas com as seguintes características, e que garantam a
precedência e a associatividade:
Já foi visto anteriormente como garantir que as características das gramáticas cumpram os
requisitos da recursividade e da ambiguidade. Falta apenas tratar do determinismo, que é fazer com
que numa gramática não existam múltiplas produções com o mesmo símbolo.
Gramática Não Determinista: A → α β1 | α β2 | α β3
Fatoração à Esquerda: Processo de eliminar o não determinismo de uma gramática.
Passos de Fatoração à Esquerda:
• Colocar na variável que causa o não determinismo apenas uma produção (genérica) por cada
símbolo diferente, seguido de uma nova variável.
• Na nova variável colocar os diferentes símbolos possíveis (símbolos removidos da produção
anterior)
Nota: Ao converter uma gramática por este processo não garante a não ambiguidade da gramática
Exemplo: Gramática anterior na forma determinista A → α A '
A ' → β1 | β2 | β3
Algoritmos de Análise Sintática
Paulo Nicolau
5/6
Resumo da UC de Compilação
Os algoritmos do ramo TopDown Parsing são algoritmos que necessitam de mais processamento,
pois são algoritmos que ou trabalham por força bruta (TopDown Parsing com Backtracking) ou para
funcioanr necessitam de garantir o determinismo e não existência de recursividade à esquerda nas
gramáticas com que vão trabalhar (Descendente Recursivo e LL(1)).
Paulo Nicolau
6/6
Descargar