Sunteți pe pagina 1din 86

INF25 Compiladores

Anlise Lxica

Felipe Ferraz

Agenda

Definio de Compilador Etapas da Compilao Introduo Anlise Lxica Implementao Manual de um Lexer

Definio de Compilador

Compilador

Definio geral:

um programa que traduz um texto escrito em uma linguagem computacional (fonte) para um texto equivalente em outra linguagem computacional (alvo)

Entrada: cdigo fonte (na ling. fonte) Sada: cdigo alvo (na ling. alvo)

Dependendo do propsito, podem ter nomes especficos


4

Tipos de Compiladores

Assembler ou Montador

Tipo simples de compilador A linguagem fonte uma linguagem assembly (ou linguagem de montagem)

Correspondncia direta com a linguagem de mquina

A linguagem alvo uma linguagem de mquina

Tipos de Compiladores

Compilador tradicional

Traduz de uma linguagem de alto nvel para uma de baixo nvel

Em muitos casos, o compilador gera cdigo objeto, que um cdigo de mquina incompleto

Precisa passar por um linker para virar executvel Exemplo: gcc

Em outros casos, o compilador gerar um cdigo em linguagem de montagem


6

Etapas da Compilao

Etapas da Compilao

Tradicionalmente, os compiladores se dividem em um conjunto de etapas Mostraremos as cinco etapas bsicas a seguir

Podem existir tambm outras etapas intermedirias de otimizao de cdigo, omitidas na figura
8

Etapas da Compilao
Anlise Lxica

Anlise Sinttica

Analise Semntica Gerao de Cdigo Intermedirio Gerao de Cdigo Final


9

Fases da Compilao

Fase de Anlise

Subdivide o programa em partes constituintes Cria uma estrutura abstrata do programa

Fase de Sntese

Constri o programa na linguagem alvo Gera cdigo final


10

Etapas da Compilao
Anlise Lxica

Anlise Sinttica

Front-End (Anlise)

Analise Semntica Gerao de Cdigo Intermedirio Gerao de Cdigo Final

Back-End (Sntese)
11

Etapas da Compilao

Mas por que essa diviso em etapas?

Modularidade deixa o compilador mais legvel e mais fcil de manter Eficincia permite tratar mais a fundo cada etapa com tcnicas especializadas Portabilidade facilita adaptar um compilador para

Receber outro cdigo fonte (muda o front-end) Gerar cdigo para outra mquina (muda o back-end)

12

Etapas da Compilao
Anlise Lxica

Anlise Sinttica

Front-End (Anlise)

Analise Semntica Gerao de Cdigo Intermedirio Gerao de Cdigo Final

Back-End (Sntese)
13

Introduo Anlise Lxica

Anlise Lxica

Objetivo

Ler os caracteres do cdigo fonte agrupando-os de maneira significativa (em lexemas) e classificando esses agrupamentos (em tokens)

Em outras palavras

Entrada: sequncia de caracteres Sada: sequncia de tokens


15

Relembrando...

Lexema: sequncia de caracteres com significado interligado Token: classificao dada ao lexema

Geralmente retornado junto com o prprio lexema ou outro atributo, como um ponteiro ou um valor numrico associado

16

Relembrando...

Tokens especificados como expresses regulares: ABRE_PAR (


FECHA_PAR )

ATRIB
ADD MULT DEF ID NUM_INT PT_VG

=
+ * def [_a-z][_a-z0-9]* [0-9][0-9]* ;
17

WHITESPACE [ \t\n\r]+

Anlise Lxica

O mdulo de software responsvel por essa etapa pode ser chamado de:

Analisador Lxico, Lexer ou Scanner

Alm de retornar os tokens, ele pode:


Remover espaos em branco Contar linhas e colunas, para identificar a localizao de erros Expandir macros
18

Anlise Lxica

Existem vrias tcnicas para construo de um lexer, inclusive tcnicas de construo (semi) automtica
Porm, iniciaremos vendo como fazer um lexer simples manualmente

19

Implementao Manual de um Lexer

Implementao Manual

Vamos comear implementando tokens em uma linguagem simples, chamada XPR-0

Linguagem para especificar expresses Tokens de 1 caractere apenas Sem tratamento de espaos em branco
21

Exemplo de Implementao

Tokens de XPR-0
NUMERO PT_VIRG ADD MULT ABRE_PAR FECHA_PAR [0-9] ; + * ( )

22

Exemplo de Implementao

Passos para implementar o lexer de XPR-0

Implementar os tipos dos tokens


Implementar uma classe para o token Implementar o lexer
23

Exemplo de Implementao

Como implementar os tipos de tokens

Java: criar uma classe separada TokenType

