Conteúdo da aula nalisadores Descendentes Tabulares; Cjs First Follow Marcelo Johann nalisadores Descendentes Recursivos com Retrocesso Recursivos Preditivos Conjunto FIRT e Implementação nalisador Preditivo Tabular Conjuntos FIRT e FOLLOW Montagem da Tabela Implementação YCC INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 2 Definição: Conjuntos First eja α qualquer seqüência de símbolos terminais ou não terminais First(α): Definição informal: conjunto de todos os terminais que começam qualquer seqüência derivável de α. Definição formal: e existe um t T e um β V* tal que α * t β então t First(α) e α * ε então ε First(α) C D First()={b,c,d b First()={b C c First(C)={c D d First(D)={d INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 3 Condição para que se possa usar um analisador preditivo Informalmente: no caso que em os First() dos lados direitos das regras de produção sejam simpáticos, não terá retrocesso. Formalmente: para qualquer produção α 1 α 2... α n, quer-se: First(α 1 ) First(α 2 )... First(α n ) = Ø INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 4 Repeat { proc First(α: string of symbols) Para todas as produções α X 1 X 2 X 3 X n do if X 1 T then // caso simples onde X 1 é um terminal First(α) := First(α) {X 1 else { // caso menos simples: X 1 é um não-terminal First(α) = First(α) First{X 1 \ {ε; for (i=1 ; i<=n ; i++) { if ε is in First(X 1 ) and in First(X 2 ) and in First(X i-1 ) First(α) := First(α) First(X i ) \ {ε if (α =>* ε) then First(α) := First(α) {ε end do until no change in any First(α) INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 5 proc Follow( N) Follow() := {; Repeat foreach p P do { // Laço sobre as produções case p == X α // a produção termina por Follow() := Follow() Follow(X); case p == X αβ { // a produção NÃO termina por Follow() := Follow() First(β)\{ε; if ε First(β) then Follow() := Follow() Follow(X); end until no change in any Follow() INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 6 1
Observações First/Follow ó terminais entram em First e Follow. O algoritmo de cálculo de First(α): É trivial quando α é um terminal t. varre as produções X tω quando α é um não-terminal X; é chato quando o início de uma derivação se α deriva em ε. Inclui ε apenas quando α pode derivar em ε. O algoritmo de cálculo de Follow() É reservado aos não-terminais Inclui o em alguns casos triviais ( == o start ) Varre as produções onde aparece à direita (X ωω ) É chato quando aparece no fim (ou logo antes de algo que deriva em ε) NUNC inclui ε Exemplo First/Follow XYZ INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 7 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 8 Exemplo First/Follow XYZ First(X) = {a, ε Follow(X) = {c, d, b, e, f First(Y) = {c, d Follow(Y) = {e, f First(Z) = {e, f Follow(Z) = {, c, d First() = {a, c, d Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 9 Gramática LL(1) Condições necessárias: sem ambigüidade sem recursão a esquerda Uma gramática G é LL(1) se e somente se Para qualquer produção do tipo: α β * t 1. First(α) First(β) = 2. α * ε implies!(β * ε) 3. α * ε implies First(β) Follow() = LL(1) = leitura Left -> right + derivação mais a esquerda (Left) + uso de 1 token lookahead. INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 10 nálise top-down com tabela preditiva Os dois métodos apresentados até agora para fazer análise descendente (top-down) usam recursividade. Cada não-terminal tem um procedimento associado; Há chamadas com ou sem retrocesso. Para gramáticas LL1 não tem retrocesso. Chamadas recursivas usam uma pilha implícita pilha das chamadas! obrecusto! Reconhecedor preditivo com Pilha Tem um buffer de símbolos em entrada; marca seu fim. Tem um fluxo de saída; Usa uma pilha cujo fundo é marcado por Inicializada com (tart) Usa uma tabela sintática preditiva M if ( idf ) uffer de entrada Idéia: de-recursificar o procedimento: Usa-se uma pilha para armazenar os não-terminais encontrados; Usa-se uma tabela para orientar as derivações. Ver o uso de tabelas para derecursificar um algoritmo em programação dinâmica. Pilha Parser preditivo top-down aída INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 11 Tabela INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 12 2
Funcionamento do parser eja X o símbolo no topo da pilha eja a o símbolo de entrada (terminal/token de lookahead) a analisar Etapas: 1. e X == e a == : para e reconheceu uma sentença. 2. e X == a e a!= : desempilha X e avança de um símbolo na entrada. 3. e X é um não-terminal: Consulta a tabela M(X, a) e for vazia: ERRO e contém X UVW, então substitui na pilha X por UVW (U no topo). INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 13 Como construir a tabela? (Re-escrever a gramática para satisfazer condições de LL(1) isso é um pre-requisito!) Calcular os conjuntos First e Follow Para cada produção α na gramática: 1. Para cada terminal a First(α) incluir a produção α em M[, a] 2. e ε First(α) incluir a produção α em M[,b] para cada b em Follow() 3. e ε First(α) e Follow() incluir a produção α em M[,] Todas as entradas não definidas são erros INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 14 tabela preditiva M(X, t) First() = {c Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 15 First() = {c Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 16 c c First() = {c Follow() = { First() = {c Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 17 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 18 3
c c bc First() = {c Follow() = { First() = {c Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 19 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 20 c ε bc ERRO ERRO ERRO c ERRO ε bc ERRO ERRO First() = {c Follow() = { First() = {c Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 21 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 22 Usando a tabela tring: cbca Pilha Entrada ção c bc c cbc cbc bc bc bc c ->ca casar c -> ->bc casar b casar c -> ε casar a casar, sucesso E TE E +TE ε T FT T *FT ε F (E) Id Mais um exemplo... ímbolo E E T T F First {(, id {+, ε {(, id {*, ε {(, id Follow {, ) {, ) {+,, ) {+,, ) {*, +,, ) INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 23 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 24 4
XYZ Exemplo LL(1) Construir Tabela nalisar abcdfcf First(X) = {a, ε Follow(X) = {c, d, b, e, f First(Y) = {c, d Follow(Y) = {e, f First(Z) = {e, f Follow(Z) = {, c, d Observação sobre a Tabela tabela indica se há ambigüidade! Mais de uma regra numa entrada! oluções? Tornar a gramática LL(1) Eliminar ambiguidade, recursividade... Usar uma heurística para desempatar as regras Qual? Usar outros algoritmos do que os top-down! Exemplo total: if... Then... Else: i E t i E t e a E b First() = {a, c, d Follow() = { INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 25 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 26 Retornando ao Gerador Yacc Leituras e Tarefas sugeridas Makefile: continuando Produções entre %% e %% %token %type, %union e yy.lval Repetir os experimentos com yacc feitos pelo professor com etapa1 Implementar uma outra gramática com o código de analisador tabular INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 27 INF01033 - Compiladores - Marcelo Johann - 2012/1 ula 08 : lide 28 5