Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. –...

96
Compiladores Marco A. Amaral Henriques DCA/FEEC/UNICAMP versão 2006

Transcript of Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. –...

Page 1: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Compiladores

Marco A. Amaral HenriquesDCA/FEEC/UNICAMP

versão 2006

Page 2: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Compilador• Programa que transforma texto escrito em

linguagem de alto nível (programa-fonte) em programa objeto.

ProgramaFonte Compilador Programa

Objeto

Page 3: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo Simples de Compilação• Compilação de trecho de programa

int a, b, valor;a = 100;b = a*(valor + 20);

• Compilador vê trecho como a sequênciaint a, b, valor;a = 100;b = a*(valor + 20);

• Sequência deve ser analisada lexicamente:– Agrupar caracteres em unidades elementares

• Itens Léxicos: palavras válidas da linguagem. |int|a|,|b|,|valor|; |a|=|100|;|b|=|a|*|(|valor| +|20|)|;|

Page 4: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo: Análise Sintática• Itens léxicos são analisados sintaticamente

– Agrupar itens léxicos em setenças válidas

• Código de máquina é gerado– Usando tabelas: uma entrada de código para cada operação

possível na linguagem (ineficiência).– Usando sistema formais:

• regras formais para construção e análise de sentenças,• algoritmos para analisar sentenças tornam-se viáveis.

int a , b , valor ; a = 100 ; b = a * (valor + 20 ) ;

Page 5: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Sistema Formal• Conjunto de palavras e de relações chamadas

regras de inferência.• Gramática Formal

– Permite especificar formalmente uma linguagem.– É uma quádrupla ordenada G=(N,T, Σ, P) onde

• T : conjunto de símbolos terminais : correspondem aos símbolos nos programas-fonte.

• P : conjuto de produções : regras de transformação de uma cadeia de caracteres em outra.

• N : conjunto de símbolos não-terminais : aparecem em estágios intermediários da geração de um sentença.

• Σ : símbolo não-terminal inicial .

Page 6: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de Gramática Formal

• Gramática G = (N, T, Σ, P):• N = {Σ, A, B}• T = { a , b }• P = {Σ --> AB;

A --> aA;A --> a;B --> Bb;B --> b; }

• Pode gerar sequências de caracteres do tipo anbm, com n, m > 0.

Page 7: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Tipos de Gramática

• De acordo com o número e o tipo de símbolos nos lados direito e esquerdo das produções, as gramáticas podem ser classificadas em quatro tipos distintos, segundo a hierarquia de Chomsky:– Tipo 0: Gramáticas redutíveis e dependentes do contexto– Tipo 1: Gramáticas irredutíveis e dependentes de contexto– Tipo 2: Gramáticas livres de contexto– Tipo 3: Gramáticas regulares

Page 8: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 0• Gramáticas redutíveis e dependentes do contexto

– Têm produções que expandem/reduzem o comprimento da sequência de caracteres, dependendo do contexto onde esta se insere.

– Não há restrições quanto ao tipo de produções:• qualquer tipo e quantidade de símbolos à esquerda ou à

direita.– Ex: aA → c

BBB → zCt BbC → aAAAAAA AAAaaaAAAa → x

Page 9: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 1• Gramáticas irredutíveis e dependentes de contexto

– Nenhuma produção diminui o número de caracteres da sequência, mas todas são dependentes do contexto onde está a mesma.

– Para produções na forma α → β, obrigatoriamente tem-se que |α| ≤ |β|, onde |x| indica o número de símbolos em x. Ou seja, a aplicação das produções aumenta ou mantem o tamanho da seqüência de símbolos, mas nunca o diminui.

– Ex: AaA → BBB AaaaA → AAAAAA Ccc → zCC

Page 10: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 2• Gramáticas livres de contexto

– Lado esquerdo das produções tem um único símbolo e assim não depende do contexto.

• Para todas as produções na forma α → β, obrigatoriamente tem-se que |α| = 1.

– Símbolo do lado esquerdo é símbolo não-terminal.– Ex: P = { B → aBbc ;

B → B ;C → xpto }

Page 11: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 3• Gramáticas regulares

– Livres de contexto e com restrições ao número máximo de símbolos acrescidos a cada produção.

– Podem ser modeladas como autômatos finitos.• Logo, existem algoritmos para implementá-las.

– Duas variantes:• Gramática Linear Direita:

– as produções são do tipo A → a ou A → aA• Gramática Linear Esquerda:

– as produções são do tipo A → a ou A → Aa

Page 12: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 3: características• São adequadas para definir formatos de

constantes, identificadores e palavras reservadas de uma linguagem → úteis na Análise Léxica– Ex: G = ({letra, digito}, {IDENT, RESTO},

P, IDENT ) P = { IDENT → letra | letra RESTO;

RESTO → letra |digito |letra RESTO |digito RESTO }

• Exercício: supondo que os símbolos terminais “letra” e “digito” sejam equivalentes a letras e dígitos respectivamente, forneça dois exemplos bem distintos de seqüências válidas e dois de seqüências inválidas na gramática acima.

Page 13: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Expressões Regulares (regexp)• Forma alternativa de se definir sentenças geradas

por gramáticas tipo 3.• As regexp clássicas de um alfabeto A podem ser:

– um elemento de A ou string vazia;– uma seqüência das regexps P e Q: PQ ;– uma escolha entre as regexps P e Q : P | Q (P ou Q) ;– zero ou mais ocorrências de P: P* .

• Ex: regexp que descreve um identificador: letra ( letra | digito )*

Page 14: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Tipo 3: limitações• Tanto as Gramáticas Tipo 3 como as regexps não

são adequadas para expressar sentenças que possuam limitadores balanceados, tais como ( ... (...) ... (...) ... ( ... (... ) ... ) ... )

