Conteúdos da cadeira

Gramáticas livres de contexto

Derivações, árvores sintáticas, ambiguidade e forma normal de Chomsky.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

Uma gramática livre de contexto (CFG, de context-free grammar) gera palavras por substituição: cada regra troca um símbolo não terminal por uma sequência, independentemente do que está à volta (daí “livre de contexto”). São o formalismo por trás da sintaxe das linguagens de programação. Esta página mostra derivações, árvores, ambiguidade e a forma normal de Chomsky.

Definição e derivações

Uma CFG é um quádruplo G=(V,Σ,R,S)G = (V, \Sigma, R, S) onde VV são as variáveis (não terminais), Σ\Sigma os terminais (o alfabeto, disjunto de VV), RR as regras AαA \to \alpha (com AVA \in V e α\alpha uma sequência de variáveis e terminais) e SVS \in V o símbolo inicial.

Uma derivação aplica regras até só restarem terminais. Escreve-se αβ\alpha \Rightarrow \beta para um passo e \Rightarrow^* para zero ou mais passos. A linguagem gerada L(G)L(G) é o conjunto das cadeias de terminais ww com SwS \Rightarrow^* w.

Exemplo: GG com variável SS e regras S0S1εS \to 0S1 \mid \varepsilon (lê \mid como “ou”). Derivação de 00110011:

S0S100S1100ε11=0011.S \Rightarrow 0S1 \Rightarrow 00S11 \Rightarrow 00\varepsilon11 = 0011.

Cada aplicação de S0S1S \to 0S1 acrescenta um 00 à esquerda e um 11 à direita, por isso a gramática gera exatamente {0n1nn0}\{0^n 1^n \mid n \ge 0\}, a linguagem que os autómatos finitos não alcançam. Vês a diferença de poder: a variável SS no meio da forma sentencial funciona como memória ilimitada.

Árvores sintáticas e ambiguidade

Uma árvore sintática (parse tree) mostra a estrutura da derivação: a raiz é SS, cada nó interior é uma variável com os filhos dados por uma regra, e as folhas da esquerda para a direita formam a palavra.

Uma gramática é ambígua se alguma palavra tem duas árvores sintáticas distintas (ou, equivalentemente, duas derivações mais à esquerda distintas). Exemplo clássico, expressões aritméticas com EE+EE×E(E)aE \to E + E \mid E \times E \mid (E) \mid a, e a palavra a+a×aa + a \times a:

  • Árvore 1: a raiz soma (a+a)(a + a) com aa, ou seja (a+a)×a(a+a) \times a. Lê o ×\times no topo.
  • Árvore 2: a raiz multiplica aa por (a×a)(a \times a) no ramo direito, ou seja a+(a×a)a + (a \times a). Lê o ++ no topo.

As duas árvores dão valores diferentes (2a22a^2 contra a+a2a + a^2 com aa numérico), por isso um compilador não pode aceitar esta gramática: a mesma expressão teria dois significados. A cura é estratificar por precedência, com uma variável por nível:

EE+TT,TT×FF,F(E)a.E \to E + T \mid T, \quad T \to T \times F \mid F, \quad F \to (E) \mid a.

Agora a+a×aa + a \times a só deriva com o ++ no topo, porque o ×\times fica preso dentro de TT. Em exercícios, “remove a ambiguidade” significa quase sempre isto: introduz níveis para precedência e recursão à esquerda ou à direita para associatividade.

Forma normal de Chomsky

Uma CFG está na forma normal de Chomsky (CNF) se todas as regras têm uma destas formas: ABCA \to BC (duas variáveis), AaA \to a (um terminal) ou SεS \to \varepsilon (só no inicial). Toda a CFG pode ser convertida para CNF (adicionando variáveis para terminais em regras longas e partindo regras com mais de dois símbolos).

Para que serve? Em CNF, cada derivação de uma palavra ww de comprimento n1n \ge 1 usa exatamente 2n12n - 1 passos: n1n - 1 regras binárias para ramificar em nn variáveis e nn regras terminais. Este número fixo permite o algoritmo CYK, que testa pertença wL(G)w \in L(G) por programação dinâmica sobre os comprimentos crescentes. Não precisas de decorar o CYK célula a célula, mas percebe a ideia: a CNF torna o custo da análise sintática previsível, e é por isso que os parsers reais normalizam as gramáticas.

Exemplo de conversão: a regra S0S1S \to 0S1 viola a CNF (mistura terminais com variável e tem três símbolos). Introduz A0A \to 0, B1B \to 1 e parte em duas regras com variável fresca CC: SACS \to AC, CSBC \to SB, SABS \to AB, A0A \to 0, B1B \to 1, SεS \to \varepsilon.

Para levar para a próxima página

Gramáticas geram de cima para baixo (do inicial até à palavra). Os autómatos de pilha fazem o caminho inverso, reconhecendo de baixo para cima com a ajuda de uma pilha, e têm exatamente o mesmo poder.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.