Compiladores (CC3001) � Aula 2: Análise Lexical
Pedro Vasconcelos
DCC/FCUP
2020
Esta aula
Análise lexical
Expressões regulares
Autómatos �nitos determinísticos
Autómatos �nitos não-determinísticos
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
Análise lexical
léxico: conjunto de palavras de uma determinada língua (. . . ); sinónimo devocabulário
Dicionário de Português Online
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
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 )...
...
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
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
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
Implementar um analisador lexical
Vamos implementar analisadores lexicais diretamente em Haskell e C.
Implementação em Haskell
Alternativas para os tokens:
data Token = ID String
| NUM Int
| LPAREN
| RPAREN
| COMMA
| IF...
deriving (Eq,Show)
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. . . )
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)
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. . . )
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
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.
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?
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
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.
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�, . . .
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
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
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
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)
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, σ)
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) }
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
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
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)
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
εε
Exemplo 1
(a|b)*acε
a cε
ε
ε
a
b
ε
Exemplo 2
0 | 1(0|1)*
ε
ε0
ε
ε ε
ε
ε
1ε
1
0
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.
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.)
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}
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
Top Related