• Entretanto, estas sentenças podem ser expressas facilmente por gramáticas livres de contexto como, por exemplo: S → ( S ) S → SS S → ε

Page 15: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramáticas Livres de Contexto• Mais utilizadas na etapa de análise sintática de

uma linguagem.• Possuem a propriedade da “autoincorporação”,

isto é possui pelo menos uma produção da forma A → α1 A α2 onde A é um símbolo não-terminal e α1 , α2 são seqüências não vazias de símbolos terminais.

• Obs: uma gramática livre de contexto que não possua a propriedade acima descrita pode ser convertida a uma gramática regular.

Page 16: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Representação de Gramáticas Livres de Contexto

• Toda gramática livre de contexto equivale a uma gramática na Forma Normal de Chomsky, onde todas as produções podem ser escritas na forma

A → BC A → a

– Lado esquerdo da produção: símbolo não-terminal– Lado direito da produção: expansão do símbolo da

esquerda, contendo símbolos terminais e/ou não-terminais

Page 17: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Notação BNF (Backus-Naur Form)• Representação textual de gramáticas livres de contexto

– operador binário ::= para descrever produções– colchetes angulares < e > para símbolos não-terminais

• Ex: <exp> ::= <exp> <termo>– operador OU | : produções alternativas (Ex: <S> ::= a | b )– operador para símbolos opcionais [ ]

• Ex: <S> ::= [ a ] equivale a <S> ::= a ou <S> ::= ε– operador de fatoração ( | )

• Ex: <S> ::= a (b | c) d equivale a <S> ::= abd ou <S> ::= acd– operador de repetição *

• Ex: <S> ::= a* equivale a <S> ::=ε ou <S> ::= a <S>– operador de concatenação { || }* para repetição múltipla

• Ex: <S> ::= {a||b}* equivale a <S>::=a <T> e <T> ::=ε ou <T> ::=ba <T>

Page 18: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Tarefas Iniciais do Compilador• Análise Léxica

– Reconhecer os itens léxicos (tokens) do programa.– Atribuir identificador a cada item léxico.

• Análise Sintática– Validação da estrutura formada pelos itens léxicos.– Procura construir uma árvore sintática com os itens.

• Análise Semântica– Normalmente é implementada junto com a análise sintática.– Extrai informações da árvore sintática para sintetizar código

de máquina.• Consistência entre declaração e uso de variáveis.• Reserva de memória para variáveis.

Page 19: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Tarefas Finais do Compilador• Geração de Código Intermediário

– Tradução de cada nó da árvore sintática em instruções de máquina.

• Há compiladores que geram código em linguagem assembly.– Formalização da gramática de linguagem de máquina é difícil.

• Rotinas de tradução ainda são especificadas manualmente.

• Otimização– Modificação do código e estruturas de dados gerados para

minimizar tempo de execução e espaço requerido.– Desempenho de otimizador depende da criatividade de seu

projetista.

Page 20: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Análise Léxica• Reduz uma sentença a conjunto de itens léxicos.• Classifica itens léxicos.

– Distingue os tipos aceitos por uma gramática.– Classes mais comuns

• identificadores de variáveis• símbolos ou palavras reservadas (for, switch, etc em C)• literais ou constantes• símbolos especiais (símbolos de controle)• marcador de fim de arquivo

– Cada novo item léxico recebe um identificador e é guardado na Tabela de Terminais.

Page 21: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Autômatos Finitos na representação de itens léxicos

• Itens léxicos normalmente representáveis por:– gramáticas regulares (Tipo 3) ou– expressões regulares (regexp)• Existe correspondência unívoca entre gramáticas

(expressões) regulares e autômatos finitos.• Autômatos finitos: quádrupla M = (K, Σ, δ, S, F)– K: conjunto finito de estados– Σ: alfabeto de entrada finito– δ: conjunto de transições– S: estado inicial (S ∈ K)– F: conjunto de estados finais (F ⊆ K)

Page 22: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Representação de Autômatos Finitos• AFs são representados por grafos dirigidos,

denotando as transições entre os estados.• Círculos representam os estados.

– Círculos duplos representam estados finais.• Transições: representadas por triplas (si , ΣT , sf ):

– si : estado inicial da transição– ΣT : conjunto de símbolos do alfabeto que disparam a

transição quando o estado é si – sf : estado do autômato após a transição

asisf

Page 23: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Representação de autômatos por tabelas de transição

• Forma mais prática de implementação.• Colunas representam os estados.• Linhas representam os símbolos do alfabeto de

entrada.• Cada célula da tabela indica o estado final de

uma transição a partir do estado indicado na coluna após a entrada do símbolo indicado na linha.

. . . si . . .

. . . . . . . . .

. . . sf . . .

. . . . . . . . .

. . .

. . .

a

Page 24: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Tipos de Autômatos• Determinísticos

– para cada par (estado, entrada) existe apenas uma transição aplicável.

• Não-determinísticos– para cada par (estado, entrada) existe mais de uma

transição aplicável.• A todo AF não-determinístico corresponde um

AF determinístico que representa (aceita) a mesma linguagem.– Logo, é possível transformar um AF não-

determinístico por um AF determinístico sem perda de funcionalidade.

Page 25: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Construção de autômato finito não-determinístico

• Algoritmo de Thompson– constrói AFs não determinísticos para reconhecer

sentenças de uma gramática regular.• Primeiro passo: decompor a expressão regular

em termos de suas relações elementares:– um símbolo do alfabeto da linguagem,– uma concatenação tipo RS,– uma alternativa tipo R | S ,– uma repetição tipo R .

• Segundo passo: construir um autômato finito que reconheça cada uma destas relações elementares.

Page 26: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Autômatos Finitos Elementares

