compiladores (cc3001) aula 2: análise lexical

36

Upload: others

Post on 08-Jul-2022

11 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Compiladores (CC3001) Aula 2: Análise Lexical

Compiladores (CC3001) � Aula 2: Análise Lexical

Pedro Vasconcelos

DCC/FCUP

2020

Page 2: Compiladores (CC3001) Aula 2: Análise Lexical

Esta aula

Análise lexical

Expressões regulares

Autómatos �nitos determinísticos

Autómatos �nitos não-determinísticos

Page 3: Compiladores (CC3001) Aula 2: Análise Lexical

Re-lembrar: fases dum compilador

texto do programa↓

Análise lexical

↓sequência de tokens

↓Análise sintática

↓árvore sintática abstrata

↓Análise semântica

↓AST & tabela de símbolos

Geração de código↓

código intermédio

Seleção de instruções↓

código assembly simbólico↓

Alocação de registos↓

código assembly concreto↓

Assembler & linker

↓código executável

Page 4: Compiladores (CC3001) Aula 2: Análise Lexical

Análise lexical

léxico: conjunto de palavras de uma determinada língua (. . . ); sinónimo devocabulário

Dicionário de Português Online

Page 5: Compiladores (CC3001) Aula 2: Análise Lexical

Análise lexical (cont.)

I Léxico de uma linguagem de programação: conjunto dos símbolos e palavrasusados para compor programas (tokens)

identi�cadores nomes de variáveis, funções, etc.literais números, caracteres, cadeias

palavras reservadas if, else, while, etc.operadores +, *, /, =, . . .

I Um analisador lexical (também chamado lexer, scanner ou tokenizer) decompõe otexto de entrada em tokens

I Esta decomposição facilita a análise sintática subsequente

Page 6: Compiladores (CC3001) Aula 2: Análise Lexical

Alguns exemplos de tokens

Para a linguagem C:

ID foo main __last_14

NUM 73 0 -13 0xff

REAL 66.1 .5 10.0 5.5e-10

IF if

COMMA ,

NOTEQ !=

LPAREN (

RPAREN )...

...

Page 7: Compiladores (CC3001) Aula 2: Análise Lexical

Representação de tokens

I Os tokens são identi�cados por uma etiqueta (token type)I Nalguns casos podem ter também um valor associado

etiqueta valorif IF �, COMMA �!= NOTEQ �( LPAREN �) RPAREN �main ID �main�71 NUM 71.5 REAL 0.5

Page 8: Compiladores (CC3001) Aula 2: Análise Lexical

Análise lexical: exemplo

float match0(char *s) /* find a zero */

{ if (!strncmp(s, "0.0", 3))

return 0.0;

}

FLOAT, ID(�match0�), LPAREN, CHAR, STAR, ID(�s�), RPAREN, LBRACE, IF,LPAREN, BANG, ID(�strncmp�), LPAREN, ID(�s�), COMMA, STRING(�0.0�),COMMA, NUM(3), RPAREN, RPAREN, RETURN, REAL(0.0), SEMI, RBRACE,EOF

Page 9: Compiladores (CC3001) Aula 2: Análise Lexical

Análise lexical: exemplo (cont.)

I Além de separar os tokens, a análise lexical consume:I carateres brancos (espaços, mudanças de linhas e tabulações);I comentários multi-linha /* ... */ ou até ao �nal da linha //

I Usamos um token EOF para marcar o �m do input

Page 10: Compiladores (CC3001) Aula 2: Análise Lexical

Implementar um analisador lexical

Vamos implementar analisadores lexicais diretamente em Haskell e C.

Page 11: Compiladores (CC3001) Aula 2: Análise Lexical

Implementação em Haskell

Alternativas para os tokens:

data Token = ID String

| NUM Int

| LPAREN

| RPAREN

| COMMA

| IF...

deriving (Eq,Show)

Page 12: Compiladores (CC3001) Aula 2: Análise Lexical

Implementação em Haskell (cont.)

O analisador é implementado como uma função:

lexer :: [Char] -> [Token]

I Transforma uma lista de carateres numa lista de tokens

I De�nida por análise de casos sobre o próximo carater

(Segue-se uma demonstração. . . )

Page 13: Compiladores (CC3001) Aula 2: Análise Lexical

Implementação em C

typedef enum { ID, NUM, LPAREN, RPAREN, COMMA, IF,...

} Token;

I Uma enumeração para os tipos de tokens

I Os valores de tokens como ID e NUM são representados separadamente (porque a

linguagem C não tem tipos algébricos)

Page 14: Compiladores (CC3001) Aula 2: Análise Lexical

Implementação em C (cont.)

O analisador é implementado como uma função:

Token getToken(void);

I Retorna o tipo do próximo token da entrada

I O valor dos tokens é guardado em variáveis de estado (e.g. globais)

int token_value; /* valor de NUM */

char token_text[MAX_SIZE]; /* texto do ID */

(Segue-se uma demonstração. . . )

Page 15: Compiladores (CC3001) Aula 2: Análise Lexical

Observações

