revisão compiladores – ap1

69
1 Revisão Compiladores – AP1 Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife

Upload: september-dunlap

Post on 04-Jan-2016

54 views

Category:

Documents


0 download

DESCRIPTION

Revisão Compiladores – AP1. Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife. Contatos. Prof. Guilherme Alexandre Monteiro Reinaldo Apelido: Alexandre Cordel E-mail/ gtalk : [email protected] [email protected] - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Revisão Compiladores – AP1

1

Revisão Compiladores – AP1

Prof. Alexandre Monteiro

Baseado em material cedido pelo Prof. Euclides Arcoverde

Recife

Page 2: Revisão Compiladores – AP1

Contatos

Prof. Guilherme Alexandre Monteiro Reinaldo

Apelido: Alexandre Cordel

E-mail/gtalk: [email protected]

[email protected]

Site: http://www.alexandrecordel.com.br/fbv

Celular: (81) 9801-1878

Page 3: Revisão Compiladores – AP1

3

Objetivo

O principal objetivo é responder à seguinte pergunta:

• Como criar uma linguagem computacional?

Para responder a pergunta, estudaremos:

• Como especificar uma linguagem• Como construir um compilador para ela

Page 4: Revisão Compiladores – AP1

História das Linguagens

Page 5: Revisão Compiladores – AP1

5

História das Linguagens Começaram a surgir outras linguagens

mais elaboradas• Fortran (1957)• LISP (1959)• COBOL (1960)• BASIC (1964)• C (1972)• etc.

Page 6: Revisão Compiladores – AP1

Linguagens de Alto Nível

Page 7: Revisão Compiladores – AP1

7

Linguagens de Alto Nível

O nome “alto nível” tem o sentido de “alto nível de abstração”, pois essas linguagens abstraem detalhes operacionais pouco relevantes• Assim, o programador pode (tenta) focar só no

algoritmo

Veremos agora dois exemplos para comparar as linguagens de nível alto e baixo

Page 8: Revisão Compiladores – AP1

8

Exemplo em Baixo Nível

Programa Hello World em assembly x86

DOSSEG.MODEL SMALL.DATA Msg db "Hello World.",13,10,"$".CODEStart: mov AX, @DATA mov DS, AX lea DX, Msg mov AH, 9 int 21h mov ah, 4ch int 21hEND Start

Page 9: Revisão Compiladores – AP1

9

Exemplo em Alto Nível

Programa Hello World em C

#include <stdio.h>

int main() { printf(“Hello World”); return 0;}

Page 10: Revisão Compiladores – AP1

10

Linguagens de Baixo Nível

Características gerais

• Dependentes de arquitetura

• Oferecem instruções primitivas simples (operações sobre o hardware)

• Programas extensos e pouco legíveis

• Visam oferecer mais controle sobre o hardware

Page 11: Revisão Compiladores – AP1

11

Linguagens de Alto Nível

Características gerais• Especificadas independentemente de

qualquer arquitetura

• Oferecem comandos mais intuitivos- Dizem mais “o que” deve ser feito do que

“como” deve ser feito

• Mais fácil de programar e de ler códigos prontos

• Restringem o uso do hardware para evitar bugs- Controle da alocação de memória em Java

Page 12: Revisão Compiladores – AP1

Introdução a Compiladores

Page 13: Revisão Compiladores – AP1

13

Compilação x Interpretação

Compilação

Interpretação

compilaçãocódigofonte

códigode

máquina

execuçãoresultados

interpretaçãocódigofonte resultados

Page 14: Revisão Compiladores – AP1

14

O que é um Compilador?

Um compilador é um programa que lê um programa escrito em uma linguagem (linguagem fonte) e a traduz em um programa equivalente em outra linguagem (linguagem alvo). Aho, Sethi, Ullman.

CompiladorProgramaFonte

ProgramaObjeto

Page 15: Revisão Compiladores – AP1

15

O que é um Compilador?

Nesse processo de tradução, há duas tarefas básicas a serem executadas por um compilador:• análise, em que o texto de entrada (na

linguagem fonte) é examinado, verificado e compreendido

• síntese, ou geração de código, em que o texto de saída (na linguagem objeto) é gerado, de forma a corresponder ao texto de entrada

Page 16: Revisão Compiladores – AP1

16

O que é um Compilador?

A fase de análise normalmente se subdivide em análise léxica, análise sintática e análise semântica

É possível representar completamente a sintaxe de uma LP através de uma gramática sensível ao contexto

Mas como não existem algoritmos práticos para tratar essas gramáticas, a preferência recai em usar gramáticas livres de contexto