i

f

f

f

f

ii

i

M1

M1

M1

M2

M2

a

ε

εεε

εε

ε

ε

Reconhecimento do símbolo a Concatenação

RepetiçãoAlternativas

(estado final de M1 e inicial de M

2)

(string vazia)

Autômato M

Page 27: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção deAF não-determinístico

• Construção do autômato finito que reconheça a expressão regular R = (a | b)* abb.

• Relações elementares:R

1 = a

R2 = b

R3 = R

1 | R

2

R4 = R

3 *

R5 = R

4 R

1

R6 = R

5 R

2

R = R

6 R

2

Page 28: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção deAF não-determinístico: resultado

5 6ε

εε

ε410 117

1

3

2

8 9ε ε

ε

ε

a

bb ba

R = (a|b)*abb

Page 29: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Conversão de AF não-determinístico a AF determinístico

• AFs não-determinísticos são ambíguos.• Conversão baseada na construção de subconjuntos.

– Subconjunto ε*(T): inclui os estados em T e todos os demais alcançáveis a partir deles por entradas vazias.

– Determina-se ε*(T0) para T

0 contendo os estados iniciais do

AF não-determinístico (estados originais).– Subconjunto ε*(T

0) é o estado inicial s

0 do AF

determinístico.– Analisa-se ε*(T

0) para cada entrada possível, obtendo-se T

1,

T2 etc. e repete-se o procedimento com

s1 = ε*(T

1), s

2 = ε*(T

2) etc.

– Subconjunto si = ε*(T

i) será um estado final do AF

determinístico se Ti contiver um estado final original.

Page 30: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Resultado da conversãopara AF determinístico

s0

s1

s3

s4s

2

a

b a a

bb

b

b

a

a

Grafo Tabela

entr.

a

b

s0

s1

s2

s3

s4

s1

s1

s1

s1

s1

s2

s3

s2

s4

s2

R = (a|b)*abb

Page 31: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Minimização de estados• Se existirem vários AFs reconhecendo uma mesma

sentença, alguns estados de alguns AFs podem ser desnecessários.

• Para minimizar o número de estados de um AF:– divide-se o grupo de estados S em um subgrupo G

1

contendo todos os estados finais (F) e outro G2

contendo os estados não-finais (S-F);– faz-se nova divisão em cada subgrupo, considerando

que um novo subgrupo Gi só conterá os estados s e t, se

todas as transições partindo de s e de t, levam sempre a um mesmo subgrupo;

– repete-se a divisão para os novos subgrupos até que não seja mais possível dividir.

Page 32: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Resultado da minimizaçãodo AF determinístico

s1

s3

s4s

0

a a

bb

b

b

a

a

Grafo Tabela

entr.

a

b

s0

s1

s3

s4

s1

s1

s1

s1

s2

s3

s4

s2

R = (a|b)*abb

Page 33: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Analisador Léxico• É um programa que implementa um autômato

finito para reconhecer ou rejeitar seqüência de símbolos σ de uma linguagem.

• Sejam os seguintes procedimentos auxiliares:

S0 = ESTADO_INICIAL(M): retorna o estado inicial do

autômato M;

Resp = ESTADO_FINAL(M,Si): indica se estado S

i é

elemento do conjunto de estados finais do autômato M;

Si+1

= PRÓXIMO_ESTADO(M, Si , símbolo): retorna o

próximo estado do autômato M, quando se encontra no estado S

i e recebe a entrada símbolo.

Page 34: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Algoritmo de Analisador Léxico

SCANNER(M,σ)s = ESTADO_INICIAL(M)while true do

if É_VAZIO(σ)then if ESTADO_FINAL(M,s)

then return trueelse return false

else c = REMOVA_O_PRIMEIRO(σ)s = PROXIMO_ESTADO(M, s, c)if s = NULL

then return false

Page 35: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Geradores de Analisadores Léxicos• Conjunto de programas para construção

automática de analisadores léxicos.• Podem não gerar analisadores eficientes.• Geradores mais comuns: lex e flex

– Formato geral de gramática em lex definida em arquivo com extensão .l :

definições%% <== divisão de seção no arquivoregras%% <== divisão de seçãorotinas do usuário

Page 36: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Seção de Regras do LEX• Define a funcionalidade do analisador léxico

através de regras (produções da gramática).• Cada regra é um par padrão-ação.• Regras:

– expressões regulares (regexps) indicam uma sequência válida de caracteres;

– expressões regulares são descritas por uma linguagem definida por lex;

– a ação associada a cada regra é um bloco de código C que será executado sempre que a seqüência de símbolos de entrada for reconhecida pela regexp;

Page 37: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Linguagem de regexps em lexO p e r a d o r S i g n i f i c a d o E x e m p l o

? e x p r e s s ã o a n t e r i o r é o p c i o n a l 1 0 ? 9 < = > 1 0 9 o u 1 9* q u a l q u e r r e p e t i ç ã o , i n c l u s i v e 0 a * < = > { 0 , a , a a , a a a , . . . }+ q u a l q u e r r e p e t i ç ã o , e x c l u i n d o 0 a + < = > { a , a a , a a a , . . . }

| a l t e r n a t i v a a | b < = > a o u b( ) a g r u p a m e n t o d e e x p r e s s õ e s

• q u a l q u e r c a r a c t e r , e x c e t o l i n e f e e d^ i n í c i o d e l i n h a , m a s s e e s t i v e r e n t r e [ ]

s i g n i f i c a c o m p l e m e n t o[ ] q u a l q u e r c a r a c t e r d e n t r e o s e s p e c i f i c a d o s [ a b c ] < = > { a , b , c }

- f a i x a d e v a l o r e s [ 0 - 9 ] < = > { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }{ } n ú m e r o d e r e p e t i ç õ e s p o s s í v e i s a { 1 , 2 } < = > { a , a a }