Sugesto: usar enum de Java >= 5

C: usar vrios defines, com valores diferentes


Definir um token especial para indicar fim de arquivo

Exemplo no Eclipse...
24

Exemplo de Implementao

Como implementar os tokens

Criar classe Token Precisa guardar pelo menos o tipo Pode ter outras informaes

O lexema Uma subclassificao O valor inteiro do token Etc.

Exemplo no Eclipse...
25

Exemplo de Implementao

Como implementar o lexer

Criar classe Lexer

Mtodo nextToken()

L o prximo caractere, classifica-o e retorna o token

Exemplo no Eclipse...
26

Implementao Manual

O exemplo anterior foi bem simples, apenas para dar uma noo de construo de um lexer
Complicaes adicionais que podem surgir

Tratamento de espao em branco Tokens de vrios caracteres Tokens com prefixos comuns Diferenciar identificadores de palavras-chave
27

Melhorando o Lexer Manual

Melhorando o Lexer

Espao em branco

Fazer um lao para ler todo caractere considerado como espao em branco Analisar antes de qualquer outro token

29

Melhorando o Lexer

Espaos em branco

// ignora os espaos em branco e quebras de linha while (nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '\n') { nextChar = this.readByte(); } // testar fim de arquivo ... // testar outros tokens ...
30

Melhorando o Lexer

Tokens de vrios caracteres

Faz uma deciso externa com base no primeiro smbolo

Usar switch (mais eficiente) ou if-elses encadeados

Dentro, faz um lao do-while (ou while) Cada smbolo vlido deve ser concatenado ao lexema
31

Melhorando o Lexer

Tokens de vrios caracteres

Assuma que lexema um objeto StringBuilder

... else if (Character.isDigit(nextChar)) { do { lexema.append((char) nextChar); nextChar = this.readByte(); } while (Character.isDigit(nextChar)); tipo = TokenType.NUMERO;

} ...
32

Melhorando o Lexer

Prefixos comuns

Se tokens de mltiplos caracteres tiverem parte em comum Adiar a deciso sobre o tipo e deixa para fazer a deciso num nvel mais interno Continuar lendo os caracteres e armazenando no lexema at poder decidir
33

Melhorando o Lexer

Prefixos comuns

Exemplo: tokens dos operadores >= e >