Deixa-se para a análise semântica a verificação de todos os aspectos da linguagens que não se consegue exprimir de forma simples usando gramáticas livres de contexto

Page 17: Revisão Compiladores – AP1

17

O que é um Compilador? A implementação de reconhecedores de

linguagens regulares (autômatos finitos) é mais simples e mais eficiente do que a implementação de reconhecedores de linguagens livres de contexto (autômatos de pilha)

Nesse caso, é possível usar expressões regulares para descrever a estrutura de componentes básicos das LP, tais como identificadores, palavras reservadas, literais numéricos, operadores e delimitadores, etc.

Essa parte da tarefa de análise (análise léxica) é implementada separadamente, pela simulação de autômatos finitos

Page 18: Revisão Compiladores – AP1

18

O que é um Compilador?

Um dos modelos possíveis para a construção de compiladores faz a separação total entre o front-end, encarregado da fase de análise, e o back-end, encarregado da geração de código, de forma que:• O front-end e back-end se comunicam apenas

através de uma representação intermediária• O front-end depende exclusivamente da linguagem

fonte• O back-end depende exclusivamente da linguagem

objeto

Page 19: Revisão Compiladores – AP1

19

Etapas da Compilação

Front-End(Análise)

Back-End(Síntese)

Análise Léxica

Análise Sintática

Analise Semântica

Geração de CódigoIntermediário

Geração de CódigoFinal

Page 20: Revisão Compiladores – AP1

20

O que é um Compilador?

Um compilador típico consiste de algumas fases onde cada uma passa sua saída para as fases seguintes

As principais fases são:• análise léxica (ou scanner)• análise sintática (ou parser)• análise semântica• otimização• gerador de código• otimização (novamente!)

Page 21: Revisão Compiladores – AP1

21

Fases da Compilação

Programa Fonte

Analisador Léxico

Analisador Sintático eSemântico

Gerador de CódigoIntermediário

Otimizador de Código

Gerador de código

Manipulador de erros

Tabela deSímbolos

Programa Objeto

Page 22: Revisão Compiladores – AP1

22

Análise Léxica Também chamada de scanner Agrupa caracteres em símbolos (ou tokens)

• Token: <nome-token, valor-atributo>

Entrada: fluxo de caracteres Saída: fluxo de símbolos Símbolos são:

• Palavras reservadas, identificadores de variáveis e procedimentos, operadores, pontuação, etc.

Expressões regulares usadas para reconhecimento

Scanner é implementado como uma MEF (Método dos Elementos Finitos)

Lex/Flex (J) são ferramentas para gerar scanners

Page 23: Revisão Compiladores – AP1

23

Análise Léxica Por exemplo, os caracteres na instrução

de atribuiçãoposition = initial + rate * 60

seriam agrupados nos seguintes tokens:• O identificador position• O símbolo de atribuição =• O identificador initial• O símbolo de adição +• O identificador rate• O símbolo de multiplicação *• O número 60

<id, 1> <=> <id, 2> <+> <id, 3> <*> <60>

Page 24: Revisão Compiladores – AP1

24

Análise Sintática

Também chamada de parser Agrupa símbolos em unidades sintáticas

• Ex.: os 3 símbolos A+B podem ser agrupados em uma estrutura chamada de expressão

Expressões depois podem ser agrupados para formar comandos ou outras unidades

Saída: representação de árvore sintática do programa

Gramática livre de contexto é usada para definir a estrutura do programa reconhecida por um parser

Yacc/Bison (J) são ferramentas para gerar parsers

Page 25: Revisão Compiladores – AP1

25

Análise Sintática Regras sintáticas (1)

• Qualquer identificador é uma expressão• Qualquer número é uma expressão• Se expressão1 e expressão2 são expressões,

então também são expressões- expressão1 + expressão2

- expressão1 * expressão2

- ( expressão1 )

Page 26: Revisão Compiladores – AP1

26

Análise Sintática Regras sintáticas (2)

• Se identificador1 é um identificador e expressão2 é uma expressão, então identificador1 = expressão2

é um comando (statement)• Se expressão1 é uma expressão e statement2

é um comando (statement), então while ( expressão1 ) { statement2 }if ( expressão1 ) { statement2 }

são comandos (statements)

Page 27: Revisão Compiladores – AP1

27

Análise Sintática

position = initial + rate * 60

initial

rate

*

+

=

position

60

comando de atribuição

identificador expressão

expressão expressão

expressãoidentificador

identificador

expressão

número

Page 28: Revisão Compiladores – AP1

28

Gerador de Código Intermediário Usa as estruturas produzidas pelo