\ E s c a p e s c a r a c t e r s e g u i n t e o ur e p r e s e n t a c a r a c t e r e s n ã o i m p r i m í v e i s .

\ • < = > •\ t < = > t a b u l a ç ã o

Page 38: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Seção de Definições do LEX• Pode conter:

– Macrosdigito [0-9]frac .[0-9]+

– Linhas de comando em C, sempre delimitadas por %{ e %} .

%{#include <classes.h>#define NUMBER 400%}

Page 39: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de Geração de Analisador Léxico

Gramática G=(N,T,Σ,P)

N = {Σ, <IDN>, <INT>, <REAL>, <SIMB_ATR>,<SIMB_MUL>,<SIMB_DIV>, <SIMB_SOM>,<SIMB_SUB>, <SIMB_POT>,<SIMB_PA1>,<SIMB_PA2>, <BL>, <seq>, <digito>, <letra>,<exp> }

T = {0,1,2,3,4,5,6,7,8,9, . ,a,b,c,...,z,A,B,C,...,Z,+,-,*,/,(,),=,”\n”,”\t”,” ”}

Page 40: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Produções da Gramática Exemplo• P = { Σ ::= <BL><exp>;

<exp> ::= <IDN>|<INT>|<REAL>|<SIMB_ATR>|<SIMB_MUL>|<SIMB_DIV>|<SIMB_SOM>|<SIMB_SUB>|<SIMB_POT> ;

<IDN> ::= <letra> <seq>; <BL> ::= “\t”<BL> | “ ”<BL> | “\t” | “ ” ; <seq> ::= <letra> <seq> | <digito> <seq> | <letra> | <digito>; <INT> ::= <digito> <INT> | <digito> ; <REAL> ::= <digito> <REAL> | .<INT> ; <SIMB_MUL> ::= * ;

<SIMB_DIV> ::= / ; <SIMB_SOM> ::= + ; <SIMB_SUB> ::= - ;

<SIMB_POT> ::= *<SIMB_MUL> ; <SIMB_ ATR> ::= = ; <SIMB_PA1> ::= ( ; <SIMB_PA2> ::= ) ; <digito> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ; <letra> ::= a | b | c | d | . . . | A | B | C | D | . . . | Z | “\n” }

Page 41: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Criação de Arquivo .l %{

#defineIDN 257#defineINT 258#defineREAL259. . .%}%%[a-zA-Z] | [a-zA-Z][a-zA-Z0-9]+ {/* Ação Semântica 1 */

printf(“Token da classe <Identificador> \n”); return IDN; }

[0-9]+ {/* Ação Semântica 2 */ printf(“Token da classe <Inteiro> \n”); return INT; }

[0-9]+\ . [0-9]+ |\ . [0-9]+ {/* Ação Semântica 3 */

printf(“Token da classe <Racional> \n”); return REAL; } . . .

Page 42: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Rotinas do Usuário em Arquivo .lSeção de definições%%Seção de regras%%Seção de rotinas do usuário#include <stdio.h>main(int argc, char *argv) {

int val;while (val = yylex( ))

printf(“valor = %d \n”, val);}

Page 43: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Utilização do Analisador Léxico• Assumindo que o arquivo .l se chama teste.l :

> lex teste.l• Tal comando gera um programa lex.yy.c que aceita

sequência de caracteres e retorna itens léxicos.• Programa lex.yy.c deve ser compilado

> cc -o teste lex.yy.c -ll • Exemplo de uso: > teste a=7.02 resultará em

Token da classe <Identificador>valor = 257Token da classe <Operador de atribuição>valor = 261Token da classe <Racional>valor = 259

Page 44: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Análise Sintática• Gramáticas do Tipo 3 (gramáticas regulares) não

são adequadas para identificar a forma como os itens léxicos estão combinados (análise sintática).

• Gramáticas do Tipo 2 (gramáticas livres de contexto) são mais adequadas para representar as regras de uma linguagem de programação e, portanto, podem ser usadas em análisadores sintáticos (parsers).– Nem todas as construções de uma linguagem de

programação podem ser representadas diretamente, mas por meio de reconhecedores de sentenças livres de contexto e algumas estratégias heurísticas é possível automatizar a etapa da análise sintática.

Page 45: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Reconhecimento de sentenças

• Procura-se “reduzir” a sentença de símbolos terminais até se alcançar o símbolo não-terminal inicial (processo inverso da derivação ou expansão).

• Caso o símbolo não-terminal inicial não seja alcançável por nenhuma combinação das regras da gramática, a sentença é considerada inválida.– Neste caso é preciso tentar todas as combinações de

regras possíveis até que não haja mais nenhuma combinação não tentada.

Page 46: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de reconhecimento• Seja a gramática G=(N,T, <E>, P), onde:

N = {<E>, <T>, <F>} T = {+, ×, id , ( , ) }

P = { <E> ::= <E> + <T> | <T> ;

<T> ::= <T> × <F> | <F> ;

<F> ::= ( <E> ) | id }

• A sentença (id + id) id não pode ser reduzida

nesta gramática, mas (id + id) × id pode.

Page 47: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Derivações Canônicas• Há diversas opções para a seqüência de aplicação

das regras, algumas reconhecendo a sentença e outras não.

• Derivações Canônicas são formas sistemáticas de aplicação das regras gramaticais.– Derivação mais à esquerda (leftmost derivation):

aplicar uma regra de derivação ao símbolo não-terminal mais à esquerda.

• Seqüência de reconhecimento mais à esquerda– Derivação mais à direita (rightmost derivation):

seleciona-se o símbolo não-terminal mais à direita para aplicação da regra de derivação.

