Compiladores
Análise Sintática
▪ Vejamos um exemplo, seja a seguinte instrução de atribuição:
▪ posicao = inicial + incremento * 60
▪ Na análise sintática tenta-se construir uma frase correta com os tokens produzidos pela fase anterior. É usual construir uma estrutura em árvore para representar a frase obtida.
▪ A partir dos tokens cria uma representação intermediária tipo árvore (árvore sintática)
Análise sintática
▪ Regras Sintáticas
▪ Especificam as sequências de símbolos que constituem estruturas sintáticas válidas; ▪ Estas regras permitem o reconhecimento de expressões e comandos;
▪ Exemplo:
▪ Pascal: atribuição → a:=b; ▪ C: atribuição → a=b;
Análise sintática
As linguagens de programação possuem regras precisas para descrever a estrutura sintática de programas bem formados;
Exemplo: Linguagem C
Funções ➔ declaração e comando Comando ➔ expressões
A estrutura sintática das construções de uma linguagem de programação é especificada pelas regras gramaticais de uma gramática livre de contexto
Análise sintática
Benefícios para projetistas de linguagens:
▪ Uma gramática provê uma especificação sintática precisa e fácil de entender para as linguagens de programação;
▪ A partir de determinadas classes gramaticais, podemos construir automaticamente um analisador sintático eficiente;
▪ Durante o processo de construção do analisador, podem ser detectadas
ambiguidades sintáticas;
▪ Uma gramática permite o desenvolvimento de uma linguagem iterativamente, possibilitando lhe acrescentar novas construções para realizar novas tarefas;
Análise sintática
▪ Utiliza os tokens produzidos pela análise léxica e verifica a formação do programa com o uso de GLC (Gramáticas Livres de Contexto)
▪ A partir dos tokens é criada uma representação intermediária da árvore sintática ➔ mostra a estrutura gramatical da sequência de tokens;
Análise Sintática
▪ posicao = inicial + incremento * 60
<id, 1>, <=>, <id, 2>, <+>, <id, 3>, <*>, <numero, 60>
Analisador Sintático <=> <id, 1> <+> <id,2> <*> <id,3> 60 Árvore Sintática
Análise sintática
▪ O analisador sintático recebe do analisador léxico uma cadeia de tokens
representando o programa fonte e verifica se essa cadeia de tokens
Análise sintática
O analisador sintático constrói uma árvore de derivação e a passa ao
restante do front-end do compilador para processamento.
Obs: na prática não é necessário construir a árvore de derivação
explicitamente, pois as ações de verificação e tradução podem ser
implementados em um único módulo.
Análise sintática
Existem 3 estratégias gerais de análise sintática para o processamento de gramáticas: Universal, Descendente (Top –Down) e Ascendente (Bottom –Up).
Em ambas as estratégias a entrada do analisador sintático é consumida da
esquerda para a direita, um símbolo de cada vez
Os analisadores criados à mão normalmente utilizam gramáticas LL
Os analisadores sintáticos para a maioria de gramáticas LR geralmente são construídos utilizando ferramentas automatizadas
Análise sintática
▪ Para descrever uma linguagem é necessário uma série de regras gramaticais;
▪ As regras são formadas por uma única estrutura do lado esquerdo seguida do metasímbolo “::=“ e por uma sequência de itens do lado direito (símbolos ou estruturas);
▪ Estruturas entre <> são chamadas de não terminais;
▪ Símbolos como garota e cachorro são chamados de terminais; ▪ As regras gramaticais são as produções.
Análise sintática
▪ Exemplo de uma gramática para expressões aritméticas de adição e multiplicação:
▪ <exp>::= <exp>+<exp> | <exp>*<exp> | (exp) | <num> ▪ <num> ::= <num><digito> | <digito>
Análise sintática
▪ BNF
▪ Sentenças simples consistem de uma frase nominal e de uma frase verbal seguida de um ponto, da seguinte maneira:
▪ <sentence> ::= <frase_nominal><frase_verbal>.
▪ Deve-se saber descrever a estrutura de uma frase nominal e de uma frase verbal: ▪ <frase_nominal> ::= <artigo><substantivo>
▪ <artigo> ::= um | a
▪ <substantivo> ::= garota | cachorro
▪ <frase_verbal> ::= <verbo> <frase_nominal> ▪ <verbo> ::= viu | abraça
Análise sintática
▪ Cada regra gramatical apresentada consiste de uma string colocada entre “<“ e “>”, esta string é o nome da estrutura que está sendo descrita;
▪ O símbolo ::= pode ser lido como “consiste de” ou “é o mesmo que”; ▪ Após o símbolo ::=, temos uma sequência de outros nomes e símbolos;
Análise sintática
▪ Construção de uma sentença legal:
▪ Inicia-se com o símbolo <sentença> e prossegue-se trocando o lado esquerdo por alternativas do lado direito nas regras;
▪ Este processo criará uma derivação na linguagem;
Análise sintática
▪ Montando a derivação da sentença: “a garota viu um cachorro” ▪ <sentença> → <frase_nominal><frase_verbal>.
▪ → <artigo><substantivo><frase_verbal>. ▪ → a <substantivo><frase_verbal>.
▪ → a garota <frase_verbal>.
▪ → a garota <verbo><frase_nominal>. ▪ → a garota viu <frase_nominal>.
▪ → a garota viu <artigo><substantivo>. ▪ → a garota viu um <substantivo>.
▪ → a garota viu um cachorro.
▪ Pode-se começar com a sentença “a garota viu um cachorro”, e voltar até <sentença> para provar que é uma sentença válida da linguagem.
Análise sintática - Extensão da BNF ➔ EBNF (Extend BNF)
Definição EBNF para uma linguagem de programação simples
Análise sintática – Recursão a Esquerda
Na gramática a seguir, o não-terminal E representa expressões consistindo
em termos separados pelo operador +; T representa termos consistindo em
fatores separados pelo operador *; e F representa fatores que podem ser
expressos entre parênteses ou identificadores.
E→ E+T | T
T → T*F | F
F → (E) | id
Essa gramática não pode ser usada com o método de análise descendente
pois é recursiva a esquerda.
Análise sintática – Recursão a Esquerda
Gramáticas são recursivas à esquerda se possui um não-terminal A para o qual existam derivações do tipo A➔Aα para uma cadeia α.
Para o par de produções recursivas à esquerda A ➔ Aα|β
A substituição abaixo elimina a recursão imediata à esquerda:
A ➔ βA’
A’ ➔ αA’ | ε
Análise sintática – Recursão a Esquerda
Gramática para expressões simples:
E → E + T | T T → T * F | F F → ( E ) | id
Aplicando transformação na Primeira Regra E → E + T | T é do tipo A ➔ Aα | β Obtemos: A ➔ βA’ E ➔TE’ A’ ➔ αA’ | ε E’ ➔ +TE’ | ε
Análise sintática – Recursão a Esquerda
Gramática para expressões simples:
E → E + T | T T → T * F | F F → ( E ) | id
Aplicando transformação na Segunda Regra E → T * F | F é do tipo A ➔ Aα | β Obtemos: A ➔ βA’ T ➔FT’ A’ ➔ αA’ | ε E’ ➔ *FT’ | ε
Análise sintática – Recursão a Esquerda
Assim, obtemos a partir
de:
E → E + T | T
T → T * F | F
F → ( E ) | id
A gramática equivalente sem recursão à
esquerda:
E → TE’
E’ → +TE’
T → FT’
T’ → *FT’ | ε
F → (E) | id
Análise sintática – Recursão a Esquerda
Exemplo 2: A→ Aa | b Exemplo 3: S → SS+ | SS* | a Exemplo 4: S → Sa | B B → Bb | cPara o par de produções recursivas à esquerda A ➔ Aα|β
Considere para eliminar a recursão A ➔ βA’
Análise sintática – Recuperação de erro
O recuperador de erros em um analisador sintático possui objetivos simples, mas desafiadores:
▪ Informar a presença de erros de forma clara e precisa;
▪ Recuperar-se de cada erro com rapidez suficiente para detectar erros subsequentes;
▪ Acrescentar um custo mínimo no processamento de programas corretos.
Como um recuperador de erro deve informar a presença de um erro?
No mínimo ele precisa informar o local no programa fonte onde o erro foi detectado, pois existe uma boa chance de que o local exato do erro seja em um dos tokens anteriores.
Análise sintática – Recuperação de erro
Recuperação em nível de frase
Ao detectar um erro, o analisador sintático pode realizar a correção local
sobre o restante da entrada.
Uma correção local típica compreende a substituição de uma vírgula por um
ponto-e-vírgula, exclusão de um ponto-e-vírgula desnecessário.
Análise sintática – Recuperação de erro
Produções de Erro
Nesta estratégia de recuperação de erro podemos estender a gramática da
linguagem em mãos com produções que geram construções erradas,
antecipando assim os erros mais comuns.
Análise sintática
▪ Não é possível enumerar a sintaxe de todos os programas das mais diferentes linguagens;
▪ É necessário uma maneira de definir um conjunto infinito usando uma descrição finita:
▪ A sintaxe de uma linguagem é definida através de uma gramática;
▪ Gramática: conjunto de regras que definem todos os construtores que podem ser aceitos na linguagem.
Análise sintática
▪ Fortran foi definido através da especificação de algumas regras em inglês;
▪ Algol 60 foi definido através de uma gramática livre de contexto desenvolvida por Jonh Backus;
▪ Essa gramática ficou conhecida como BNF (Backus-Naur Form);
▪ BNF foi utilizada posteriormente na definição de várias linguagens como C, Pascal e Ada;
▪ BNF é uma metalinguagem pois consiste numa linguagem para descrição de outras linguagens.
Análise sintática
▪ Observe os dois trechos de código a seguir, sendo o código a. em C e o código b. em Pascal
a. b.
while(x!=y) while x<>y do
{ begin
... ...
} end
▪ Ambas possuem a mesma estrutura conceitual, porém, diferem na aparência léxica;
▪ Quando duas construções diferem apenas no nível léxico, se diz que elas seguem a mesma sintaxe abstrata e diferem na sintaxe contreta.
Análise sintática
▪ Com tudo isso, é possível concluir que a descrição sintática de uma linguagem:
▪ Ajuda o programador a saber como escrever um programa sintaticamente correto; ▪ Pode ser usada para determinar se um programa está sintaticamente correto ➔ este
Análise sintática - Análise Top-Down
▪ Como reconhecer se uma sentença está de acordo com uma gramática?
▪ Pode-se implementar reconhecedores de sentença ▪ Recursivamente, com retrocesso
▪ Com mecanismo preditivo ▪ First e Follow
▪ Para usar os reconhecedores, primeiramente deve-se transformar a Gramática Livre de Contexto
▪ Eliminação de produções vazias
▪ Eliminação de recursividade a esquerda ▪ Fatoração de uma gramática
Análise sintática – Conjuntos First
▪ First(α)
▪ Definição informal: conjunto de todos os terminais que começam com qualquer sequência derivável de α
▪ Definição formal
▪ Se existe um t ∈ T e um β ∈ V* tal que α ⇒* t β então t ∈ First(α) ▪ Se α ⇒* ε então ε ∈ First(α)
A → B | C | D first(A) = {b, c, d}
B → b first(B)= {b}
C → c first(C)= {c}
Análise sintática – Conjuntos First
▪ Para determinar o FIRST(A):
▪ Se a é terminal, então o first(a) = a;
▪ Se A é não terminal e A→aα é uma produção, então se acrescenta a ao conjunto de first de A, logo: first(A)=a;
▪ Se A→ε é uma produção ε, logo first(A)=ε;
▪ Se A→Y1Y2...Yk é uma produção, então todo i tal que todos Y1...Yi-1 são não terminais e FIRST(Yj) contém ε, onde j=1,2...i-1. acrescente todo símbolo diferente de ε de FIRST(Yj) a FIRST(A). Se ε ∈ FIRST(A), para todo i=1,2..k. então acrescente ε a FIRST(A).
Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | id First(E) = { ? } First(E’) = { ? } First(T) = { ? } First(T’) = { ? } First(F) = { ? }Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε}
First(T) = First(F) = { (, id } First(T’) = { *, ε }
Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε}
First(T) = First(F) = { (, id } First(T’) = { *, ε }
First(F) = { (, id }
Se F derivasse em ε seria
preciso incluir o first(T’)
Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ H → E’T T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε}
First(T) = First(F) = { (, id }
First(H) = { ? }
First(T’) = { *, ε } First(F) = { (, id }
Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ H → E’T T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε}
First(T) = First(F) = { (, id }
First(H) = { First(E’) U First(T) }
First(T’) = { *, ε } First(F) = { (, id }
Análise sintática – Conjuntos First
E → TE’ E’ → +TE’ | ε T → FT’ H → E’T T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε}
First(T) = First(F) = { (, id }
First(H) = { +, (, id }
First(T’) = { *, ε } First(F) = { (, id }
Análise sintática – Conjuntos Follow
▪ Se A é um não-terminal, o follow(A) é o conjunto de terminais imediatamente seguintes (à direita) de A
Análise sintática – Conjuntos Follow
▪ Para determinar follow(A)
1. Colocar $ em follow(S) se S é o símbolo de partida. $ é o marcador de fim de entrada durante análise
2. Se existe uma produção A→αBβ e β ∉ ε então tudo que estiver em first(β), exceto ε, deve ser adicionado em follow(B)
3. Se existe uma produção A→ αB ou A→ αBβ onde first(β) contem ε (β → ε), então tudo que está em follow(A) está em follow(B)
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – Conjuntos Follow
E → TE’ E’ → +TE’ | ε T → FT’ T’ → *FT’ | ε F → (E) | idFirst(E) = First(T) = First(F) ={ (,id } First(E’) = { +, ε} First(T) = First(F) = { (, id } First(T’) = { *, ε } First(F) = { (, id } Follow(E) = { ), $ } Follow(E’) = Follow(E) = { ), $ }
Follow(T) = First(E’) U Follow(E) U Follow(E’) = { +, ), $}
Follow(T’) = Follow(T) = {+, ), $} Follow(F) = First(T’) U Follow(T) U Follow(T’) = { *, +, ), $}
Análise sintática – First Follow
S→AB first(S)={c} follow(S)={ $ } A→c | ε first(A)={c, ε} follow(A)={ c } B→ cbB | ca first(B)={c} follow(B)={ $ }
Análise sintática – Analisador Top-Down
▪ A análise top-down é realizada da raiz para as folhas
▪ Parte-se de um não-terminal que é o símbolo inicial da gramática em direção aos terminais
Análise sintática preditiva não-recursiva
▪ O símbolo da cadeia de entrada, em análise, é suficiente para determinar qual regra de produção deve ser escolhida
▪ São construídos utilizando gramáticas LL ( 1 )
▪ Cadeia de entrada é analisada da esquerda para a direita ( Left-toright) ▪ A derivação das produções é feita mais a esquerda ( Leftmost)
▪ A cada passo é observado um ( 1) símbolo a frente para determinar que ação deve ser tomada
Análise sintática preditiva não-recursiva
▪ Condições
▪ Eliminar a recursividade a esquerda ▪ Fatorar a gramática
Análise sintática preditiva não-recursiva
▪ Construção da tabela preditiva
▪ Dimensão1: não terminal X
▪ Dimensão2: símbolo de entrada (terminal) t
▪ A entrada (X, t) contém a regra da produção a aplicar → obtida a partir dos conjuntos first e follow
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
S→cAa first(S)={c} follow(S)={ $ } A→cB | B first(A)={b, c, ε} follow(A)={ a } B→ bcB | ε first(B)={b, ε} follow(B)={ a }
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
Topo da pilha S
S deriva em c?
Sim: S→ cAa
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
S→ cAa
substitui na pilha o S por
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
O topo da pilha é igual ao
valor do topo de entrada
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
A deriva em b?
Sim: A→B
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
Substitui o A na pilha por
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
B deriva em b?
Sim: B→bcB
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
B deriva em b?
Sim: B→bcB
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
bcBa$ bca$ casar(b)
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
O topo da pilha é igual ao
valor do topo de entrada
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
bcBa$ bca$ casar(b)
cBa$ ca$ casar(c)
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
O topo da pilha é igual ao
valor do topo de entrada
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
bcBa$ bca$ casar(b)
cBa$ ca$ casar(c)
Ba$ a$ B→ε
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
B deriva em a?
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
bcBa$ bca$ casar(b)
cBa$ ca$ casar(c)
Ba$ a$ B→ε
a$ a$ casar(a)
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
O topo da pilha é igual ao
valor do topo de entrada
Análise Sintática – Tabela Preditiva
Pilha Entrada Ação
S$ cbca$ S→cAa
cAa$ cbca$ casar(c)
Aa$ bca$ A→B
Ba$ bca$ B→bcB
bcBa$ bca$ casar(b)
cBa$ ca$ casar(c)
Ba$ a$ B→ε
a$ a$ casar(a)
$ $ aceita
Não Terminal Símbolo de Entrada
a b c
S erro erro S→ cAa
A A→B A→B A→cB
B B→ε B→bcB erro
Entrada: cbca
O topo da pilha é igual ao
valor do topo de entrada
Análise sintática – Analisador Bottom-up
▪ A análise top-down é realizada das folhas para a raiz
Análise sintática – Analisador Bottom-up
id * id F * id id T * id F id T * F F id id T T * F F id id E T T * F F id id E → E + T | T T → T * F | F F → (E) | id Entrada: id*idAnálise sintática – Analisador Bottom-up
▪ O processo de análise sintática ascendente pode ser encarado como um processo de “reduzir” uma cadeia w para o símbolo inicial da gramática
▪ Redução : operação de substituição do lado direito de uma produção pelo não-terminal correspondente do lado esquerdo
Análise sintática – Analisador Bottom-up
▪ Analisadores sintáticos Bottom-up
▪ Analisadores conhecidos como empilha-reduz (shift-reduce)
▪ Etapas do reconhecimento: determinar quando reduzir e determinar a produção a ser utilizada para que a análise prossiga
Análise sintática – Analisador Bottom-up
▪ Componentes do analisador bottom-up
▪ Pilha, onde os símbolos a serem reduzidos são empilhados ▪ Tabela sintática, que guia o processo de shift e reduce
▪ Processo de reconhecimento de uma sentença
1. Empilhar símbolos da cadeia de entrada
2. Quando um lado direito apropriado de uma produção aparece, ele é reduzido (substituído) pelo lado esquerdo da produção
3. Se a análise tiver sucesso, esse processo ocorre até que os símbolos da cadeia de entrada sejam todos consumidos e a pilha fique apenas com o símbolo inicial da gramática
Análise sintática – Analisador Bottom-up
Gramática: S→(L) | a L→ L+S | S
Entrada: a+a
Pilha Cadeia Regra
$ (a+a)$
$ (a+a)$ shift (
$( a+a)$ shift a
$(a +a)$ reduce S→a
$(S +a)$ reduce L→S
$(L +a)$ shift +
$(L+ a)$ shift a
$(L+a )$ reduce S→a
$(L+S )$ reduce L→L+S
Análise sintática – Analisador Bottom-up
▪ Operações durante a análise:
▪ Shift: coloca-se no topo da pilha o primeiro símbolo da cadeia de entrada ▪ Reduce: substitui-se o lado direito do handle pelo seu lado esquerdo
▪ Aceita: a cadeia de entrada é reconhecida ▪ Erro: a cadeia de entrada não é reconhecida
Referências
▪ SEBESTA, Robert W. Conceitos de linguagens de programação. 9ª ed. Porto Alegre: Bookman, 2011. 792 p. ISBN 978-85-7780-791-8.