analise-sintatica
aula referente ao cap 4.1 e 4.4 do livro
Análise Sintática
![[Pasted image 20250916171035.png]]
Entrada: Cadeia de tokens representando o programa fonte e verifica se a cadeia em si pertence a linguagem gerada pela gramatica.
Ele deve ser projetado para emitir mensagens de erros de uma forma inteligível e se recuperar deles, em certas ocasiões.
Aqui, devemos estruturar a gramatica de fato, partindo, naturalmente, de uma keyword definida, i.e, while ou int, assim, os próximos lexemas a serem aceitos devem se basear nessa indicação.
Utilizaremos um PDA (push-down automata) para aceitarmos a gramatica, devido a sua “memoria” (pilha). Assim, podemos aceitar uma sequencia de tokens como int a = 5; ou não, ja que ele olha todos os lexemas.
O analisador sintático interage com a tabela de símbolos, adicionando, por exemplo, tipo, argumentos, etc.
Saída: Gera uma arvore de derivação (arvore sintática) como saída.
Tratamento de erro
Precisa-se tratar erros corretamente e existem diversas maneira de o fazer. Devemos atrasar a parada do programa, apenas marcando erros e os informando ao final da analise (se não for critico); O compilador pode, por exemplo, parar essa emissão de mensagens em caso de um threshold de erros seja alcançado (e.g 50).
Estratégias podem ser:
Recuperação no modo panico
// livro
Recuperação em nível de frase
// livro
Produções de Erro
// livro
Correção Global
// livro
Tipos de Analise Sintática
- Descendente
- Ascendente
Descendente (top down)
“Na analise sintatica Descendente, inicia-se o processo pelo simbolo S e chega-se à cadeia.”
constroi a arvore de derivação para a cadeia de cima para baixo, da raiz para as folhas, criando os nos da arvore em pré-ordem (DFS). Pode ser recursiva ou nao recursiva.
Ascendente (bottom up)
“Na análise ascendente, tenta-se construir a árvore de derivação para uma sentença $w$ a partir dos símbolos de $w$ (folhas), fazendo reduções (substituir o lado direto de uma regra pelo seu lado esquerdo) até obter-se o símbolo inicial S”.
constroi a arvore de redução ao invés de derivação para a cadeia de baixo para cima, das folhas para a raiz.
Diagramas de Transicao para Analisadores Sintaticos Preditivos
[!note] Caderneta Visto no caderno
Construcao do ASDR (analisador sintatico descendente recursivo)
- construir as rotinas que implementam cada um dos diagramas de transição da gramatica referente.
Extra
como implementar a tabela de simbolos?
- pode ser uma AVL, com busca consideravelmente rapida (em $O(log(n))$);
- qualquer arvore balanceada;
- tabela hash (prioridade - se bem espalhada) $(O(log(1)))$.
Continuação análise sintática descendente
- sem retrocesso
- chamado analisador sintático preditivo.
- adequado para gramaticas LL(1) -> left-to right -> left (derivações) -> (k-lookahead = 1)
2 tipos de AS (analisadores sintáticos) preditivos:
- recursivo: associa uma função para cada simbolo não terminal da gramatica.
- não recursivo: usa uma tabela que indica quais regras de produção devem ser usadas.
Construir um analisador sintático descendente recursivo para G
# nao funciona
token: str = None
def ASDR():
try:
token = solicita_token(analex)
e(token)
except Excepetion as e:
print(e)
def e(token):
t(token)
e_linha(token)
def t(token):
f(token)
t_linha(token)
def e_linha(token):
if token.value == "+" or token.value == "-":
token = solicita_token(analex)
t(token)
e_linha(token)
def f(token):
if token.value == "(":
token.value = solicita_token(analex)
e()
if token.value == ")":
return
throw new Error("Nao fechou parenteses")
if token.type == num:
return
throw new Error("Nem parenteses nem numero")
def t_linha(token):
if token.value == "*" or token.value == "/":
f()
t_linha()Quando usar um ASDR
-> poucas regras gramaticais -> linguagens de programação possui recursividade -> ATENÇÃO: a GLC não pode ser recursiva à esquerda
Exercício: construir os diagramas (caderno)
Eliminação de recursividade à esquerda
$A -> A\alpha |\beta$ pode ser substituído por: $A -> \beta A’$ $A’ -> \alpha A’ |\epsilon$
outro exemplo: E -> E + T | T
vira: E -> TE' E’ -> +TE’ | $\epsilon$
Analise Sintatica Produtiva
![[Pasted image 20250829102631.png]]
First and Follow
Necessários para construir um analisador sintático preditivo, podendo prever a regra de produção correta a ser escolhida.
First
- Se X for terminal, First (X) = {X}
- Se X -> $\epsilon$ for uma produção, adicione $\epsilon$ a First(X)
- Se X for não-terminal e $X \rightarrow Y_1, Y_2,\ \dots,\ Y_n$ uma produção, colocar a em primeiro (X) se para algum $i$, a estiver em First($Y_i$), e $\epsilon$ estiver em todos: First($Y_1$) $\dots$ First($Y_{i-1}$), isto é, se $$Y_1\dots Y_{i-1}\xRightarrow{y} \ \epsilon$$ Se $\epsilon$ estiver em First($Y_j$), $j = 1,\ 2 \ \dots \ n$, então adicione $\epsilon$ a First(X).
Follow(seguinte)
- colocar $ em Seguinte(S), S símbolo de partida.
- Se existir uma produção A->$\alpha B \beta$, então tudo em First($\beta$) está em Seguinte($\beta$) exceto $\epsilon$
- Se existir uma produção A->$\alpha B\beta$ onde First($\beta$) contém $\epsilon$, então tudo em Seguinte de A está em Seguinte($B$).