I Faltam: comentários, números de vírgula �utuante, operadores e palavrasreservadas. . .

I Estes programas são simples mas bastante repetitivos

I É necessário algum cuidado com a ordem das condições(e.g. �if� deve ser uma palavra reservada e não um identi�cador)

I São difíceis de modi�car

Page 16: Compiladores (CC3001) Aula 2: Análise Lexical

Observações (cont.)

Em vez de escrever o analisador lexical manualmente podemos:

I descrever os tokens usando expressões regulares;

I gerar automaticamente o analisador a partir dessa descrição.

Page 17: Compiladores (CC3001) Aula 2: Análise Lexical

Descrever tokens

Como são identi�cadores em C?

An identi�er is a sequence of letters and digits; the �rst character must be

a letter. The underscore _ counts as a letter. Upper- and lowercase letters

are di�erent. If the input stream has been parsed into tokens up to a given

character, the next token is taken to include the longest string of characteres

that could possibly constitute a token. Blanks, tabs, newlines, and comments

are ignored except as they serve to separate tokens. Some white space is

required to separate otherwise adjacent identi�ers, keywords, and constants.

(fonte: Modern Compiler Implementation in ML)

Os analisadores anteriores estão incompletos � consegue ver o que falta?

Page 18: Compiladores (CC3001) Aula 2: Análise Lexical

Expressões regulares

I Em vez de implementar analisadores diretamente, vamos descrever os tokensusando expressões regulares

I Vantagens:1. as expressões regulares permitem descrições concisas e não-ambíguas2. podem ser automaticamente traduzidas para automátos �nitos que implementam

analisador lexicais e�cientes

Page 19: Compiladores (CC3001) Aula 2: Análise Lexical

Re-lembrar

Uma linguagem é um sub-conjunto L ⊆ Σ∗ de palavras formadas a partir de umalfabeto Σ.

As expressões regulares (REs) são:

a uma letra a ∈ Σ

ε palavra vazia

M |N união de duas expressões regulares M e N

M · N concatenação1 de duas expressões regulares M e N

M∗ repetição2 de M, i.e., a concatenação de zero ou mais palavras de M

1Ou seja: as palavras de M · N são u · v tal que u ∈ L(M) ∧ v ∈ L(N).2Também designada fecho de Kleene.

Page 20: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplos

Expressão regular Linguagema · b �ab�a|b �a�, �b�

(a · b) · a �aba�(a · b)|(b · a) �ab�, �ba�

(a|b) · a �aa�, �ba�(a|ε) · b �b�, �ab�(a|b)∗ ��, �a�, �b�, �aa�, �ab�, �ba�, �bb�, . . .(a · b)∗ ��, �ab�, �abab�, �ababab�, . . .

Page 21: Compiladores (CC3001) Aula 2: Análise Lexical

Convenções

I Podemos omitir o sinal da concatenação (não é ambíguo por causa daassociatividade)

abc = (a · b) · c = a · (b · c)

I Prioridades: repetição > concatenação > união

ab|c = (ab)|c abb∗ = ab(b∗)

I Abreviaturas:

M?def= (M | ε) opcional

M+ def= M ·M∗ repetição (uma ou mais vezes)

[x1x2 . . . xn]def= (x1|x2| . . . |xn) alternativas

[a1 − an]def= (a1|a2| . . . |an) intervalos de carateres contíguos

Page 22: Compiladores (CC3001) Aula 2: Análise Lexical

Notação para REs

a um carater literalM|N alternativa entre M ou NMN concatenação de M com NM* repetição (zero ou mais vezes)M+ repetição (uma ou mais vezes)M? opção (zero ou uma ocorrência de M)[a-zA-Z] qualquer carater destes intervalos[�a-zA-Z] complementar (qualquer carater fora dos intervalos). qualquer carater exepto mudança de linha\ escape (para carateres especiais)"a+" cadeia literal (entre aspas)"" cadeia vazia

Page 23: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplos

if palavra reservada (IF)[_a-zA-Z][_a-zA-Z0-9]* identi�cadores (ID)[0-9]+ número inteiro (NUM)([0-9]+"."[0-9]*)|([0-9]*"."[0-9]+) número fracionário (REAL)//.* comentário até ao �nal da linha

Page 24: Compiladores (CC3001) Aula 2: Análise Lexical

Implementação de analisadores

I As expressões regulares são descrições declarativas dos tokensI Para implementar o analisador necessitamos de um modelo operacional

I Solução: converter as expressões regulares em autómatos �nitosI A conversão pode ser efetuada por um gerador de analisadores (próxima aula)

Page 25: Compiladores (CC3001) Aula 2: Análise Lexical

Autómatos �nitos determinísticos (DFAs)

(Σ,Q, q0,F , δ) autómatoΣ alfabetoQ conjunto dos estadosq0 ∈ Q estado inicialF ⊆ Q estados �naisδ ⊆ Q × Σ× Q transições

I Um conjunto �nito de estados e um conjunto �nito de transiçõesI Um único estado inicial e um conjunto de estados �naisI As transições são determinísticas:

I para cada q ∈ Q e σ ∈ Σ existe no máximo um q′ tal que (q, σ, q′) ∈ δI podemos também ver δ como uma função: q′ = δ(q, σ)

Page 26: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplo: DFA para identi�cadores

1 2_,a-z,A-Z

_,a-z,A-Z

0-9

Σ é o conjunto de carateres ASCII

Q = {1, 2}q0 = 1

F = {2}δ = { (1, _, 2), (1, a, 2), (1, b, 2), . . . , (1, z, 2), (1, A, 2), (1, B, 2), . . . , (1, Z, 2),

(2, _, 2), (2, a, 2), (2, b, 2), . . . , (2, z, 2), (2, A, 2), (2, B, 2), . . . , (2, Z, 2),(2, 0, 2), (2, 1, 2), . . . , (2, 9, 2) }

Page 27: Compiladores (CC3001) Aula 2: Análise Lexical

Converter uma expressão num autómato

1 2_,a-z,A-Z

_,a-z,A-Z

0-9

I Este DFA é equivalente à expressão [_a-zA-Z][_a-zA-Z0-9]*

I No caso geral: para converter uma RE num DFA temos de obter primeiro umautómato não-determínístico (NFA)

I Não podemos implementar o NFA diretamente (por causa do não-determinísmo)I Contudo podemos sempre converter o NFA num DFA equivalente

Page 28: Compiladores (CC3001) Aula 2: Análise Lexical

Autómatos �nitos não-determísticos (NFAs)

(Σ,Q, q0,F , δ) autómato �nito não-determinístico... (de�nições de alfabeto, estados, etc. inalteradas)

δ ⊆ Q × (Σ ∪ {ε})× Q transições

I Várias transições com o mesmo símbolo a partir de um estado, e.g.

1

2

3

a

a

I Transições-ε (não consomem um símbolo), e.g.

1

2

3

ε

a

Page 29: Compiladores (CC3001) Aula 2: Análise Lexical

Conversão de uma RE num NFA

Para cada RE de�nimos um fragmento de autómato:

I Uma entrada unica (seta) e saida única (linha)

fragmento

I A composição de fragmentos segue a estrutura da expressão, e.g.:

a b

⇓ε

ε

a

b

ε

(fragmento para a|b)

Page 30: Compiladores (CC3001) Aula 2: Análise Lexical

Conversão de uma RE num NFA (cont.)

σ σ (σ ∈ Σ) ε ε

Se A, B são duas sub-expressões:

A · B A B A |BA

B

ε

ε

ε

A∗

A

εε

Page 31: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplo 1

(a|b)*acε

a cε

ε

ε

a

b

ε

Page 32: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplo 2

0 | 1(0|1)*

ε

ε0

ε

ε ε

ε

ε

1

0

Page 33: Compiladores (CC3001) Aula 2: Análise Lexical

Implementar NFAs

Di�culdades:I as transições-ε podem ocorrem sem consumir o próximo símbolo;I num estado q e para o próximo símbolo σ pode have transições para dois ou mais

estados distintos.

Solução: temos de converter o NFA num DFA equivalente (�construção dos

sub-conjuntos�).I os estado do DFA são sub-conjuntos de estados do NFA;I as transições do DFA �simulam� todas as transições possíveis pelo NFA.

Page 34: Compiladores (CC3001) Aula 2: Análise Lexical

Converter um NFA num DFA

Seja A = (Σ,Q, q0,F , δ) um NFA.

De�nimos:

closure(S) = { q′ ∈ Q : existe q ∈ S e um caminho de transições-ε entre q e q′) }

Transformamos A no DFA A′ = (Σ, 2Q , S0, F ′, δ′) tal que:

S0 = closure({q0})F ′ = { S ⊆ Q : S ∩ F 6= ∅ }

δ′(S , σ) = closure({q′ : q ∈ S ∧ (q, σ, q′) ∈ δ})

(Nota: podemos de�nir δ′ como uma função porque A′ é determinístico.)

Page 35: Compiladores (CC3001) Aula 2: Análise Lexical

Exemplo

1 2 3 4

7

6

5 8

εa c

ε

ε

ε

a

b

ε

Σ = {a, b, c} símbolos

Q = {1, 2, 3, 4} estados

q0 = 1 estado inicial

F = {4} estados �nais

S0

S1

S2

S3

a

b

a

b

b

a

c

S0 = {1, 2, 5, 6, 7}S1 = {1, 2, 3, 5, 6, 7, 8}S2 = {1, 2, 5, 6, 7, 8}S3 = {4}

Page 36: Compiladores (CC3001) Aula 2: Análise Lexical

Minimização de autómatos

I O DFA obtido pela construção dos sub-conjuntos pode ainda ter estadosredudantes

I Podemos �fundir� estados equivalentes e obter assim o autómato mínimoI Os geradores de analisadores lexicais efetuam esta minimização automaticamente

S0

S1

S2

S3

a

b

a

b

b

a

c

S0≡S2=⇒ S0

S1

S3

a

b

ac

b