... else if (nextChar == '>') { nextChar = this.readByte(); if (nextChar == '=') { tipo = TokenType.GREATER_EQ; nextChar = this.readByte(); } else { tipo = TokenType.GREATER; //no precisa ler o prximo char } } ...
34

Melhorando o Lexer

Diferenciando identificadores de palavraschave

Ler todo o lexema, como se fosse um identificador

Depois, compara o lexema inteiro com a lista de palavras-chave


Pode usar uma tabela hash (Hashtable, em Java) Adicionar as palavras-chave com seus tipos de token Aps ler o lexema, s consultar a tabela

Se no existir palavra-chave para aquele lexema, ento um identificador


35

Hashtable

Estrutura de dados que mapeia chaves (keys) a valores (values) Classe Hashtable (Java)

Mtodo put recebe o par (chave,valor) Mtodo get recebe a chave e retorna o valor Exemplo: associar String com Integer
Hashtable numbers = new Hashtable(); numbers.put("one", new Integer(1)); numbers.put("two", new Integer(2)); Integer v = (Integer) numbers.get("one");
36

Melhorando o Lexer

Palavras-chave

Criao da hash

class Lexer { ... private Hashtable keywords;

Lexer() { keywords.put(if , TokenType.IF); keywords.put(else, TokenType.ELSE); keywords.put(int , TokenType.INT); ... }


37

Melhorando o Lexer

Palavras-chave

Reconhecimento dos tokens, em nextToken()

if (Character.isLetter(nextChar)) { do { lexema.append((char)nextChar); nextChar = this.readByte(); } while (Character.isLetter(nextChar)); if (keywords.containsKey(lexema.toString())) { tipo = keywords.get(lexema.toString()); } else { tipo = TokenType.IDENTIFICADOR; } }
38

Buffers de Leitura

Por que usar buffers?

Para tratar situaes em que preciso olhar caracteres frente

Na leitura de um ID, por exemplo, preciso chegar num caractere invlido para parar Como devolver este ltimo caractere?

Para melhorar a performance

Ler um bloco de caracteres do disco mais eficiente do que ler caractere a caractere
40

Buffer nico

L um bloco de caracteres do arquivo para um array na memria

Geralmente, usa-se como tamanho do buffer o tamanho do bloco de disco Exemplo: 4096 bytes (4 KB)

41

Buffer nico
t e m p forward = a

lexemeBegin

Variveis para controlar o buffer


lexemeBegin: incio do lexema atual forward: prximo caractere a ser analisado pelo
lexer

O lexema final fica entre lexemeBegin e

forward

42

Buffer nico

Vantagens

Leitura mais eficiente do arquivo (em blocos) Permite devolver um caractere, retornando o apontador forward

Porm, o uso de buffer nico ainda traz problemas

Lexemas podem ficar quebrados no fim do buffer


43

Buffers Duplos

Dois buffers de mesmo tamanho

Exemplo: dois buffers de 4kB

Evita que um lexema fique incompleto, desde que tokens no possam passar do tamanho de um buffer
e m p = a u x * 1 0

lexemeBegin

forward
44

Buffers Duplos

Um buffer carregado quando o outro j foi completamente lido


A cada leitura de caractere (por meio da varivel forward), preciso testar os limites

Se chegou ao fim de um buffer, muda para o prximo e recarrega

Esse teste ainda pode ser otimizado...


45

Sentinelas

So caracteres especiais usados para demarcar o fim do buffer

No precisa testar o fim do buffer a cada passo, basta testar quando achar esse caractere

Geralmente se usa o mesmo smbolo usado para fim de arquivo eof


m p = a eof u x * 1 0
eof

cdigo fonte
sentinela

cdigo fonte
sentinela
46

Sentinelas

Como diferenciar um sentinela de um fim de arquivo real?

Basta consultar a posio do caractere Sentinelas ficam em posies fixas no fim do buffer Um fim de arquivo real aparece em qualquer outra posio
p = a eof u x ; eof
eof

sentinela

fim de arquivo

sentinela
47

Sobre Buffers e Sentinelas

So tcnicas para quem est muito preocupado com eficincia na compilao

No para quem faz um compilador em Java, para quem faz em C ou Assembly

48

Expresses Regulares

Expresses Regulares

Tokens: classificao de um lexema

So vistos como unidades atmicas da linguagem

Para especificar quais lexemas so associados a cada token, podem ser usadas expresses regulares

Cada token associado a uma expresso regular

50

Expresses Regulares

Exemplo de especificao dos tokens


ABRE_PAR FECHA_PAR ( )

ATRIB
ADD MULT DEF ID NUM_INT PT_VG

=
+ * def [_a-z][_a-z0-9]* [0-9][0-9]* ;
51

WHITESPACE [ \t\n\r]+

Lexer Manual

Fazer manualmente envolve diversas dificuldades, como j vimos


Tratar espaos em branco Tratar tokens de mltiplos caracteres Diferenciar identificadores de palavras reservadas Criao de buffer

No seria possvel criar o lexer automaticamente a partir da especificao?


52

Lexer Automtico

Cada expresso regular da especificao deve ser transformada em um reconhecedor

Recebe uma sequncia de caracteres de entrada Retorna se ela casa ou no com a expresso
Reconhecedor sim/no
53

palavra
(encontrada no cdigo fonte)

Expresses Regulares

Expresses bsicas

Para representar um caractere x qualquer: x Para representar a palavra vazia:

Operadores

ab concatenao: a seguido de b a|b unio: a ou b a* zero ou mais ocorrncias de a

54

Autmatos Finitos

Autmatos Finitos

Formalismo reconhecedor de linguagens

Linguagem: conjunto de palavras

Foram vistos em Teoria da Computao, junto com expresses regulares So equivalentes s expresses regulares, ou seja, representam as mesmas linguagens
56

Autmatos Finitos

O primeiro tipo que veremos o autmato finito no-determinstico (AFN ou NFA)

Seguiremos a definio do livro texto para AFN, porm usando a sigla em ingls NFA

57

NFA

Um estado inicial e vrios estados de aceitao


Mudanas entre estados

Pode ler o prximo smbolo da palavra Ou pode acontecer sem leitura de smbolo:

Se existir algum caminho que pare em um estado de aceitao, a palavra dita aceita

Se no houver nenhum caminho, rejeita

58

NFA

Exemplos:

id -> he | she | his | hers


0 h 1 e i h 2 6 r s e 8 7 s 9

s 3

Exerccio:

comparacao -> < | > | <= | >= | = | <>

59

Expresso Regular NFA

Como vimos em Teoria da Computao, possvel converter de uma expresso regular para um NFA
Veremos

Converso de expresses bsicas Converso de cada operador


60

Expresso Regular NFA

Converso de cada expresso regular bsica r

61

Expresso Regular NFA

Operador de concatenao r1r2

Converter r1 para um autmato M1 e r2 para M2 Depois, criar o autmato:

62

Expresso Regular NFA

Operador de unio r1|r2


Converter r1 para M1 e r2 para M2 Depois, criar o autmato:

63

Expresso Regular NFA

Operador de concatenao sucessiva r*

Converter r para M1 Depois, criar o autmato:

64

NFA

Autmatos no-determinsticos (NFA) permitem mltiplos caminhos para leitura de uma mesma palavra

Pode ser usado, mas computacionalmente ineficiente, devido necessidade de expandir todos os caminhos

O ideal seria uma autmato sem ambiguidades no processo de reconhecimento


65

DFA

Autmato finito determinstico (AFD ou DFA) um caso especial de NFA

Sem transies vazias Com apenas uma opo de transio para cada caractere/smbolo Para todo caractere possvel, h uma transio

66

DFA

Exemplo

67

DFA

Exemplo

Diagrama de estados

Tabela
68

NFA DFA

A partir do NFA pode ser feita uma converso para um DFA por um processo genrico

Cada estado no DFA vai representar um conjuntos de estados no NFA

O DFA resultante pode ficar com mais estados, mas existe um processo genrico de minimizao de estados tambm No veremos esses dois procedimentos...
69

Autmatos

Assim, os autmatos so usados para criar reconhecedores a partir de expresses regulares dadas
Mas como usar autmatos para criar um scanner? Como fazer isso automaticamente?
70

Geradores Automticos de Lexers

Gerador Automtico de Lexers

Recebe uma especificao (na forma de regras lxicas) Como sada, gera o cdigo do lexer

Regras Lxicas

Gerador de Analisadores Lxicos

Scanner

72

Regras Lxicas

Servem para especificar as expresses regulares e os tokens associados a elas Na prtica, associa a expresso regular com algum cdigo definido pelo usurio
{ return new Token(A_PARENT); } { return new Token(F_PARENT); }

"(" ")"

[0-9]+ { return new Token(NUMERO, yytext()); }

* public String yytext(): returns the matched input text region

73

Gerando um Lexer...

Converte cada expresso regular (associada a cada token) para um NFA Une todos os NFAs em um s, criando um estado inicial e usando transies vazias

Um s estado inicial, mas vrios estados de aceitao Cada estado de aceitao vai indicar o reconhecimento de um token especfico
74

Gerando um Lexer...

Em seguida, converte o NFA combinado para um DFA

Cria estados combinando os estados do NFA

Se dois estados de aceitao do NFA forem combinados em um estado do DFA, apenas o token definido primeiro ser retornado

Trata a regra primeiro na lista

Depois, ainda pode minimizar os estados do DFA por questes de eficincia


75

Exemplo

Seja a seguinte especificao de entrada para o gerador de lexers


a abb a*b+ { return TOKEN_X; } { return TOKEN_Y; } { return TOKEN_Z; }

Convertendo cada expresso para NFAs...


76

Exemplo

NFAs para cada expresso regular

77

Exemplo

NFA combinado

78

Exemplo

Converso para DFA

79

Reconhecimento no Lexer...

Vimos como gerar o autmato para reconhecer as expresses regulares associadas aos tokens
Mas como esse autmato usado no lexer gerado automaticamente?

80

Reconhecimento no Lexer...

A cada chamada da funo nextToken(), comea um novo processo de reconhecimento

Reinicia o autmato volta ao estado inicial Retoma a leitura de onde parou na ltima chamada

L o arquivo de entrada, fazendo as transies no autmato para cada caractere

Basta consultar a tabela de transio


81

Reconhecimento no Lexer...

O reconhecimento pra quando no houver mais nenhuma transio possvel

Trata a regra maior lexema

O lexer, ento, recupera o ltimo estado de aceitao atingido

Retorna o token associado a esse estado


82

Exemplo

Reconhecimento de abbba no AFD anterior

Primeira chamada a nextToken()


Incio no estado q0 L a q2q4q7 L b q5q8 L b q6q8 L b q8 L a erro, ento volta a q8 e retorna TOKEN_Z

Segunda chamada a nextToken()


Incio no estado q0 L a q2q4q7 Fim da leitura, ento retorna TOKEN_X

83

Reconhecimento no Lexer...

Ateno: No confundam o gerador com o lexer que ele cria

O gerador l as regras lxicas, cria um autmato e, ento, gera o cdigo fonte do lexer baseado no autmato

O lexer, depois de compilado, que vai operar como descrito na ltima parte da aula

84

Exemplos de Geradores

Para C

Lex e Flex

Para Java

JLex e JFlex

Para C#

C# Lex, C# Flex
85

Bibliografia

AHO, A., LAM, M. S., SETHI, R., ULLMAN, J. D., Compiladores: princpios, tcnicas e ferramentas. Ed. Addison Wesley. 2a Edio, 2008 (Captulo 3)

86

S-ar putea să vă placă și