sintaxe de uma linguagem especificada através de uma gramática livre de contexto, bnf (backus-naur...
Post on 07-Apr-2016
231 Views
Preview:
TRANSCRIPT
Sintaxe de uma Linguagem
• Especificada através de uma gramática livre de contexto, BNF (Backus-Naur Form).
Vantagens de usar uma gramática
• Uma gramática dá uma especificação precisa e fácil de entender da sintaxe de uma linguagem de programação
• Para algumas classes de gramáticas, é possível gerar automaticamente um parser eficiente. Além disso as ferramentas usadas indicam ambiguidades e outras construções difíceis de serem reconhecidas e que passaram desapercebidas
• Tem relação direta com a estrutura da linguagem usada para tradução/compilação.
• Fácil de ser estendida/atualizada.
Analisador Sintático - Parser
Analisador léxico parser
pede próximotoken
Programafonte
token
tabela de símbolos
Parsetree
Resto dofront-end
Representaçãointermediária
Tipos de parsers para gramáticas
• Métodos de parsing universais: funcionam para qualquer gramática, mas são muito ineficientes (inviáveis para uso prático).
• Top down: constroem as parse trees a partir da raiz em direção às folhas.
• Bottom-up: constroem as parse trees a partir das folhas.
Parsers top-down ou bottom-up
• Em parsers top-down ou bottom-up a leitura do arquivo é sempre feita da esquerda para a direita, um símbolo de cada vez.
• Só funcionam para um subconjunto de gramáticas, que na prática são suficientes para a grande maioria das linguagens de programação.
Tratamento de Erros de Sintaxe
• Relatar presença de erros claramente e com precisão
• Recuperar-se do erro rapidamente, para possibilitar a detecção de erros subsequentes
• Não deve gerar overhead significativo para programas corretos.
Gramáticas Livres de Contexto
• stmt if expr then stmt else stmt • Um conjunto de símbolos terminais (tokens). • Um conjunto de símbolos não-terminais
(“variáveis”).• Um conjunto de produções, cada produção consiste
de um não-terminal. Uma seta, e uma seqüencia de tokens e/ou não terminais
• Um não terminal designado como símbolo inicial
Exemplo 1
• expr expr op exprexpr ( expr )expr - exprexpr idop +op -op *op /op ^
Exemplo 1 (notação abreviada)
• expr expr op expr | ( expr ) | - expr | idop + | - | * | / | ^
Exemplo 2
block begin op_stmts endop_stmts stmt_list | stmt_list stmt_list ; stmt | stmt
Parse Trees
• Mostra graficamente como o símbolo inicial de uma gramática deriva uma string da linguagem.
• Para uma produção A XYZ
Z
A
X Y
Ambiguidade
• Parse-tree gera uma string, mas uma string pode possuir várias parse-trees, se a gramática for ambígua.
• Solução: usar sempre gramáticas não-ambíguas, ou gramáticas ambíguas com informações adicionais sobre como resolver ambiguidades.
Ambiguidade - Exemplo
• E E + E | E * E | - E | ( E ) | id
Exemplo: Duas parse trees
• id + id * id
E
E
E
E
E +
*
id id
id E E
E
E
E +
*id
id id
Expressões Regulares x Gramáticas Livres de Contexto
• Tudo que pode ser descrito por uma expressão regular pode ser descrito com gramáticas livres de contexto, mas:– As regras léxicas são especificadas mais simplesmente
com expressões regulares– Expressões Regulares geralmente são mais concisas e
simples de entender– Podem ser gerados analisadores léxicos mais eficientes
a partir de expressões regulares– Estrutura/modulariza o front-end do compilador
Exemplo
• (a | b)*abb• A0 aA0 | bA0 | aA1
A1 bA2
A2 bA3
A3
Expressões Regulares x Gramáticas Livres de Contexto
• Expressões regulares são convenientes para especificar a estrutura de construções léxicas, como identificadores, constantes, palavras chave etc.
• Em geral usa-se gramáticas para especificar estruturas aninhadas, como parenteses, begin-end, if-then-else etc.
Eliminando Ambiguidades
• stmt if expr then stmt | if expr then stmt else stmt | other
• if E1 then S1 else if E2 then S2 else S3
• if E1 then if E2 then S1 else S2
• Nas linguagens de programação normalmente a regra é que o else casa com o then mais próximo.
Solução
stmt matched_stmt | unmatched_stmt
matched_stmt if expr then matched_stmt else matched_stmt | other
unmatched_stmt if expr then stmt | if expr then matched_stmt else unmatched_stmt
Recursão à Esquerda
• Uma gramática é recursiva à esquerda se existe um não terminal A tal que existe uma derivação de A que gera A, para alguma string .
• Existem técnicas/algorítimos para eliminar a recursão à esquerda.
Recursão à Esquerda - exemplos
• A A | pode ser substituido porA A’A’ A’ |
• E E + T | Tpode ser substituido porE TE’E’ +TE’ |
Fatoração à Esquerda
• Técnica de transformação de gramática usada para produzir uma gramática adequada para predictive parsing.
• Combina os casos em que há mais de uma alternativa possível a partir do reconhecimento de um token.
• Existem técnicas/algorítimos para fazer a fatoração à esquerda.
Fatoração à Esquerda - exemplo
• stmt if expr then stmt | if expr then stmt else stmt
• stmt if expr then stmt stmt’
stmt’ else stmt |
Construções que não podem ser especificadas por gramáticas
livres de contexto• L = {wcw | w está em (a|b)*}
ex: declaração de variáveis antes de seu uso• L = {anbmcndm | n >= 1 e m >= 1}
ex: contagem do número de argumentos de funções/procedimentos.
Parsers top-down
• Recursive-descent parsing: técnica de parsing top-down que suporta backtracking
• predictive parsing: recursive-descent parsing sem backtracking.
• Relativamente fáceis de escrever à mão• Só reconhecem alguns tipos de gramáticas:
não suportam recursão à esquerda, precisa fazer fatoração à esquerda (predictive).
Parsers top-down
• Exemplo: reconhecerstmt if expr then stmt else stmt | while expr do stmt | begin stmt_list end
• Pode fazer uso na implementação de diagramas de transição, ou ser implementado recursivamente.
Parsers bottom-up
• Também chamado de shift-reduce parsing – reduz uma string w ao símbolo inicial da gramática. A redução ocorre através da substituição do lado direito de uma produção pelo não-terminal do seu lado esquerdo.
• Mais complexo, constrói a árvore a partir das folhas.
• Gerado por ferramentas automáticas.
Parser bottom-up - exemplo
• S aABeA Abc | b B d
• abbcdeaAbcdeaAdeaABeS
top related