• Seqüência de reconhecimento mais à direita

Page 48: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplos de Derivações Canônicas Derivação mais à esquerda

<E>::= <T>::= <T> × <F>::= <F> × <F>::= (<E>) × <F>::= (<E> + <T>) × <F>::=(<T> + <T>) × <F>::=(<F> + <T>) × <F>::=(id + <T>) × <F>::=(id + <F>) × <F>::=(id + id) × <F>::=(id + id) × id

Derivação mais à direita

<E>::= <T>::= <T> × <F>::= <T> × id::= <F> × id::= (<E>) × id::= (<E> + <T>) × id::= (<E> + <F>) × id::= (<E> + id) × id::= (<T> + id) × id::= (<F> + id) × id::= (id + id) × id

Page 49: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Árvores Sintáticas ou Gramaticais• Representação para derivações de uma sentença a partir

do símbolo inicial Σ.• Símbolo Σ ocupa raiz da árvore.• Símbolos terminais ocupam folhas da árvore.• Símbolo não-terminal <S> corresponde à raiz de uma

sub-árvore.– Ex: se <S> ::= X1X2X3...Xn , então <S> é uma sub-árvore da

gramática.<S>

X1 X2 X3 Xn. . .

Page 50: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplos de árvores sintáticas

Page 51: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Formas de reconhecimento• Reconhecimento pode ser visto como:

– leftmost parse: encontrar uma seqüência de reconhecimento mais à esquerda

ou

– rightmost parse: encontrar uma seqüência mais à direita

ou

– construção de uma árvore sintática.

Page 52: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramática Ambígua• Gramática livre de contexto na qual existe mais de

uma árvore sintática para uma mesma sentença.• Ex: gramática G=(N,T,Σ,P)

• N = {Σ , <inteiro>}• T = { 1 , 0 }• P = {Σ ::= <inteiro>; <inteiro> ::= <inteiro> <inteiro>; <inteiro> ::= 1; <inteiro> ::= 0 }tem duas árvores para sequência 101.

Page 53: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Gramática Não-ambígua• Só há uma árvore sintática por sentença.• Permite geração de mais de uma derivação para uma

mesma sentença, dependendo da ordem de substituição dos símbolos não-terminais (problema de precedência).

• Formas naturais de escolha do símbolo– substituir o mais à esquerda

• Gramáticas LL : input from Left, Leftmost derivation– substituir o mais à direita

• Gramáticas LR : input from Left, Rightmost derivation

• Às vezes pode ser obtida de gramática ambígua, mas não existe algoritmo que determine se uma dada gramática é ou não é ambígua.

Page 54: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de Gramática Não-ambígua• Gramática G=(N,T,Σ,P)

• N = {Σ, <inteiro> , <digito>}• T = { 1 , 0 }• P = { Σ ::= <inteiro> ;

<inteiro> ::= <inteiro> <digito> ;<inteiro> ::= <digito> ;<digito > ::= 1 ;<digito > ::= 0 }

tem somente uma árvore para sequência 101.

Page 55: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Analisadores Sintáticos• Constroem a árvore sintática correspondente à

sentença sob análise.• Duas formas de contrução:

– ascendente (bottom-up): parte das folhas para a raizou

– descendente (top-down): parte da raiz e tenta chegar até as folhas.

• Ex: seja a função REDUZIR(G,α) que retorna o símbolo não-terminal à esquerda de uma produção da gramática G cujo lado direito contenha α.

Page 56: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção ascendentePARSER_ASCENDENTE(G,α)

declare s : Símbolowhile true do s ← REMOVER_PRIMEIRO(α)

if s = OBTER_NÃO_TERM_INICIAL(G) e ESTA_VAZIA(α)

then return trueelse INSERIR(α, s)

α ← REDUZIR(G,α) if ESTA_VAZIA(α)

then return false

Page 57: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Analisador de deslocamento e redução• Baseia-se na técnica de construção ascendente para

reconhecer sentenças válidas.• Símbolos terminais da sentença são lidos um a um.• A cada símbolo lido, analisador decide se:

– lê um novo símbolo (desloca o ponteiro para o próximo da sentença) ou

– aplica uma produção da gramática aos símbolos já lidos, reduzindo-os a um símbolo não-terminal.

• Sua peça fundamental é a Tabela de Deslocamento e Redução (Shift-Reduce Table)

Page 58: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Tabela SR• A Tabela SR (Shift-Reduce) é baseada nas

relações de precedência simples entre os símbolos da gramática.

• As relações de precedência são:

X Y : X confere precedência a Y

e

X > Y : X tem precedência sobre Y.

Page 59: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Regras para relações “confere precedência”

• Regra 1: $ ∑ , isto é, delimitador de sentença confere precedência ao símbolo não-terminal inicial.

• Regra 2: se existe alguma produção de G na forma α → βXYμ, então diz-se que XY.

• Regra 3: se X α , onde α é um símbolo não-terminal, e existe uma produção para α em G onde Y é o primeiro símbolo do lado direito (α→Yμ), então diz-se que XY.

Page 60: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Regras para relações “tem precedência sobre”

• Regra 4: ∑ > $ , isto é, símbolo não-terminal inicial tem precedência sobre delimitador de sentença.

• Regra 5: se, para algum símbolo não-terminal α, existe a relação α Y e existe uma produção para α cujo último símbolo é X (α → βX), então diz-se que X > Y.

• Regra 6:se, para algum símbolo não-terminal α, existe a relação α > Y e existe uma produção para α cujo último símbolo é X (α → βX), então diz-se que X > Y.

• Regra 7: se, para algum símbolo não-terminal α, existe a relação X > α e existe uma produção para α cujo primeiro símbolo é Y (α → Yμ), então diz-se que X > Y.

