Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


COMP aula2, Notas de aula de Informática

Compiladores ensinado por Patrick Pedreira.

Tipologia: Notas de aula

Antes de 2010

Compartilhado em 01/12/2009

ygor-dos-santos-luz-3
ygor-dos-santos-luz-3 🇧🇷

4.7

(3)

55 documentos

1 / 14

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
1
Compiladores
Disciplina: Compiladores
Professor: Patrick Pedreira
2Análise Léxica
Compiladores
Objetivo da aula
Entender como funciona a análise léxica em
um compilador
Compiladores
Revisão
Compiladores
Onde Estamos?
Compiladores
Análise Léxica
Compiladores
Scanner, Analisador Léxico
É a primeira fase do compilador
A função do Analisador Léxico (Scanner) é:
Fazer a leitura do programa-fonte, caractere a
caractere, e traduzí-lo para uma sequência de
símbolos léxicos, também chamados de token
Organização
Às vezes dividido em:
scanning remoção de comentários e espaços em
branco duplicados
Análise léxica propriamente dita – parte mais complexa,
onde o scanner produz a sequencia de tokens
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe

Pré-visualização parcial do texto

Baixe COMP aula2 e outras Notas de aula em PDF para Informática, somente na Docsity!

Disciplina: Compiladores Professor: Patrick Pedreira

Análise Léxica

Objetivo da aula

  • Entender como funciona a análise léxica em

um compilador

Compiladores

Revisão

Compiladores

Onde Estamos?

Compiladores

Análise Léxica

Compiladores

Scanner, Analisador Léxico

  • É a primeira fase do compilador
  • A função do Analisador Léxico (Scanner) é:
    • Fazer a leitura do programa-fonte, caractere a caractere, e traduzí-lo para uma sequência de símbolos léxicos, também chamados de token
  • Organização
    • Às vezes dividido em:
      • scanning – remoção de comentários e espaços em branco duplicados
      • Análise léxica propriamente dita – parte mais complexa, onde o scanner produz a sequencia de tokens

Scanner – Analisador Léxico

  • Exemplos de símbolos léxicos:
    • Palavras reservadas
    • Identificadores
    • Constantes
    • Operadores da linguagem
  • Durante a análise léxica, são desprezados:
    • Caracteres não significativos
      • Espaços em branco
      • Comentários

Scanner – Analisador Léxico

  • Na análise léxica também são realizadas outras funções: - Armazenamento de alguns símbolos (identificadores e constantes) em tabelas internas - Indicação da ocorrência de erros léxicos - Tratamento de mensagens de erro (localização/impressão)
  • Saída do Analisador Léxico (tokens) é utilizada como entrada da fase seguinte: análise sintática
  • O analisador léxico pode constituir um passo individual do compilador - Porém, em geral, o analisador léxico atua como uma subrotina que é chamada pelo analisador sintático sempre que este necessita de mais um token

Compiladores

Scanner – Analisador Léxico

  • Por que separar scanner e parser?

Compiladores

Analisador léxico x Parser

  • Design mais simples – misturar análise léxica

com sintática torna o parser bem mais

complicado

  • Eficiência – separação possibilita construir

processadores léxicos e sintáticos mais

eficientes.

  • Portabilidade – variações de dispositivos

podem ficar restritas ao analisador léxico.

Compiladores

Definições léxicas de uma linguagem

  • Exemplos:
    • O que delimita um token?
    • Diferenciação de letras maiúsculas/minúsculas?
    • Qual o conjunto de palavras reservadas?
    • Qual as regras para a formação de identificadores?
    • Quais os operadores aceitos?
    • Quais os delimitadores aceitos? (. ; : ) [ ] { }
    • Quais as regras para a formação de números?
    • Quais as regras para a formação de comentários?
    • etc.

Compiladores

Tokens, padrões e lexemas

  • Lexema: sequencia de caracteres que casam com o padrão de um token. Uma instância de um token.
  • Padrão: descrição da forma dos lexemas que um token pode ter
  • Tokens: par com o nome do token e atributos opcionais.

Atributos de um token - Exemplo

• E = M * C ** 2

  • <id, apontador p/posição de E na tabela de símbolos> <assign_op,> <id, apontador p/posição de M na tabela de símbolos> <mult_op,> <id, apontador p/posição de C na tabela de símbolos> <exp_op,> <num, valor 2>