analisador sintático e verificadas pelo analisador semântico para criar uma sequência de instruções simples (código intermediário)

Está entre a linguagem de alto nível e a linguagem de baixo nível

Page 29: Revisão Compiladores – AP1

29

Gerador de Código Intermediário Considere que temos um único

registrador acumulador Considere o comando de atribuição

x := a + b * c

pode ser traduzido em:t1 := b * ct2 := a + t1x := t2

Pode-se fazer um gerador de código relativamente simples usando regras como:

Page 30: Revisão Compiladores – AP1

30

Gerador de Código Intermediário

Page 31: Revisão Compiladores – AP1

31

Gerador de Código Intermediário O comando de atribuição

x := a + b * c Gera o códigoLoad b { t1 := b * c }

Mult c

Store t1

Load a { t2 := a + t1 }

Add t1

Store t2

Load t2 { x := t2 }

Store x

Page 32: Revisão Compiladores – AP1

32

Otimizador de Código

Independente da máquina Melhora o código intermediário de modo

que o programa objeto seja menor (ocupe menos espaço de memória) e/ou mais rápido (tenha tempo de execução menor)

A saída do otimizador de código é um novo código intermediário

Page 33: Revisão Compiladores – AP1

33

Otimizador de Código

Otimizador por sub-expressões comuns

Page 34: Revisão Compiladores – AP1

34

Gerador de Código

Produz o código objeto final Toma decisões com relação à:

• Alocação de espaço para os dados do programa;

• Seleção da forma de acessá-los• Definição de quais registradores serão usados,

etc.

Projetar um gerador de código que produza programas objeto eficientes é uma das tarefas mais difíceis no projeto de um compilador

Page 35: Revisão Compiladores – AP1

35

Gerador de Código

Várias considerações têm que ser feitas:• Há vários tipos de instruções correspondendo

a vários tipos de dados e a vários modos de endereçamento

• Há instruções de soma específicas, por exemplo para incrementar/decrementar de 1

• Algumas somas não foram especificadas explicitamente

- Cálculo de endereço de posições em vetores• Incremento/decremento registrador de topo

pilha• Local onde armazenar variáveis• Alocação de registradores

Page 36: Revisão Compiladores – AP1

36

Gerador de Código

temp1 = id3 * 60.0id1 = id2 + temp1

MOVF id3, R2MULF #60.0, R2MOVF id2, R1ADDF R2, R1MOVF R1, id1

Page 37: Revisão Compiladores – AP1

37

Tabela de Símbolos

É uma estrutura de dados usada para guardar informações a respeito de todos os nomes usados pelo programa e registrar informações importantes associadas a cada um, tais como seu tipo (inteiro, real, etc.), tamanho, escopo, etc.

Page 38: Revisão Compiladores – AP1

38

Manipulador de Erros

É ativado sempre que for detectado um erro no programa fonte

Deve avisar o programador da ocorrência do erro emitindo uma mensagem, e ajustar-se novamente à informação sendo passada de fase a fase de modo a poder completar o processo de compilação• Mesmo que não seja mais possível gerar

código objeto, a análise léxica e sintática deve prosseguir até o fim

Page 39: Revisão Compiladores – AP1

39

Bibliografia

AHO, A., LAM, M. S., SETHI, R., ULLMAN, J. D., Compiladores: princípios, técnicas e ferramentas. Ed. Addison Wesley. 2a Edição, 2008 (Capítulo 1)

Page 40: Revisão Compiladores – AP1

40

Adiantando...

Lexema: sequência de caracteres com significado interligado

Token: classificação dada ao lexema• Geralmente retornado junto com o próprio

lexema ou outro atributo, como um ponteiro

Padrão: é uma descrição da forma que os lexemas de um token podem tomar.

•Ex. sequência de caracteres que formam palavra-chave como um token.

Page 41: Revisão Compiladores – AP1

41

Exemplos

Page 42: Revisão Compiladores – AP1

42

Especificando Tokens

Geralmente são especificados com expressões regulares

Cada token é associado a uma expressão regular que representa seus lexemas válidos

• Padrão que representa várias palavras (dizemos que as palavras “casam” com o padrão)

Page 43: Revisão Compiladores – AP1

43

Especificando Tokens

Expressões Regulares• Formalismo utilizado para definir o conjunto de

aceitação de uma linguagem• Principais operadores utilizados pelas ERs

Expressão Reconhece

ε A cadeia de caractedes vazia “”

“str” A string “str”

A | B Todas as cadeias reconhecidas por A ou B

A . B Cadeias formadas pela concatenação das cadeias reconhecidas por A e B