Page 61: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Observações sobre regras de precedência

• Não se deve confundir as relações de precedência com as relações “maior que” ou “menor que”, pois podem surgir situações que aparentemente não fariam sentido. Por exemplo:– XY não implica que Y>X ;– é possível encontrar gramáticas em que XY ocorre

ao mesmo tempo que YX ;– é possível encontrar gramáticas em que XY ocorre

ao mesmo tempo que X>Y .

Page 62: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Formação da Tabela SR• Gramática é estendida com a inclusão do símbolo $

que serve para indicar início e fim de sentença.• Regras de 1 a 7 são aplicadas à gramática.• Para toda relação Xa, a tabela deverá indicar que

deve ser buscado o próximo símbolo da sentença.– X é um símbolo qualquer e a é um símbolo terminal.

• Para toda relação X>a, a tabela deverá indicar que é possível fazer uma redução nos últimos símbolos lidos da sentença.

• Para os pares (X,a) de símbolos sem relação de precedência definida, a tabela deverá estar em branco.

Page 63: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção de Tabela SR• Seja a gramática G=(N,T, <E>, P), onde:

N = {<E>, <T>, <F>} T = {+, ×, id , ( , ) } P = { <E> ::= <E> + <T> | <T> ;

<T> ::= <T> × <F> | <F> ;<F> ::= ( <E> ) | id }

• Pela Regra 1: $E• Pela Regra 2: E+ +T T×