Erros léxicos

  • Relativamente raros.
  • Geralmente o analisador tenta recuperar do

erro, ignorando caracteres.

  • Poucos erros podem ser verificados pelo

analisador devido a sua visão limitada do

código

  • Ex: em fi ( a == f(x) ) O analisador léxico entende “fi” como um identificador e não como um erro

Compiladores

Erros léxicos

  • Exemplos de erros
    • Símbolo não pertencente ao conjunto de símbolos terminais da linguagem: @ - Não há autômato para reconhecer esses símbolos
    • Identificador mal formado: j@, 1ª
    • Tamanho do identificador: minha_variável_para_...
    • Número mal formado: 2.a
      • Estado final do autômato de números reais não é atingido
    • Tamanho excessivo do número: 5555555555555555
      • Dependência da especificação da linguagem
    • Fim de arquivo inesperado (comentário não fechado): {...
      • Dependência da especificação da linguagem: comentários de várias linhas?
      • Estado final do autômato de comentários não é atingido
    • Char ou string mal formados: ‘a, “hello world
      • Estado final do autômato de literais não é atingido

Compiladores

Recuperação de Erros Léxicos

  • Técnicas de recuperação de erros
    • “Panic Mode” – Remoção de caracteres até que um token válido seja encontrado
    • Inserção do caractere ausente
    • Substituição do caractere incorreto
  • A maioria das técnicas pressupõem que apenas

um caractere está errado

Compiladores

Recuperação de Erros Léxicos

  • Idealmente, a compilação não pode parar
  • Opções para recuperação de erro - Exemplo: beg#in
  • Deletar caracteres lidos até o erro e começar a análise no próximo caractere não lido - Retorna par <in,t_id>
  • Deletar o caractere ilegal e continuar a análise
    • Retorna pares <beg,t_id> e <in,t_id>
  • Não distinguir erros léxicos, i.e., associa-se um token ‘nada’ ao erro e deixa-se a identificação do erro para uma próxima etapa - Retorna pares <beg,t_id>, <#,t_nada> e <in,t_id>
  • Em qualquer caso, erros devem ser relatados
    • <#,erro_léxico> ou <#,caractere_inválido> na linha xxx...

Compiladores

Especificação de Tokens

  • É desejável que se usem notações formais para

especificar e reconhecer a estrutura dos tokens

que serão retornados pelo analisador léxico

  • Evitam-se erros
  • Mapeamento mais consistente e direto para o programa de análise léxica
  • Notações
  • Gramáticas ou expressões regulares: especificação de tokens
  • Autômatos finitos: reconhecimento de tokens

Especificação de Tokens

  • Para o analisador léxico, o programa fonte é uma sequência de palavras de uma linguagem regular
  • No caso mais simples, uma linguagem é um conjunto de palavras formadas por símbolos de um determinado alfabeto
  • Esse é o caso do conjunto de tokens de uma linguagem de programação - O conjunto de tokens da ling. de programação é uma linguagem regular
  • No contexto da tradução de ling. de programação, as linguagens são usualmente apresentadas através de gramáticas ou de autômatos (algoritmos) que as reconhecem

Especificação de Tokens

  • Baseado em Teoria de Linguagens:

Alfabetos, strings e linguagens

  • Operações sobre linguagens
  • Exemplo:

seja L o conjunto (de letras)

{A,B,…,Z,a,b,…,z}

e D o conjunto (de dígitos) {0,1,…,9}.

Compiladores

Gramáticas e Linguagens Regulares

  • Definição – Gramática
    • Uma gramática G é um mecanismo para gerar as sentenças (ou palavras) de uma linguagem e é definida pela quádrupla: (N,T, P, S) - N é um conjunto de símbolos não-terminais (variáveis) - T é um conjunto de símbolos terminais (constantes), e T ∩ N = Ø - P é um conjunto de regras de produção (regras sintáticas) - S é o símbolo inicial da gramática (S (^) ∈∈∈∈ N)

Compiladores

Gramática

  • As regras de produção são representadas por α →β e definem o mecanismo de geração das sentenças da linguagem.
  • Uma sequência de regras da forma α →β 1 , α →β 2 , ..., α →βn, (com o mesmo lado esquerdo) pode ser representada de forma simplificada como segue: - α →β 1 |β 2 | ...|βn
  • A aplicação sucessiva de regras de produção, a partir do símbolo inicial da gramática, permite derivar as sentenças válidas da linguagem representada pela gramática.

Compiladores

Derivação

  • Uma derivação é um par da relação denotada

por , com domínio em (N U T)+^ e

contradomínio em (N U T)*, e é representada

de forma infixada como

  • O conjunto (N U T)*^ é o conjunto de sentenças

que podem ser formadas por símbolos de N e

T, incluindo a palavra vazia ε (palavra com

comprimento zero) e (N U T)+^ = (N U T)*^ -

Compiladores

Derivação

  • Portanto, uma derivação é a substituição de

uma sequência de símbolos numa forma

sentencial de acordo com uma regra de

produção.

  • Derivações sucessivas são definidas como

segue:

    • fecho transitivo da relação ,ou seja, uma ou mais derivações sucessivas;
    • fecho transitivo e reflexivo da relação , ou seja, zero ou mais derivações sucessivas.

Autômatos

  • Os autômatos compõem-se basicamente de três

partes:

  • a fita de entrada. a qual contém a sentença a ser analisada;
  • uma unidade de controle, que reflete o estado corrente e realiza os movimentos da máquina (leitura e mudança de estado);
  • a função de transição que comanda a leitura de símbolos da fita de entrada e define o estado da máquina.

Autômato Finito

  • Um autômato finito M sobre um alfabeto Ʃ é

uma 5-upla ( K, Ʃ, δ, e 0 , F) onde:

  • K é um conjunto finito de estados
  • Ʃ é o alfabeto dos símbolos da linguagem
  • δ : K x Ʃ  K é a função de transição de estados
  • e 0 é o estado inicial
  • F é o conjunto de estados finais.

Compiladores

Autômato Finito - Exemplo

  • O autômato M abaixo reconhece números inteiros e reais
  • M = ( K, Ʃ, δ, e 0 , F) onde:
  • Ʃ = (d, .)
  • K = (e 0 , e 1 , e 2 , e 3 )
  • F = (e 2 , e 3 )
  • δ (e 0 , d) = e 1
  • δ (e 1 , d) = e 1
  • δ (e 1 , .) = e 2
  • δ (e 2 , d) = e 3
  • δ (e 3 , d) = e 3

Alternativamente poderia serAlternativamente poderia ser representado também pelarepresentado também pela tabelatabela

Compiladores

Autômato Finito - Exemplo

  • Diz-se que uma sentença é aceita por um autômato (pertence à linguagem que ele representa) se, após seu processamento, o autômato para em um estado final.
  • Se, durante o processamento da sentença, ocorre uma situação de indefinição, o autômato para e a sentença não é aceita.
  • No exemplo anterior, as transições δ(e 0 , .), δ(e 2 , .) e δ(e 3 , .) são situações indefinidas - δ é uma função parcial, pois não precisa estar definida para todos os pares K x Ʃ

Compiladores

Autômato Finito - Representação

  • Um autômato finito pode também ser representado através de um grafo, no qual os nodos representam os estados, e os arcos representam as transições entre estados.
  • O estado inicial é indicado por uma seta, e os estados finais são distinguidos por circunferências concêntricas.
  • A figura seguinte ilustra um autômato finito que reconhece identificadores e constantes numéricas reais e inteiras.

Compiladores

Autômato Finito - Representação

  • Representação em tabela de transição
    • Vantagem: acesso rápido
    • Desvantagem: pode ocupar grande espaço quando o alfabeto de entrada é grande

Autômato Finito - Execução

  • Execução do autômato
    • Se o autômato é determinístico (i.e., para cada estado s e símbolo de entrada a, existe somente uma transição possível e não existem transições vazias), o seguinte algoritmo pode ser aplicado

Autômato Finito - Execução

  • Exemplo de execução do autômato

Reconhecer cadeia bab

Compiladores

Autômato Finito - Execução

  • Opção: incorporação das transições no código

do programa

  • Tabela de transição não é mais necessária

Compiladores

Expressões Regulares

  • A estrutura léxica dos tokens pode ser descrita também por expressões regulares.
  • A especificação dos símbolos léxicos em uma dessas notações é utilizada na construção do analisador léxico.
  • Uma vantagem em usar expressões regulares para especificar os tokens é que essa notação é bastante clara e concisa.
  • Além disso, a partir de uma expressão regular, pode- se utilizar um gerador de analisadores léxicos, tal como o LEX, para construir automaticamente um reconhecedor para os tokens gerados pela expressão.

Compiladores

Expressões Regulares

  • Uma expressão regular (ER) sobre um

alfabeto Ʃ é definida indutivamente a partir

de expressões regulares básicas:

  1. Ø é a ER que representa a linguagem vazia (conjunto contendo zero palavras);
  2. ε é a ER que representa a linguagem cuja única palavra é a palavra vazia, ou seja, {ε};
  3. x, onde x∈ Ʃ, é ER que representa a linguagem cuja unica palavra é x, ou seja, {x};
  4. (continua)...

Compiladores

Expressões Regulares

  1. se r 1 e r 2 são ER que representam as linguagens L(r 1 ) e L(r 2 ), tem-se que:
  • (r 1 + r 2 ) é a ER que representa a linguagem L(r 1 ) U L(r 2 );
  • (r 1 r 2 ) é a ER que representa a linguagem {vw | v ∈ L(r 1 ) e w ∈ L(r 1 )}, isto é, a linguagem cujas palavras são formadas pela concatenação de uma palavra de L(r 1 ) com uma palavra de L(r 2 ), nesta ordem;
  • (r 1 )* é a ER que representa a linguagem L*(r 1 ), isto é, o conjunto de palavras que podem ser formadas concatenando-se zero ou mais palavras de L(r 1 ).

Tokens

  • posição do token, a qual indica o local do texto fonte (linha e coluna) onde ocorreu o token. - Essa informação é utilizada. principalmente. para indicar o local de erros.
  • Em função do campo valor, os tokens podem ser divididos em dois grupos: - Tokens simples. - que são os tokens que não têm um valor associado (como as palavras reservadas, operadores e delimitadores) porque a classe do token descreve-o completamente. Esses tokens correspondem a elementos fixos da linguagem. - Tokens com argumento - que são os tokens que têm um valor associado (como identificadores e constantes). Correspondem aos elementos da linguagem definidos pelo programador como, por exemplo, identificadores, constantes numéricas e cadeias de caracteres.

Tokens - Exemplo

  • while I < 100 do I := J + I ;
  • A análise léxica desse segmento produz a seguinte sequência:
    • [whi, ] [id, 7] [<, ] [cte,13] [do, ] [id, 7] [:=, ] [id,12] [+, ] [id,7] [;, ]
  • Por simplicidade
    • os tokens estão representados por pares (omitiu-se a posição).
    • Identificadores e constantes numéricas estão representados pelo par [classe-token, índice-tabela].
    • As classes para palavras reservadas constituem-se em abreviações dessas, não sendo necessário passar seus valores para o analisador sintático.
    • Para delimitadores e operadores, a classe é o próprio valor do token.
    • Usualmente, os compiladores representam a classe de um token por um número inteiro para tomar a representação mais compacta.

Compiladores

Especificação/Implementação

Já sabemos como especificar tokens. E agora, como encontrá-los?

Compiladores

Reconhecimento de tokens

  • A forma mais recomendada no aprendizado é o

Diagrama de Transições seguido da

implementação de uma máquina de estados

  • AFN – Autômatos Finitos Não-determinísticos
  • AFD – Autômatos Finitos Determinísticos

Compiladores

Reconhecimento de tokens

  • Exemplo: Considere uma linguagem simples

cujos tokens são os seguintes:

  • identificadores formados por uma letra (L) seguida, opcionalmente, por uma ou mais letras e/ou dígitos (D)
  • Números inteiros formados por um ou mais dígitos
  • Comentários delimitados por (* e *)
  • Espaços em branco (B) são ignorados

Compiladores

Reconhecimento de tokens

Reconhecimento de tokens – outros exemplos

  • Diagrama de transições que reconhece >=

Reconhecimento de tokens – outros exemplos

  • Diagrama de transições que reconhece

identificadores e palavras reservadas

  • Como diferenciar id de palavra-reservada?

Compiladores

Reconhecimento de tokens – outros exemplos

Compiladores

Opções de Implementação de um analisador

léxico

  1. Uso de um gerador de analisadores léxicos, como lex ou flex, que produzem um analisador léxico a partir de uma especificação em expressões regulares.
  2. Escrever o analisador em uma linguagem de programação convencional, usando as facilidades de E/S da linguagem para ler a entrada.
  3. Escrever um analisador léxico em linguagem de montagem e manipular explicitamente a leitura e a escrita
  • Uso de bufferização da entrada é importante para a eficiência de um analisador léxico!

Compiladores

Opções de Implementação de um analisador léxico

Transforma o programa de entrada em um programa em C queTransforma o programa de entrada em um programa em C que implementa um Autômato Finitoimplementa um Autômato Finito Reconhecem a mesma linguagem, linguagens regulares, expressas porReconhecem a mesma linguagem, linguagens regulares, expressas por expressões regularesexpressões regulares

Compiladores

Opções de Implementação de um analisador

léxico

  • Outra alternativa para implementação de um

analisador léxico é a construção de um

programa que simula o funcionamento do

autômato correspondente

  • O trecho de código a seguir simula o

funcionamento de um autômato finito

  • Nesse código, a função getchar controla a leitura do texto fonte, retomando o caractere do programa fonte indicado pelo ponteiro de leitura e posicionando esse ponteiro sobre o próximo caractere a ser lido.

Pares de buffers

Questões de implementação

  • Palavras reservadas
    • Carregadas no início da execução do compilador
    • Busca deve ser eficiente
    • Usar a mesma estrutura da Tabela de Símbolos ou uma tabela separada (Tabela de Palavras Reservadas)
  • Reconhecimento de tokens
    • Criação e manutenção de um buffer
      • Facilidade de leitura e devolução de caracteres no caso de arquivos grandes - Arquivos pequenos podem ser lidos de uma vez para a memória

Compiladores

Projeto do Analisador Léxico

  • Para cada definição regular da linguagem, será

construído um autômato finito determinístico

  • Com exceção para as palavras reservadas, pois inicialmente serão tratadas como identificadores

Compiladores

Projeto do Analisador Léxico

  • Autômato para o token relop

Compiladores

Projeto do Analisador Léxico

  • Autômato para o token id e palavras

reservadas

Compiladores

Projeto do Analisador Léxico

  • Autômato para o token num
    • A definição é da forma dígito fração? expoente?
    • Faremos 3 autômatos:
      • dígito
      • dígito fração?
      • dígito fração? expoente?
    • O lexema reconhecido para um dado token precisa ser o mais longo possível - O analisador léxico não pode parar após enxergar 12 ou 12. quando a entrada for 12.3E - Portanto, os 3 autômatos precisam ser testados na ordem reversa - Inicio pelo autômato mais abrangente

Projeto do Analisador Léxico

  • Autômato para o token num

Projeto do Analisador Léxico

  • Se pusermos todos os autômatos anteriores juntos, teremos uma seqüência de autômatos para o reconhecimento dos tokens - Estados iniciais com numeração mais baixa são testados antes
  • Sempre que possível, é melhor procurar por tokens de alta freqüência antes dos tokens menos freqüentes - Um autômato é atingido somente após termos falhado nos autômatos anteriores - Ex.: Espaço em branco é muito freqüente, portanto, seu autômato deve vir no início

Compiladores

Implementação

  • Uma seqüência de autômatos pode ser convertida em um programa que procure pelos tokens especificados
  • Enfoque sistemático:
    • Cada estado recebe um segmento de código
      • Se existem transições deixando o estado corrente, então seu código lê um caracter e determina que transição seguir (se possível)
      • Se existe uma transição (caracter lido, estado E), o caracter é reconhecido e o controle é transferido para o código do estado E
      • Senão, o estado corrente não aceita o caracter lido e, nesse caso, ocorre uma falha (chama-se a rotina falha(), que determina um novo autômato para ser testado)

Compiladores

Compiladores

Implementação

  • Rotina falha()
    • Retrocede o ponteiro de leitura para o início do lexema
    • Decide qual será o próximo estado de partida (qual autômato vai ser testado)