A+ Reconhece cadeias formadas pela concatenação de um número finito de cadeias reconhecidas por A

Page 44: Revisão Compiladores – AP1

44

Especificando Tokens

Operadores derivados

Expressão Equivale a

( A ) Agrupamento de operadores

A* A+ | ε

A? A | ε

[A-Z] A | B | ... | Y | Z

A{N} A . A . A ... } N vezes

A{M,N} A . A . A ... } entre M e N vezes

AB A . B

abc String “abc”

Page 45: Revisão Compiladores – AP1

45

Especificando Tokens

Exercícios

• Defina expressões para expressar:- Número IP: \d{3}.\d{3} .\d{3} .\d{3}- Números naturais (e inteiros): \d{n} ou [0-9]{n}- Números de telefone (com DDD opcional): \([0-9]{2}\).[0-9]{4}.

[0-9]{4}- Horas: [012]\d:[0-5]\d- E-mails: [a-zA-Z0-9\._-]@[A-Za-z]+\\.[A-Za-z]+- Placa de Carro: [A-Z]{3}-\d{4}- CEP: \d{5}-\d{3} ou \d\d\d\d\d- URLs:

- Com http - (http|https)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

- Sem http - ([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?

Page 46: Revisão Compiladores – AP1

46

Análise Sintática

Alguns autores consideram que a análise sintática envolve tudo que diz respeito à verificação do formato do código fonte

• Inclui a análise léxica como subfase

• Visão mais coerente, porém o livro texto que usamos tem outra visão...

Page 47: Revisão Compiladores – AP1

47

Análise Sintática

Entenderemos análise sintática como sendo apenas a segunda fase dessa verificação de formato:

• “É a fase que analisa os tokens para descobrir a estrutura gramatical do código fonte”

• Também chamada “Reconhecimento” (Parsing)

• Porém, um nome melhor seria “Análise Gramatical”

Page 48: Revisão Compiladores – AP1

48

Gramáticas

São usadas para organizar os tokens em “frases” de sentido lógico

Definem regras de formação recursivas

expressão → CTE_INT

| ID

| expressão + expressão

Page 49: Revisão Compiladores – AP1

49

Gramáticas

As gramáticas livres de contexto possuem quatro elementos:

• Símbolos terminais• Símbolos não-terminais • Símbolo inicial• Produções! ou Regras de Produção!

Page 50: Revisão Compiladores – AP1

50

Gramáticas

Elementos das gramáticas livres de contexto:

• Símbolos terminais: - Símbolos assumidos como atômicos, indivisíveis- Em compiladores, são os tokens (int, +, -, /, identificador,

valores literais, etc)

• Símbolos não-terminais: - Usados para organizar os tokens em “frases”- Representam elementos abstratos do programa (expressões,

termos, etc)

Page 51: Revisão Compiladores – AP1

51

Gramáticas

Elementos das gramáticas livres de contexto:

• Símbolo inicial: - Não-terminal a partir do qual são derivadas

“cadeias” de símbolos terminais- Geralmente é um não-terminal chamado programa

• Produções: - São as regras de formação - Definem as “frases” de terminais válidas na

linguagem

Page 52: Revisão Compiladores – AP1

52

Derivação

Seja a gramática BNF anterior• Derivar a cadeia “i+i+x”

• Consideremos que esta é uma derivação mais à esquerda

<expressao>Þ <termo> + <expressao>Þ i + <expressao>Þ i + <termo> + <expressao>Þ i + i + <expressao>Þ i + i + <termo>Þ i + i + x

Page 53: Revisão Compiladores – AP1

53

Derivação

Seja a gramática BNF mostrada antes

• Agora a Derivação mais à direita da cadeia “i+i+x”

<expressao>Þ <termo> + <expressao> Þ <termo> + <termo> + <expressao>Þ <termo> + <termo> + <termo>Þ <termo> + <termo> + xÞ <termo> + i + xÞ i + i + x

Page 54: Revisão Compiladores – AP1

54

Derivação

O processo de derivação consiste em substituir cada ocorrência de um não-terminal pelo lado direito (corpo) de alguma de suas produções• Derivação mais à esquerda: substituir sempre

o não-terminal mais à esquerda• Derivação mais à direita: análogo

A derivação pára quando sobrarem apenas terminais e o resultado é a cadeia

Page 55: Revisão Compiladores – AP1

55

Árvore de Derivação

A árvore dos exemplos anteriores

expressao

expressao

i

+

i

+

x

termo

termo expressao

a cadeia gerada pode ser percebida nas folhas, analisando-as da esquerda para a

direita

termo

Page 56: Revisão Compiladores – AP1

56

Árvore de Derivação

A mesma árvore reorganizada

expressao

expressao

i + i + x

termo

termo expressao

a seqüência de terminais (cadeia) gerada

termo

Page 57: Revisão Compiladores – AP1

57

Gramáticas Ambíguas

Uma gramática é dita ambígua se ela puder gerar duas árvores de derivação distintas para uma mesma cadeia

Veremos uma gramática equivalente à anterior, porém ambígua...

Page 58: Revisão Compiladores – AP1

58

Gramáticas Ambíguas

Exemplo

• Mostrar duas árvores de derivação para “i+i+x”

<expressao> ::= <expressao> "+" <expressao> | "x" | "i"

Page 59: Revisão Compiladores – AP1

59

Gramáticas Ambíguas

Gramáticas ambíguas são, em geral, inadequadas para uso em compiladores

• Dificultam a construção do analisador sintático

Em alguns casos, são usadas gramáticas ambíguas junto com restrições adicionais

• Exemplo: precedência e associatividade

Page 60: Revisão Compiladores – AP1

60

Tratando Ambiguidades

A seguinte de definição de comando apresenta ambigüidade

Exemplo: “if (x) if (x) outro else outro”

• A qual “if” está ligado o “else”?

cmd ::= if ( expr ) cmd else cmd | if ( expr ) cmd | outro

expr ::= x

Page 61: Revisão Compiladores – AP1

61

Tratando Ambiguidades

Solução

cmd ::= matched-cmd | open-cmd

matched-cmd ::= | if ( expr ) matched-cmd else matched-cmd | outro

open-cmd ::= | if ( expr ) cmd | if ( expr ) matched-cmd else open-cmd

Page 62: Revisão Compiladores – AP1

62

Análise de Descida Recursiva

É uma análise sintática top-down ou descendente

É um parser LL(1)• Left-to-right – a ordem de leitura dos tokens é

da esquerda para a direita

• Leftmost derivation – segue a ordem típica de uma derivação mais à esquerda

• Só olha 1 token por vez

Page 63: Revisão Compiladores – AP1

63

Análise de Descida Recursiva

É útil para construir parsers manualmente, por ser fácil de implementar

Princípio Básico• Se eu quero produzir um não-terminal e sei qual o

terminal corrente eu devo saber que regra deve ser aplicada.

Porém, requer uma gramática muito bem ajustada

• Veremos os ajustes necessários

Mostraremos como usar a técnica, assumindo que o parser final será uma classe Java

Page 64: Revisão Compiladores – AP1

64

Exemplo de Reconhecedor Gramática:Terminais = {a,b,c}

Não-terminais = {S, X}

Produções = {

S a X b

S b X a

S c

X b X

X a

}

Não-terminal inicial = S

a b c

S a X b

b X a c

X a b X Error

Page 65: Revisão Compiladores – AP1

65

Conjunto FIRST

FIRST(α)

• Aplicado a cadeias α quaisquer

É o conjunto de terminais que podem iniciar a cadeia α dada

• Se a cadeia derivar vazio, também inclui ε

Como calcular?

Page 66: Revisão Compiladores – AP1

66

Conjunto FIRST

Se α for a cadeia vazia (α = ε)

• FIRST(ε) = { ε }

Se for um terminal a qualquer

• FIRST(a) = { a }

Se for um não-terminal N com as produções N → α | β

• FIRST(N) = FIRST(α) FIRST(β)

Page 67: Revisão Compiladores – AP1

67

Conjunto FIRST

Se for uma cadeia de símbolos α = X1X2...Xk • Depende de X1

Se X1 não pode gerar vazio• FIRST (X1X2...Xk) = FIRST(X1)

Se X1 pode gerar vazio• FIRST (X1X2...Xk) = FIRST(X1) FIRST(X2...Xk)• Calcula para X1 e continua o cálculo

recursivamente para o restante da cadeia

Page 68: Revisão Compiladores – AP1

68

Múltiplas Produções

Calculando o FIRST para as duas produções de comando ...

• comando ::= atribuição | declaração

FIRST(atribuição) = FIRST(IDENTIFICADOR = <expressao> ;) = { IDENTIFICADOR }

FIRST(declaração) = FIRST(tipo IDENTIFICADOR ;) = FIRST(tipo) = { int , char, float }

Page 69: Revisão Compiladores – AP1

69

Eliminação de Fatoração

Direta:X a b cX a d e

Sem fatoração:X a YY b cY d e

IndiretaX a bX Y cY a d

Elimina-se a indireção:X a bX a d cY a d

Sem fatoração:X a ZY a dZ bZ d c