×F (E E)• Pela Regra 3: $E $T +T +F ×(

×id (E (T $F +( +id (F $( $id (( (id

Page 64: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção de Tabela SR (cont.)

• Seja a gramática G=(N,T, <E>, P), onde:N = {<E>, <T>, <F>} T = {+, ×, id , ( , ) } P = { <E> ::= <E> + <T> | <T> ;

<T> ::= <T> × <F> | <F> ;<F> ::= ( <E> ) | id }

• Pela Regra 4: E>$

• Pela Regra 5: T>+ F>× T>)• Pela Regra 6: T>$ F>+ )>× id>×

F>) F>$ )>+ id>+ )>) id>) )>$ id>$

Page 65: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de construção de Tabela SR (cont.)

id + × ( ) $$ S SE S S R*T R S R RF R R R Rid R R R R+ S S× S S( S S) R R R R

indica reconhecimentoda sentença

indica combinaçãoerrônea de símbolos

Page 66: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Geradores de Analisadores Sintáticos

• Ferramentas similares e complementares aos geradores de analisadores léxicos.

• Ferramentas mais comuns: yacc (yet another c compiler) e bison.– lex gera a função yylex( ) que retorna o identificador

de um item léxico reconhecido.– yacc gera a função yyparse( ), que analisa os itens

léxicos e decide se eles formam ou não uma sentença válida.

Page 67: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Passos para Gerar Analisador Sintático• Escrever programa analisador léxico ou usar

ferramenta lex para tal.• Escrever gramática da linguagem em arquivo

com extensão .y .• Escrever programa analisador sintático ou usar a

ferramenta yacc para tal.• Compilar e ligar os programas-fonte.

– Para yylex( ) e yyparse( ) trabalharem em conjunto é preciso garantir que os tokens e seus valores sejam comuns às duas funções.

Page 68: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Formato Geral da Gramática de yacc

• Similar ao da gramática de lex– Três seções no arquivo .y :

definições (declaração de nomes e tipos de tokens, de variáveis etc)

%%regras (contém as produções da gramática em BNF:

símbolo ::= derivações {ações semânticas} )%%rotinas do usuário (contém a função principal

main( ) e outras rotinas do usuário)

Page 69: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de Geração de Analisador Sintático

• Gramática G = (N,T,<stat>,P)N = {<stat> , <expr> , <termo> , <fator> }

T = { INT , REAL , IDN , ( , ) , + , - , * , / }

P = { <stat> ::= <expr>; <expr> ::= <expr> (+ | - ) <termo> | <termo> ; <termo> ::= <termo> ( * | / ) <fator> | <fator> ; <fator> ::= INT | REAL | IDN | ( <expr> ) }

Page 70: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Criação de Arquivo .y%token IDN%token INT%token REAL%token SIMB_ATR%token SIMB_PA1%token SIMB_PA2%token SIMB_MUL%token SIMB_DIV%token SIMB_SOM%token SIMB_SUB%token SIMB_POT%token SIMB_END%start stat

%%stat: SIMB_END | expressao SIMB_END { /* Ação Semântica 0 */ printf("<stat> ::= <expressao> SIMB_END\n"); exit(1); } ;

expressao: termo { /* Ação Semântica 1 */

printf("<expr> ::= <termo> \n"); } | expressao SIMB_SOM termo { /* Ação Semântica 2 */

printf("<expr> ::= <expr> + <termo>\n"); } | expressao SIMB_SUB termo { /* Ação Semântica 3 */

printf("<expr> ::= <expr> - <termo>\n"); } ;/* demais regras devem ser incluídas . . . */%%main( ) {

yyparse( );}

Page 71: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Utilização do Analisador Sintático• Função main( ) deve ser retirada do analisador

léxico, para que somente uma exista no conjunto .• Analisador sintático y.tab.c é gerado por

> yacc teste.y (usando o nome teste para o arquivo .y )• Os programas-fonte devem ser compilados e

ligados, formando o executável analisador .> gcc -o analisador y.tab.c lex.yy.c -ll -ly

Page 72: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Usando o Analisador Sintático> analisador93 + (122)Token da classe <Inteiro><fator> ::= INTToken da classe <Op. Soma>Token da classe <Abre parênteses>Token da classe <Inteiro><fator> ::= INTToken da classe <Fecha parênteses><fator> ::= ( <expr> )<expr> ::= <expr> + <termo><stat> ::= <expr> SIMB_END

Page 73: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Análise Semântica noAnalisador Sintático

• Ações semânticas podem ser atribuídas às produções da gramática– Gramática se torna gramática com atributos.– Exemplo

Produção Ação Semântica<expr> ::= <termo> Atribuir valor de <termo> a <expr> .<expr> ::= <termo> (+|-) <termo>

Valor de <expr> é a soma/subtração dos valores dos filhos.<termo> ::= <fator> Atribuir valor de <fator> a <tarmo> .<termo> ::= <fator> (*|/) <fator>

Valor de <termo> é o produto/divisão dos valores do filhos.<fator> ::= <expr> Atribuir valor de <expr> a <fator> .<fator> ::= <INT> Atribuir valor do token léxico <INT> a <fator> .

• Não existe gerador “universal” para analisadores semânticos.– É possível aproveitar gerador de analisadores sintáticos para definir ação

atribuída a cada produção.

Page 74: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Criação de Arquivo .y%token IDN%token INT%token REAL%token SIMB_ATR%token SIMB_PA1%token SIMB_PA2%token SIMB_MUL%token SIMB_DIV%token SIMB_SOM%token SIMB_SUB%token SIMB_POT%token SIMB_END%start stat

%%stat: SIMB_END | expressao SIMB_END { /* Ação Semântica 0 */ printf("Resultado = %d \n", $1); exit(1); } ;

expressao: termo { /* Ação Semântica 1 */ $$ = $1; } | expressao SIMB_SOM termo { /* Ação Semântica 2 */ $$ = $1 + $3; printf("Soma de %d e %d = %d \n", $1, $3, $$); } | expressao SIMB_SUB termo { /* Ação Semântica 3 */ $$ = $1 - $3;

printf("Diferença de %d e %d = \n", $1, $2, $$); } ;/* demais regras devem ser incluídas . . . */%%main( ) {

yyparse( );}

Page 75: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Utilização do Analisador Sintático-Semântico

• É a mesma adotada para o analisador sintático:• Cria-se o analisador y.tab.c através de

> yacc teste.y (usando o nome teste para o arquivo .y )• Compila-se e liga-se os programas-fonte y.tab.c e

lex.yy.c , para gerar arquivo executável analisador .> gcc -o analisador y.tab.c lex.yy.c -ll -ly

Page 76: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de uso do Analisador Sintático-Semântico

> analisador103 - (54 + 9)Token da classe <Inteiro>Token da classe <Op. Subtração>Token da classe <Abre parênteses>Token da classe <Inteiro>Token da classe <Op. Soma>Token da classe <Inteiro>Token da classe <Fecha parênteses>Soma de 54 e 9 = 63Diferença de 103 e 63 = 40Resultado = 40>

Page 77: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Análise Semântica• É difícil verificar por meio de gramáticas:

– se todas as variáveis estão declaradas;– se variáveis estão sendo usadas com o tipo no qual

foram declaradas.• Análise semântica cuida do inter-relacionamento

entre partes distintas do programa.• Tarefas básicas:

– verificação de tipos de variáveis;– verificação de fluxo de controle;– verificação de unicidade de declaração de variáveis;– outras tarefas, dependendo da linguagem.

Page 78: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplos de Análise Semântica- verificação de tipos -

• Na compilação com gcc do código em C:int teste(int a, float b){

return a%b;}

teríamos o seguinte erro:In function 'teste':...: invalid operands to binary %

acusado pelo analisador semântico, pois o operador “ % ” (módulo) não admite operando real.

Page 79: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplos de Análise Semântica- verificação de fluxo de controle -

• Na compilação com gcc do código em C:void teste(int i, int j){

if (j == k)break;

elsecontinue; }

teríamos os seguintes erros:In function 'teste':...: break statement not within loop or switch...: continue statement not within a loop

acusados pelo analisador semântico, pois o comando break só pode ser usado dentro de um laço ou no final de um switch-case, e o continue só pode ser usado em laços.

Page 80: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplos de Análise Semântica- verificação de unicidade -

• Na compilação com gcc do código em C:void teste(int k){

struct { int a;float a;} x;

float x;switch (k){

case 0x31: x.a = k;case '1': x = x.a; }

teríamos os seguintes erros:In function 'teste':...: duplicate member 'a'...: previous declaration of 'x'...: duplicate case value

Page 81: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Conversão automática de tipos• Vários compiladores fazem conversão

automática de tipos quando encontram alguma incompatibilidade.– Conversão conhecida também como coerção ou cast.

• Exemplos: codigo = codigo – '0'

– a constante '0' é convertida do tipo char para o tipo int antes de se resolver a expressão aritmética.

medida = 5.9 + 2

– a constante inteira 2 é convertida do tipo int para o tipo float antes de se resolver a expressão aritmética.

Page 82: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Conversão manual de tipos• O programador pode controlar as conversões de

tipos manualmente por meio dos operadores de molde.– Coloca-se o nome do tipo desejado entre parênteses

antes da expressão cujo resultado deve ser convertido.• Ex. 1: int a, *ponteiro;

a = ponteiro;

– compilando as linhas acima obteríamos:warning: assignment makes integer from pointer without a cast

• Ex. 2: int a, *ponteiro; a = (int) ponteiro;

– neste caso não obteríamos nenhum alerta, pois o tipo de ponteiro seria convertido para int antes da atribuição.

Page 83: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Geração de Código

• Geração ótima de código não é factível.• Geração de código orientada a sintaxe:

– adicionar à gramática as ações que escrevem num arquivo a sequência de instruções adequadas a cada redução.

• Normalmente feita em duas etapas:– geração de código intermediário com base em processador fictício;– conversão do código intermediário em código definitivo para o

processador alvo.• Tipos de código intermediário:

– notação posfixa– código de três endereços

Page 84: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços• Composto por instruções com operações unárias,

operações binárias e uma atribuição.– Instruções envolvem no máximo três variáveis: duas

para os operandos e uma para receber resultados.• Esta é a razão para o nome “Três Endereços”.

– Quatro tipos básicos de instruções:• atribuição• desvios• chamada a rotinas• acesso (indireto ou indexado)

Page 85: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços- instruções de atribuição -

• Três formas básicas:– variável recebe resultado de operação binária

a = b operador c ;– variável recebe resultado de operação unária

a = operador b ;– variável recebe valor de outra variável

a = b ;• Ex.:

– instruções em C: a = b + c * d ;– instruções intermediárias:

t = c * d ;a = b + t ;

Page 86: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços- instruções de desvio -

• Possuem duas formas básicas:– desvio incondicional: GOTO rótulo– desvio condicional: IF x operador y GOTO rótulo

• Exemplo:

while (i++ <= k)x[i] == 0;

x[0] = 0 ;

_L1: if i>k goto _L2; i := i + 1; x[i] := 0; goto _L1;_L2: x[0] := 0;

Page 87: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços- instruções de chamada de rotinas -

• Ocorre em duas etapas:– argumentos são devidamente armazenados pela

instrução param ;– rotina é efetivamente chamada pela instrução call;

• pode ou não haver valor de retorno.• Exemplo: para chamar uma função func(a,b,c) o

código intermediário seriaparam aparam bparam c_t1 := call func,3

– o valor “3” após a chamada mostra quantos argumentos foram armazenados para serem usados na chamada à rotina.

Page 88: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços- instruções de acesso -

• Acessos indexados:– Exemplos:

a := b[i]d[j] := c

• Acessos indiretos: permitem manipulação de endereços.– Exemplos:

a := &b c := *d

*e := f

Page 89: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Código de Três Endereços- representação interna -

• Baseada em tabelas de três ou quatro colunas.• Ex. para expressão a = b + c * d ;

1

2

operador arg_1 arg_2 resultado

* c d _t

+ b _t aquádrupla

tripla: associaresultados aos números de linha na tabela

1

2

operador arg_1 arg_2

* c d

+ b (1)

Page 90: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Notação Posfixa• Também conhecida por notação polonesa ou

notação polonesa reversa (RPN).• Características:

– operador vem após operandos;– não exige parênteses;– pode ser eficientemente implementada em máquinas

baseadas em pilhas (máquinas de zero endereços):• operandos são inseridos e retirados do topo da pilha com

instruções tipo push e pop;• operadores retiram da pilha os operandos e devolvem o

resultado da operação para o topo da pilha.• Exemplos:

a * b + c ; ==> a b * c +(a + b) * (c + d) ==> a b + c d + *

Page 91: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de processadorcom notação posfixa

• Repertório parcial de instruções de um processador fictício:

Código Mnemônico Função

11 LDC <valor> Empilhe valor. 12 LD Desempilhe endereço e empilhe

conteúdo deste endereço. 13 ST Desempilhe valor; desempilhe endereço;

armazene valor neste endereço. 16 ADD Desempilhe a; desempilhe b; empilhe b+a . 17 SUB Desempilhe a; desempilhe b; empilhe b-a .

Page 92: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Exemplo de uso de processador fictício• Resolução de a = (2+3) - 1;

– Em notação posfixa: 2 3 + 1 - a =– Sequência de instruções:

Mnemônico Conteúdo da pilha

LDC <end. de a> <end. de a>LDC 2 <end. de a> , 2LDC 3 <end. de a> , 2 , 3ADD <end. de a> , 5LDC 1 <end. de a> , 5 , 1SUB <end. de a> , 4ST

Page 93: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Adaptação do Arquivo .y%token IDN%token INT%token REAL%token SIMB_ATR%token SIMB_PA1%token SIMB_PA2%token SIMB_MUL%token SIMB_DIV%token SIMB_SOM%token SIMB_SUB%token SIMB_POT%token SIMB_END%start stat

%%stat: SIMB_END | expressao SIMB_END { /* Ação Semântica 0 */ exit(1); } ;

expressao: termo { /* Ação Semântica 1 */ $$ = $1; } | expressao SIMB_SOM termo { /* Ação Semântica 2 */ $$ = $1 + $3; fprintf("ADD \n",); } | expressao SIMB_SUB termo { /* Ação Semântica 3 */ $$ = $1 - $3;

fprintf("SUB \n"); } ;/* demais regras devem ser incluídas . . . */%%main( ) {

yyparse( );}

Page 94: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Otimização• Conjunto de transformações no código gerado

visando minimização de tempo de execução e/ou memória ocupada.– Otimização independente de máquina:

• Não considera a arquitetura da máquina, como p. ex.x + 0 --> x

– Otimização dependente da máquina:• Usa recursos da arquitetura para melhorar o código

ADD --> ADDQ (no 68000)– Otimização local: considera apenas um bloco de

instruções.– Otimização global: considera todo o procedimento.

Page 95: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Otimização por Trecho de Instruções• Técnica de otimização local que inclui:

– Eliminação de códigos redundantes– Eliminação de códigos não alcançáveis– Eliminação de desvios desnecessários– Redução de complexidade– Uso de modos de endereçamento

Page 96: Compiladores - Unicamp• Há compiladores que geram código em linguagem assembly. – Formalização da gramática de linguagem de máquina é difícil. • Rotinas de tradução

Otimizações Independentes de Máquina• Eliminação de expressões comuns• Propagação de cópias• Eliminação de códigos mortos• Otimização em laços

– Movimento de códigos– Eliminação de variáveis de indução

• Substituições algébricas