Slides 3 Compiladores
Slides 3 Compiladores
_________________________________________
Professor Álvaro Antônio Fonseca de Souza
Aula de hoje
_____________________________________________________________________________________________________________
Estrutura de um compilador
Fundamentos da linguagem de programação
● Estático e Dinâmico
● Estático: política de linguagem que permite ao compilador decidir a respeito da
questão.
○ Decisão em tempo de compilação
● Dinâmico: política só permite que a decisão seja tomada quando o programa está
em execução.
○ Decisão em tempo de execução.
3
Fundamentos da linguagem de programação
● Estático e Dinâmico
● O termo static aplicado aos dados em uma declaração de classe Java.
○ uma variável é um nome que designa uma localização de memória
● Torna x uma variável de classe e diz que existe apenas uma única cópia de x.
● O compilador determina a localização na memória onde x será mantido.
● Do contrário, cada objeto teria sua própria localização de x.
4
Fundamentos da linguagem de programação
● Escopo
● Escopo de uma declaração de x: é a região do programa em que os usos de x se
referem a essa declaração.
● Escopo estático: Também conhecido como escopo léxico, determina o escopo
de uma declaração examinando-se apenas o programa.
● A maioria das linguagens utilizam escopo estático.
● Escopo dinâmico: o escopo é definido enquanto o programa é executado.
○ O mesmo uso de x poderia se referir a qualquer uma das declarações diferentes de x.
5
Fundamentos da linguagem de programação
● As regras de escopo para C são baseadas na estrutura do programa.
● O escopo de uma declaração é determinado implicitamente pelo local onde a
declaração aparece no programa.
● Linguagens modernas, como C++, Java e C#, tem controle explícito sobre
escopos, através de palavras-chave como public, private e protected.
● Escopo estático para uma linguagem com blocos,
● Um bloco é um agrupamento de declarações e comandos.
● C utiliza chaves { e } para delimitar um bloco;
● Escopo teve origem na linguagem Algol usando begin e end para esta finalidade.
6
Aula de hoje
_____________________________________________________________________________________________________________
Análise léxica
Introdução
count + 1,
9
Tokens, padrões e lexemas
● Um token é um par consistindo em um nome e um valor de atributo
opcional.
● O nome do token é um símbolo abstrato que representa um tipo de
unidade léxica
○ uma palavra-chave em particular, ou uma sequência de caracteres da entrada
denotando um identificador.
12
Lexema e token
13
Lexema e token
14
Lexema e token
15
Símbolos léxicos
● identificadores: palavras para nomear entidades do programa
○ variáveis, funções, métodos, classes, módulos, etc.
16
Símbolos léxicos
● identificadores: palavras para nomear entidades do programa
○ variáveis, funções, métodos, classes, módulos, etc.
17
Símbolos léxicos
● identificadores: palavras para nomear entidades do programa
○ variáveis, funções, métodos, classes, módulos, etc.
18
Símbolos léxicos
● identificadores: palavras para nomear entidades do programa
○ variáveis, funções, métodos, classes, módulos, etc.
19
Símbolos léxicos
printf("Total = %d\n”, score);
20
Símbolos léxicos
21
Símbolos léxicos
22
Exemplos
const PI = 3.1416
Onde:
23
Tokens
25
Atributos de tokens
● O analisador léxico retorna ao analisador sintático um valor de atributo,
além do nome de token;
● O valor do atributo descreve o lexema representado pelo token
● O nome do token influencia as decisões durante a análise sintática,
● O valor do atributo influencia a tradução dos tokens após o
reconhecimento sintático.
26
Atributos de tokens
● Os tokens possuem no máximo um atributo associado
● Esse atributo pode ter uma estrutura que combine com várias peças
da informação.
● O token id é um exemplo em que é necessário associar muitas
informações ao token.
● As informações do token, como lexema, tipo, e localização são
mantidas na tabela de símbolos.
● O valor de atributo apropriado para um identificador é um apontador
para sua entrada na tabela de símbolos. 27
Remoção de espaços em branco
● Um analisador léxico pode realizar outras tarefas além da
identificação de lexemas.
● Uma dessas tarefas é remover:
○ comentários
○ espaço em branco (espaço);
○ quebra de linha;
○ tabulação;
○ outros caracteres usados para separar os tokens na entrada.
28
Remoção de espaços em branco
● Espaços em branco podem causar erro.
● Devem ser ignorados assim como os comentários.
● Se os espaço em branco for eliminado, o analisador sintático não precisa
considerá-lo.
● Incorporar o espaço em branco na análise sintática é uma tarefa difícil.
Os números de linha e o contexto são úteis dentro das mensagens de erro para auxiliar a localizar os
erros; 29
Lendo adiante
● Um analisador léxico talvez precise ler alguns caracteres adiante antes de
poder decidir sobre o token a ser retornado.
● Por exemplo:
● Um analisador léxico para C precisa ler adiante após ver o caractere >.
● Se o caractere seguinte for =,
● então > pertence à sequência de caracteres >=;
○ o lexema do token para o operador “maior ou igual a”,
30
Lendo adiante
● Manter um buffer de entrada no qual o analisador
léxico pode ler e colocar caracteres de volta.
● Um apontador registra a parte da entrada que está
sendo analisada.
● Para voltar um caractere, move-se o apontador para
trás.
31
Lendo adiante
● A leitura de um caractere adiante normalmente é suficiente,
● Uma solução é usar uma variável para tratar o próximo
caractere da entrada.
● O analisador léxico lê um caractere adiante enquanto coleta
dígitos para formar os identificadores;
● por exemplo, após 1 ele lê mais um caractere para distinguir
entre 1 e 10, e após t ele lê mais um caractere para distinguir
entre t e true.
32
Lendo adiante
● O analisador léxico lê adiante apenas quando necessário.
● Um operador como * pode ser identificado sem leitura adiante.
● A variável de leitura é definida como um espaço em branco
○ será ignorado quando o analisador léxico for chamado para encontrar o
próximo token.
33
Reconhecendo palavras-chave e identificadores
● As palavras-chave geralmente satisfazem as regras para formar
identificadores.
● Necessário um mecanismo para decidir quando um lexema forma
uma palavra-chave e quando ele forma um identificador.
● O problema é mais fácil de resolver se as palavras-chave forem
reservadas;
○ Se não puderem ser usadas como identificadores.
● Uma sequência de caracteres forma um identificador apenas se não
for uma palavra-chave.
34
Reconhecendo palavras-chave e identificadores
● Representação única.
● Uma tabela com sequências de caracteres pode isolar o
resto do compilador da representação das sequências de
caracteres.
● As fases do compilador podem trabalhar com referências ou
apontadores para a sequência de caracteres na tabela.
● As referências também podem ser manipuladas com mais
eficiência do que as próprias sequências de caracteres. 35
Reconhecendo palavras-chave e identificadores
● Palavras reservadas.
● As palavras reservadas podem ser implementadas inicializando a tabela
de sequências de caracteres com as sequências de caracteres
reservadas e seus tokens.
● Quando o analisador léxico lê uma sequências de caracteres ou lexema
que possa formar um identificador, ele primeiro verifica se o lexema está
na tabela de sequências de caracteres.
● Se estiver, retorna o token da tabela; caso contrário, retorna um token
cujo primeiro componente é o terminal id.
36
Reconhecendo palavras-chave e identificadores
● Uma tabela de sequências de caracteres pode ser implementada como
uma tabela hash.
● A declaração
37
Qual é a sequência de tokens?
38
Qual é a sequência de tokens?
39
Um analisador léxico
1. Token scan()
2. ignora os espaços em branco
3. trata os números
4. trata as palavras reservadas e identificadores
5. /* se chegamos aqui, trata o caractere lido adiante como
token */
6. Token 1 = new Token(peek);
7. peek = espaço /* inicialização
8. return t
9. }
40
Exemplo
41
Exemplo
42
Exemplo
43
Tabelas de símbolos
● Tabelas de símbolos são estruturas de dados que contém informações sobre as
construções do programa fonte.
● As informações são coletadas de modo incremental pelas fases de análise de um
compilador.
● As entradas na tabela de símbolos são criadas e usadas durante a fase de
análise pelo analisador léxico, pelo analisador sintático e pelo analisador
semântico.
● As informações são usadas pelas fases de síntese para gerar o código objeto.
● As entradas na tabela de símbolos contêm informações sobre um identificador,
como nome ou lexema, tipo, endereço na memória e outras informações
relevante.
44
O papel do analisador léxico
Quando o analisador léxico descobre que um lexema é um identificador, precisa inserir esse
lexema na tabela de símbolos.
45
Erros léxicos
● É difícil para um analisador léxico saber que existe um erro no código
fonte.
● Por exemplo, se a cadeia de caracteres fi for encontrada pela primeira
vez em um programa C no contexto:
fi (a = f(x)) …
● fi pode ser
● A palavra-chave if escrita errada
● Um identificador de função não declarada.
46
Erros léxicos
● fi é um lexema válido para o token id
● O analisador léxico precisa retomar o token id
● Deixa que alguma outra fase do compilador trate do erro
devido à transposição das letras.
● Provavelmente o analisador sintático, neste caso.
● O compilador deve continuar o processo de compilação para
encontrar o maior número de erros possível.
47
Abordagens de implementação
em lexemas apropriados.