E N D
1. Compiladores
Cristiano Damiani Vasconcellos
damiani@joinville.udesc.br
2. Bibliografia Recomendada
3. Introdução(Construção de um Executável)
4. Introdução(Fases de um Compilador)
5. Introdução
6. Introdução
7. Análise Léxica O Analisador Léxico (scanner) examina o programa fonte caractere por caractere agrupando-os em conjuntos com um significado coletivo (tokens):
palavras chave (if, else, while, int, etc),
operadores (+, -, *, /, ^, &&, etc),
constantes (1, 1.0, ‘a’, 1.0f, etc),
literais (“Projeto Mono”, etc),
símbolos de pontuação (; , {, }, etc),
labels.
8. Análise Léxica constanteInt ? digito digito*
constanteDouble ? digito digito*. digito*
digito ? {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
9. Análise Sintática Verifica se as frases obedecem as regras sintáticas da linguagem:
Por exemplo, uma expressão pode ser definida como:
expressão + expressão
expressão – expressão
(expressão)
constante
10. Gramáticas Livres de Contexto Definidas por uma quádrupla (VN, VT, S, P), onde:
VN é um conjunto de símbolos não terminais (representam as construções sintáticas da linguagem).
VT é um conjunto de símbolos terminais (tokens da linguagem).
S ? VN é o símbolo inicial da gramática.
P é um conjunto de regras de produção, pares ordenados representados na forma ? ? ?, onde ? ? VN e ? ? (VN ? VT)*.
11. Gramáticas Livres de Contexto <expr> ? <expr> + <expr>
| <expr> – <expr>
| (<expr>)
| <const>
<const> ? <const><const>
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9
12. Derivação Verificar se uma frase faz parte da linguagem gerada pela gramática, envolve sucessivas substituições dos símbolos que ocorrem do lado esquerdo da produção pela sua construção sintática correspondente.
Essa substituição é chamada derivação sendo normalmente denotada pelo símbolo ?. E deve iniciar a partir do símbolo inicial da gramática.
13. Derivação
14. Árvore de Derivação
15. Gramáticas Ambíguas
16. Gramáticas <expr> ? <expr> + <termo>
| <expr> - <termo>
| <termo>
<termo> ? (<expr>)
| <const>
<expr>
<expr> + <termo>
<expr> - <termo> + <termo>
<termo> - <termo> + <termo>
10 – 2 + 3
17. Gramáticas <expr> ? <expr> + <termo>
| <expr> - <termo>
| <termo>
<termo> ? <termo> * <fator>
| <termo> / <fator>
| <fator>
<fator> ? (<expr>)
| <const>
18. Gramáticas <expr> ? <expr> + <termo>
| <expr> - <termo>
| <termo>
<termo> ? <termo> * <fator>
| <termo> / <fator>
| <fator>
<fator> ? (<expr>)
| <const>
19. Tradução Dirigida pela Sintaxe
20. Gramáticas - Exercícios Considerando a gramática apresentada anteriormente derive as expressões e apresente a árvore sintática correspondente:(1 + 2) * 3 (1 – 2) + 3 * 4
Altere a gramática para incluir o operador unário -, esse operador deve ter precedência maior que todos os outros operadores.
Altere a gramática para que os operadores de adição, subtração, multiplicação e divisão tenham associatividade da direita para a esquerda.
Defina uma gramática para expressões aritméticas (operadores +, -, *, /) pós fixadas.
21. Gramáticas Dados 2 conjuntos independentes de símbolos:
VT – Símbolos terminais.
VN – Símbolos não terminais.
Uma gramática é definida como a quádrupla:
(VN, VT, S, P)
Onde,
S ? VN é o símbolo inicial da gramática.
P é um conjunto de regras de reescrita na forma: ? ? ?, sendo: ? ? (VN ? VT)* VN (VN ? VT)*
? ? (VN ? VT)*
22. Classificação de Gramáticas Irrestritas – nenhuma restrição é imposta
Sensíveis ao Contexto - |?| ? |?|
Livres de Contexto - ? ? VN ? ? (VN ? VT)+
Regulares - ? ? VN
? tem a forma a ou aB, onde
a ? VT e B ? VN
23. Gramáticas Regulares Uma gramática regular gera uma linguagem regular.
C ? 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9
| 0C | 1C | 2C | 3C | 4C | 5C | 7C | 8C | 9C
24. Linguagens Regulares Geradas a partir de uma gramática regular;
Podem ser representadas através de uma expressão regular;
Podem ser reconhecidas por Autômatos Finitos.
Considerando linguagens compostas por símbolos 0 e 1 podemos afirmar:
a linguagem L1 ={0n1n | n ? 1} não é regular; a linguagem L2 ={0n1m | n ? 1, m ? 1} é regular;
25. Expressões Regulares Maneira compacta de representar linguagens regulares. É composta de 3 operações. Sendo e1 e e2 expressões que geram respectivamente duas linguagens regulares L1 e L2:
26. Expressões Regulares Exemplos:
identificador ? (letra | _) (letra | digito | _)*
letra ? a | b | ... | z | A | B | ... | Z
digito ? 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
constInt ? digito digito*
constDouble ? digito digito*.digito* | . digito digito*
27. Autômato Finito A linguagem gerada por uma gramática regular pode ser reconhecida por um autômato finito.
Um autômato finito consiste em:
28. Autômato Finito
29. Autômato Finito
30. Autômato Finito Implementação
31. Geradores de Analisadores Léxicos
32. Análise Léxica - Exercícios Escreva uma gramática, expressão regular e AFD que defina os números binários terminados em zero.
Mostre uma expressão regular e o AFD correspondente a gramática abaixo:S ? aS B ? bC C ? aC | aB | a
Escreva uma expressão regular para as constantes double da linguagem C.
33. Especificação Análise Léxica – expressões regulares.
Análise Sintática – gramáticas livres de contexto.
Análise Semântica – sistema de tipos (regras de inferência), semântica denotacional, semântica operacional, semântica de ações.
Geração/Otimização de Código – linguagens para descrição de arquiteturas.
34. Analisador Sintático
35. Métodos top-down
36. Método Descendente Recursivo
37. Método Descendente Recursivo
38. Analisadores Sintáticos Preditivos
39. Fatoração a Esquerda
40. Fatoração a Esquerda
41. Eliminação da Recursividade a Esquerda
42. Eliminação da Recursividade a Esquerda
43. Análise Sintática Preditiva não Recursiva LL(1)
44. Analisador Sintático LL(1)
45. Analisador Sintático LL(1)
46. Construção da Tabela LL(1)
47. Construção da Tabela LL(1)
48. Construção da Tabela LL(1)
49. Construção da Tabela LL(1)
50. Métodos bottom-up
51. Métodos LR(k)
52. Métodos LR
53. Algoritmo LR(1)
64. Tabelas SLR(1)
65. Construção da Tabela Sintática SLR(1)
66. Construção da Tabela Sintática SLR(1)
67. Construção da Tabela Sintática SLR(1)
68. Construção da Tabela Sintática SLR(1)
69. Construção da Tabela Sintática SLR(1)
70. Construção da Tabela Sintática SLR(1)
71. Construção da Tabela Sintática SLR(1)
72. Construção da Tabela Sintática SLR(1)
73. Construção da Tabela Sintática LR(1)
74. Construção da Tabela Sintática LR(1)
75. LALR – lookahead LR
76. Construção da Tabela Sintática LALR(1)
77. Hierarquia de Gramáticas Livres de Contexto
78. Uso de Gramáticas Ambíguas
79. Lex delim [ \t]
ws {delim}+
digito [0-9]
num {digito}+(\.{digito}*(E[+-]?{digito}+)?)?
%%
{ws} {}
"+" {return TADD;}
"-" {return TSUB;}
"*" {return TMUL;}
"/" {return TDIV;}
"(" {return TAPAR;}
")" {return TFPAR;}
\n {return TFIM;}
{num} {yylval=atof(yytext); return TNUM;}
80. yacc %{
#include <stdio.h>
#include <stdlib.h>
#define YYSTYPE double
%}
%token TADD TMUL TSUB TDIV TAPAR TFPAR TNUM TFIM
%%
81. yacc Linha :Expr TFIM {printf("Resultado:%lf\n", $1);exit(0);}
;
Expr: Expr TADD Termo {$$ = $1 + $3;}
| Expr TSUB Termo {$$ = $1 - $3;}
| Termo
;
Termo: Termo TMUL Fator {$$ = $1 * $3;}
| Termo TDIV Fator {$$ = $1 / $3;}
| Fator
;
Fator: TNUM
| TAPAR Expr TFPAR {$$ = $2;}
;
%%
82. yacc
int yyerror (char *str)
{
printf("%s - antes %s\n", str, yytext);
}
int yywrap()
{
return 1;
}
83. Programa #include <stdio.h>
extern FILE *yyin;
int main()
{
yyin = stdin;
printf("Digite uma expressão:");
yyparse();
return 0;
}
84. Definição Dirigida pela Sintaxe
85. Definição Dirigida pela Sintaxe
86. Árvores Sintáticas E ? E1 + T {E.ptr = criarNo (‘+’, E1.ptr, T.ptr)}
E ? T {E.ptr = T.ptr}
T ? T1 * F {T.ptr = criarNo (‘*’, T1.ptr, F.ptr)}
T ? F {T.ptr = F.ptr}
F ? (E) {F.ptr = E.ptr}
F ? const {F.ptr = criarFolha(const.lexval)}
87. DAG Grafo Direcionado Acíclico Identifica as subexpressões comuns.
Exemplo:
DAG que representa a expressão: a * b + c + a *b.
88. Código de 3 endereços Uma sequência de enunciados na forma:
x = y op z
Onde x, y e z são nomes, constantes ou dados temporários (criados pelo compilador) e op representa uma operação qualquer.
Uma versão linearizada da árvore sintática, é assim chamado por cada instrução poder conter até três endereços, dois para os operandos e um para o resultado. Bastante semelhante a linguagem de montagem.
89. Código de 3 endereços Exemplo: a = 2 * b + c
t1 = 2 * b
t2 = t1 + c
a = t2
90. Código de 3 endereços S ? id = E {S.cod = E.cod ++ gerar(id.lexval = E.local)}
E ? E1 + T {E.local = novoTemporario();
E.cod = E1.cod ++T.cod ++ gerar(E.local = E1.local + T.local)}
E ? T {E.local = T.local; E.cod = T.cod}
T ? T1 * F {T.local = novoTemporario();
T.cod = T1.cod ++ F.cod ++ gerar(T.local = T1.local * F.local)}
T ? F {T.local = F.local; T.cod = F.cod}
F ? (E) {F.local = E.local; F.cod = E.cod}
F ? id {F.local = id.lexval; F.cod =“”}
F ? const {F.local = const.lexval; F.cod =“”}
91. Código de 3 endereços Alguns enunciados comumente usados:
92. Código de 3 endereços n = 1;
f = 1;
while (n < 10)
{
f = f * n;
n = n + 1;
}
93. Código de 3 endereços n = 1;
f = 1;
while (n < 10)
{
f = f * n;
n = n + 1;
}
94. Definições S-atribuídas Definições dirigidas pela sintaxe que possuem apenas atributos sintetizados.
95. Definições L-atribuídas Uma definição dirigida pela sintaxe é L-atribuída se cada atributo herdado de Xj, 1 ? j ? n, do lado direito de uma produção, A ? X1X2...Xn depende somente:
96. Tradução Top-Down S ? E {imprimir (E.val)}
E ? T {E’.h = T.val} E’ {E.val = E’.s}
E’ ? +T {E’1.h = E’.h + T.val} E1 {E’.s = E’1.s}
E’ ? ? {E’.s = E’.h}
T ? F {T’.h = F.val} T’ {T.val = T’.s}
T’ ? * F{T’1.h = T’.h * F.val} T’ {T’.s = T1’.s}
T’ ? ? {T’.s = T’.h}
F ? const {F.val = const.lexval}
F ?({push(T’.h); push(E’.h)} E {E’.h = pop(); T’.h = pop()})
97. Análise Semântica D ? var S
S ? id L {atribuirTipo(id.lexval, L.tipo)}
S ? S id L {atribuirTipo(id.lexval, L.tipo)}
L ? , id L1 {atribuirTipo(id.lexval, L.tipo); L.tipo = L1.tipo}
L ? :T {L.tipo = T.tipo}
T ? integer {T.tipo = integer}
T ? string {T.tipo = string}
98. Análise Semântica E ? E1 + T {if (E1.tipo = T.tipo) then E.tipo = E1.tipo else error()}
E ? T {E.tipo = T.tipo}
T ? T1 * F {if (T1.tipo = F.tipo) then T.tipo = T1.tipo else error()}
T ? F {T.tipo = F.tipo}
F ? id {F.tipo = consultaTipo(id.lexval);}
F ? constInt {F.tipo = Inteiro}
F ? constReal {F.tipo = Real}
Obs: Em uma situação real as regras semânticas devem implementar a coerção dos tipos.
99. Expressões Lógicas e Relacionais B ? B1 or M C {corrigir(B1.listaf, M.label);
B.listav = merge(B1.listav, C.listav);
B.listaf = C.listaf;}
B ? B1 and M C {corrigir(B1.listav, M.label);
B.listaf = merge(B1.listaf, T.listaf);
B.listav = C.listav;}
B ? C {B.listav = C.listav; B.listaf = C.listaf;}
C ? not C1 {C.listav = C1.listaf; C.listaf = C1.listav;}
C ? (B) {C.listav = B.listav; C.listaf = B.listaf;}
C ? E1 rel E2 {C.listav = criaLista(proxInst);
C.listf = criaLista(proxInst+1);}
gerar(if E1.local rel E2.local goto _);
gerar (goto _);
M ? ? {M.label = novolabel()}
100. Comandos de Seleção e Repetição S ? if (B) then M S {corrigir (B.listav, M.label);
corrigir(B.listaf, novolabel();}
S ? if (B) then M1 S N else M2 S
{corrigir(B.listav, M1.label);
corrigir(B.listf, M2.label);
corrigir(N.listav, novoLabel();}
S ? while M1 (B) M2 S
{corrigir(B.listav, M2.label);
gerar(goto M1.label);
corrigir(B.listaf, novolabel();}
N ? ? {N.listav = criarLista(ProxInstr); gerar(goto _);}
101. Organização da Memória
102. Dados Estáticos A área de memória é reservada no início da execução do programa e liberada apenas no fim de sua execução (e.g. variáveis globais e variáveis locais declaradas com o modificador static em linguagem C).
103. Dados Dinâmicos Pilha – Área de armazenamento temporário onde é armazenado o registro de ativação das funções.
Heap – Área reservada para alocação dinâmica, permite ao programador alocar e liberar espaços de memória quando necessário (e.g. funções malloc e free em linguagem C).
104. Registro de Ativação As informações necessárias para execução de uma função/procedimento são gerenciadas utilizando um bloco de memória chamado registro de ativação, fazem parte do registro de ativação: parâmetros, endereço de retorno e variáveis locais.
105. Chamadas de Funções/Procedimentos int fat (int n)
{
if (n >= 1)
return 1;
return n * fat(n-1);
} fat:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %ebx
cmpl $1, %ebx
jl L1:
movl $1, %eax
movl %ebp, %esp
popl %ebp
ret
L1: subl $1, %ebx
pushl %ebx
call fat
subl $4, %esp
movl 8(%ebp), %ebx
imull %ebx, %eax
movl %ebp, %esp
popl %ebp
ret
106. Chamadas de Funções/Procedimentos int fat (int n)
{
if (n >= 1)
return 1;
return n * fat(n-1);
}
Int main()
{
int x;
x = fat(3);
}