IF688 – Análise Sintática
Resumo desta aula Revisão de conceitos gerais de parsing Método de parsing top down e bottom up
Analisador Sintático Programa fonte lexerparser getNextToken() token tabela de símbolos type checker Árvore sintática ou outra representação intermediária de código
Sintaxe de uma linguagem Define as strings estruturalmente válidas de uma linguagem “Fez parsing corretamente” = A sintaxe está correta Note: O programa pode ainda... não passar na checagem de tipos ou (de forma mais geral) conter erros
Especificação da sintaxe Dever ser precisa e fácil de entender Precisa: não ambígua Fácil de entender: deixa evidente a sintaxe da linguagem Historicamente, gramáticas livre de contexto (BNFs) é um formalismo adequado Fácil de especificar/manter/entender S aABe A Abc | b B d Exemplo:
Exercício. Qual das strings a seguir faz parte da liguagem definida pela BNF abaixo? abcba acca aba abcbcba S → aXa X → € | bY Y → € | cXc
Derivação e parsing S aABe A Abc | b B d Gramática G S aABe aAbcBe aAbcbcBe abbcbcBe abbcbcde Derivação de string em G S ABae Abc Abc d b Árvore sintática para abbcbcde
Diferenças: Derivação e parsing Derivação: Dada uma gramática G, produz uma string s que faz parte de L(G) Parsing: Dada uma string s em L(G), produz uma árvore sintática que demonstra como se obter derivação de s
Exercício. Qual das seguintes derivações é válida de acordo com a gramática ao lado? S aXa aa S aXa abYa acXca acca S → aXa X → € | bY Y → € | cXc | d S aXa abYa abcXcda abccda S aXa abYa abcXca abcbYcaabc bdca
Top-down e Bottom-up Considerando a ordem de criação da árvore sintática, top-down constrói o nó raiz primeiro e depois os internos em direção aos nós folha. bottom-up faz o contrário.
Top-down parser Procura sequência de derivações mais a esquerda para se obter uma string de entrada O parse da string abbcbcde é caracterizado pela sequência de derivações abaixo. S aABe A Abc | b B d S aABe aAbcBe aAbcbcBe abbcbcBe abbcbcde
Top-down parser Procura sequência de derivações mais a esquerda para se obter uma string de entrada O parse da string abbcbcde é caracterizado pela sequência de derivações abaixo. S aABe A Abc | b B d S aABe aAbcBe aAbcbcBe abbcbcBe abbcbcde Note a preferência da produção mais à esquerda
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eS
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eaABe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eABe escolha!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd ebBebBe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eBeBe erro. Backtrack!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eABe Restaura estado anterior a última escolha Faz outra escolha!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eAbcBe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eAbcBe escolha novamente! Símbolo A novamente na posição mais à esquerda
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd ebbcBe Outra escolha!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd ebcBe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eBeBe erro. Backtrack!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eAbcBe Restaura estado anterior a última escolha
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eAbcbcBe Faz outra escolha!
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd ebbcbcBe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd eBeBe
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd ede
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd e
O método Inicie com símbolo raiz Consuma tokens da esquerda para direita Decida que produção aplicar S aABe A Abc | b B d abbcbcd e derivação correspondente! S aABe aAbcBe aAbcbcBe abbcbcBe abbcbcde
Top-down parsers operam desta forma!
Exercício. Construa a árvore sintática associada a derivação (mais à esquerda) abaixo S aABe A Abc | b B d abbcbcd e S aABe aAbcBe aAbcbcBe abbcbcBe abbcbcde GramáticaString de entrada Derivação mais à esquerda
Classificação de parsers LL(k) Lê entrada da esquerda (L) para direita Procura derivação mais à esquerda Número de tokens de lookahead lidos porém não consumidos
Ambiguidade e Recursão à esquerda Ambiguidade: Existe mais de uma forma de se derivar a string em uma gramática ambígua Mais de uma parse tree Recursão à esquerda: dificuldade em saber quando parar de aplicar uma produção S aABe A Abc | b B d aABe aAbcBe aAbcbcBe aAbcbcbcBe aAbcbcbcbcBe … complicador
Ex: Quais das seguintes gramáticas são ambíguas? S → SS | a | b E → E + E | id S → Sa | Sb | a E → E’ | E’ + E E’ → -E’ | id | (E)
Predictive parsing É um parser top-down É um parser que não requer backtracking Simples de construir manualmente Mas, requer modificação na gramática para tratar recursão à esquerda e ambigüidade Eliminação de recursão à esquerda (fatoração): S aABe A Abc | b B d S aABe A bK K bcK | ∈ B d
Ex: Escolha a gramática que elimina recursão à esquerda corretamente da seguinte gramática: E → id + E | E + T | T T → id | (E) E → E’ + T | T E’ → id | (E) T → id | (E) E → E + T | T T → id | (E) E → TE’ E’ → +TE’ | € T → id | (E) E → E + id | E + (E) | id | (E)
Pode-se construir parser LL(k=1) para uma gramática não ambígua. Gramáticas ambíguas pedem parsers com valor de k > 1. Existem algoritmos para gerar parsers top-down de gramáticas ambíguas (e também com recursão à esquerda). Resultados gerais
Bottom-up parser Procura sequência de derivações mais a direita para se obter uma string de entrada O parse da string abbcbcde é caracterizado pela sequência de derivações abaixo. S aABe A Abc | b B d Animação S aABe aAde aAbcde aAbcbcde abbcbcde
O método Encontre padrões que casam com lado direito da produção e substitua pelo lado esquerdo S aABe A Abc | b B d abbcbcd e
O método Encontre padrões que casam com lado direito da produção e substitua pelo lado esquerdo S aABe A Abc | b B d abbcbcd e A
O método Encontre padrões que casam com lado direito da produção e substitua pelo lado esquerdo S aABe A Abc | b B d abbcbcd e A
O método Encontre padrões que casam com lado direito da produção e substitua pelo lado esquerdo S aABe A Abc | b B d abbcbcd e AB
O método Encontre padrões que casam com lado direito da produção e substitua pelo lado esquerdo S aABe A Abc | b B d abbcbcd e S S aABe aAde aAbcde aAbcbcde abbcbcde derivação correspondente!
Shift-reduce parsers Usa uma pilha e uma tabela Pilha: armazena tokens para salvar contexto Tabela: determina as opções atuais de ação Possíveis ações Shift (push): coloca tokens na pilha Reduce: determina uma produção Accept: finaliza. reconhece string. Error: Nenhuma ação é possível
LR(k) Lê entrada da esquerda (L) para direita Procura a derivação mais à direita Número de tokens de lookahead lidos porém não consumidos Bottom-up parsers operam desta forma! Terminologia: classificação de parsers
Comparação Top-down e Bottom-up Em geral, bottom-up é mais poderoso Coloca menos restrições na gramática Bem mais trabalhoso de se escrever e manter manualmente. Porém... Yacc e Bison geram parser de gramática LALR(1), um subconjunto LR(1)
Resumo desta aula Revisão de conceitos gerais de parsing Método de parsing top down e bottom up