Luiz Carlos d´Oleron – [email protected]
Análise Léxica e SintáticaTeoria e Implementação de Linguagens Computacionais - IF688 – 2007.1
Luiz Carlos d´Oleron – [email protected]
Roteiro Fases da
compilação Analise Lexica Tokens, lexemas,
expressões regulares e autômatos finitos
Analise Sintática Gramáticas e
parsers Parser trees Derivações Gramáticas
ambíguas
Ambigüidade aritméticas
Parser recursive descendent
Recursão à esquerda Gramáticas LL(k) Gramáticas LR(k) Outras gramáticas Dangling else Parsing LR de
gramáticas ambíguas
AST Referências
Luiz Carlos d´Oleron – [email protected]
Atenção!
Este material não substitui a leitura da bibliografia
Sugerimos pesquisar a leitura referenciada no final deste trabalho e no site da disciplina
Luiz Carlos d´Oleron – [email protected]
Processo de Compilação
beginif x = 5 then... 1100111
0011100011
Código Fonte Compilador Programa
output+ params
Luiz Carlos d´Oleron – [email protected]
Fases da compilaçãoab
stra
ção
implem
entação
Código fonte
tokens e lexemas
Árvoresintáticaabstrata
CódigoMáquina
AST decorada
Análise Léxica
Análise SintáticaAnálise Semântica
Geração de Código
Luiz Carlos d´Oleron – [email protected]
Background Acadêmico - CIn
Luiz Carlos d´Oleron – [email protected]
Análise Léxica
O analisador léxico é responsável por traduzir o arquivo fonte em lexemas e tokens
if (n == 0) { return 1;} else { ...} RPAR LCUR
RCUR
if LPAR
return
else
"n"id
"0"intLit
assign
"1"intLit ...comm
Luiz Carlos d´Oleron – [email protected]
Reconhecendo tokens
Expressões regulares (implementadas como Autômatos Finitos) são comumente utilizadas
Exemplos:
if IF
[a-z][a-z0-9]* ID
[0-9]+ NUM
Luiz Carlos d´Oleron – [email protected]
Análise Sintática
“syn-tax: the way in wich words are put together to form phrases, clauses or setences.”
Webster´s Dictionary
A seguinte construção é válida?
int y = 0,k = 0;int x = y+++k;
Luiz Carlos d´Oleron – [email protected]
Análise Sintática
O Analisador Sintático é responsável
por verificar quando uma sentença faz parte da gramática da linguagem.
Entrada: lexemas e tokens gerados pelo analisador léxico
Luiz Carlos d´Oleron – [email protected]
Gramáticas – descrevendo linguagens Gramáticas livres de contexto
são utilizadas para descrever linguagens de programação
Produções Símbolos terminais Símbolos não-terminais Símbolo inicial
Luiz Carlos d´Oleron – [email protected]
Exemplo
S → S ; SS → id := ES → print (L)E → idE → numE → E + EE → (S , E)L → EL → L , E
Terminais: id print , + ; := ( ) Não terminas: S E L Símbolo inicial: S → é utilizado na notação de
produções
A cadeia seguinte pertence à gramática?
a := 7;
b := c + (d := 5 + 6, d)
Luiz Carlos d´Oleron – [email protected]
Derivações Para determinar se uma cadeia pertence à
gramática pode ser utilizado o processo de Derivação:
SS ; SS ; id := Eid := E ; id := Eid := num ; id := Eid := num ; id := E + Eid := num ; id := E + (S, E)id := num ; id := id + (S, E)id := num ; id := id + (id := E, E)id := num ; id := id + (id := E + E, E)id := num ; id := id + (id := E + E, id)id := num ; id := id + (id := num + E, id)id := num ; id := id + (id := num + num, id)
Luiz Carlos d´Oleron – [email protected]
Parse treeS
SS
E
Eid :=;
E:=id
id
+ E
)( , ES
Eid :=id
EE +
num num
num
A Parse Tree é construída conectando cada derivação a sua origem.
Na prática não é implementada pelos compiladores.
Luiz Carlos d´Oleron – [email protected]
Gramáticas ambíguas Uma gramática é ambígua se a partir
dela uma sentença pode dar origem a duas arvores de parsing diferentes
Indeterminismo é problemático para a compilação
Eliminação de ambigüidade é quase sempre possível
Refatoração da gramática
Luiz Carlos d´Oleron – [email protected]
Gramáticas ambíguas
x := 1 + 2 + 3;
S
Eid :=
E + E
E + E num
num num
S
Eid :=
E + E
E + Enum
num num
Luiz Carlos d´Oleron – [email protected]
Gramática refatorada
S → S ; SS → id := ES → print (L)E → idE → numE → E + EE → (S , E)L → EL → L , E
S → S ; SS → id := ES → print (L)E → idE → numE → E + TE → TE → (S , E)L → EL → L , E
Luiz Carlos d´Oleron – [email protected]
Parsers
Utilizados para avaliar uma entrada quanto à sintaxe
Podem ser Top-down
Recursive-descent / LL(k)
Bottom-up
SRL, LR(k)
Luiz Carlos d´Oleron – [email protected]
Parser Recursive descent Algoritmo baseado em previsões Também conhecido como Predictive
Parsing Funções mutuamente recursivas Simples implementação Uma função para cada não-terminal Uma cláusula para cada produção Verifica o primeiro símbolo terminal
para decidir qual função usar
Luiz Carlos d´Oleron – [email protected]
Parser Recursive descent
Desenvolvendo um recursive descent parser
Cada não terminal 'X' dará origem a um método/função parseX();
Produções do tipo 'A | B' darão origem a cláusulas cases
Luiz Carlos d´Oleron – [email protected]
Parser Recursive descent
A ::= aBcC
B ::= CB | cC
C ::= da
parseA() { accept(‘a’); parseB(); accept(‘c’); parseC();}
parseB() { case (d): parseC(); parseB(); case (c): accept(‘c’); parseC();}
parseC() { accept(‘d’); accept(‘a’); }
Luiz Carlos d´Oleron – [email protected]
Recursive descent
Na prática constrói uma tabela de produções indexadas por não-terminais e terminais
A ::= aBcC
B ::= CB | CA
C ::= da
a c d
A A::= aBcC
B B::= CBB::= CA
C C::= da
Luiz Carlos d´Oleron – [email protected]
Recursive descent
Vantagens Fácil de implementar Fácil de entender
Desvantagens Performance deficiente Gramática reconhecida possui
restrições Sem recursão à esquerda Deve estar fatorada
Luiz Carlos d´Oleron – [email protected]
Recursive descent
A ::= aBcC
B ::= CB | CA
C ::= da
A ::= aBcC
B ::= CX
X ::= B | A
C ::= da
a c d
A A::= aBcC
B B::= CX
C C::= da
X X::=A X::=B
GramáticaLL(1)
Luiz Carlos d´Oleron – [email protected]
Gramáticas e Parsers LL(1) Gramáticas SEM entradas duplicadas na
tabela são conhecidas como LL(1) LL(1) - Left-to-right, leftmost-
derivation, 1-symbol lookahead Left-to-right – direção na qual os símbolos
serão examinados Leftmost-derivation – ordem pela qual os
símbolos não-terminais serão expandidos 1-symbol lookahead– não mais que um
símbolo será avaliado por vez Existem LL(2), LL(3),... Toda LL(1) é LL(2), toda LL(2) é LL(3),...
LL(k)
Luiz Carlos d´Oleron – [email protected]
LL(1) na prática - Applet
http://ag-kastens.uni-paderborn.de/lehre/material/uebi/parsdemo/LL1Parser.html
Luiz Carlos d´Oleron – [email protected]
Recursão à esquerda
Gramáticas LL(1) são vulneráveis às entradas duplicadas. Por exemplo, o fragmento a seguir:
E → E + TE → T
O fato de E aparecer no início do lado direito da produção é a causa do problema. Isso é conhecido como Recursão à Esquerda. Para corrigir isso, vamos refatorar a gramática, com Recursão à Direita:
E → T E´E´ → +T E´ E´ →
Luiz Carlos d´Oleron – [email protected]
Gramáticas e Parsers LR(1) As fraquezas de LL(k) são superadas
pela técnica LR(k) LR(1) - Left-to-right, rightmost-
derivation, 1-symbol lookahead Uso de uma pilha para armazenar
símbolos de forma temporária Possui duas operações, shift e reduce shift: Move o primeiro símbolo para o
topo da pilha reduce: escolhe uma regra da
gramática do tipo X→A B C. push X da pilha e pop C B A.
Luiz Carlos d´Oleron – [email protected]
Outros Parsers LR LR(0)
Olham apenas para a pilha SLR
Melhoramento sobre o LR(0) LR(1)
Lookahead de 1 símbolo Consegue descrever a maioria das
linguagens de programação LALR(1)
Melhoramento sobre o LR(1) Diminuí o tamanho da tabela de parsing
Luiz Carlos d´Oleron – [email protected]
shift-reduce na prática - Applet
http://ag-kastens.uni-paderborn.de/lehre/material/uebi/parsdemo/SRParser.html
Luiz Carlos d´Oleron – [email protected]
Parsing LR de Gramáticas Ambíguas Gramáticas ambíguas ocasionam
conflitos em parsers LR Shift-reduce conflict
O parser não consegue decidir se empilha o próximo símbolo da entrada, ou se reduz para uma regra já disponível
Reduce-reduce conflict O parser pode realizar uma redução
para duas regras distintas
Luiz Carlos d´Oleron – [email protected]
Parsing LR de Gramáticas Ambíguas Caso clássico: dangling-else
S ::= 'if' E 'then' S 'else' SS ::= 'if' E 'then' SS ::= ...
Luiz Carlos d´Oleron – [email protected]
Parsing LR de Gramáticas Ambíguas
if a then if b then s1 else s2
if a then { if b then s1 else s2 }
if a then { if b then s1 } else s2
?
Luiz Carlos d´Oleron – [email protected]
Parsing LR de Gramáticas Ambíguas Solução:
Transformar a gramática Introdução dos conceitos de matched e
unmatched
S ::= 'if' E 'then' S 'else' SS ::= 'if' E 'then' SS ::= ...
S ::= M | U
M ::= 'if' E 'then' M 'else' M | ...
U ::= 'if' E 'then' S | 'if' E 'then' M 'else' U
Luiz Carlos d´Oleron – [email protected]
LR(0)LL(0)
SLR
LALR(1)
LL(k)
LL(1)
Gramáticas não-ambíguas Gramáticas ambíguas
LR(1)
LR(k)
Luiz Carlos d´Oleron – [email protected]
Sintaxe abstrata Apenas reconhecer se uma sentença
pertence ou não a linguagem especificada por uma gramática não é o suficiente
É necessário produzir uma estrutura que sirva de base para a próxima fase do processo de compilação Parse trees nunca são montadas na
prática
Luiz Carlos d´Oleron – [email protected]
AST – Abstract Syntax Tree Capturam a essência da estrutura de
uma gramática abstraindo não-terminais
Representação possível Java: Classes que possam se relacionar
a fim de montar uma árvore
Pode ser produzida através da inserção de ações semânticas no parser
Luiz Carlos d´Oleron – [email protected]
AST – Abstract Syntax Tree
IfThenElse ::= 'if' expr 'then' comm1 'else' comm2
return new IfThenElse(expr, comm1, comm2);
IfThenElse
expr : Expressioncomm1 : Commandcomm2 : Command
Luiz Carlos d´Oleron – [email protected]
Luiz Carlos d´Oleron – [email protected]
Referências
Análises léxica e sintática, Mauro La-Salette C. L. de Araújo
Modern Compiler implementation in Java, Andrew W. Appel