Compiladores Prof. Bruno Moreno Aula 9 – 06/05/2011 Como transformar uma expressão regular em um AFN? Exp. Regular para AFN Para E Para a Para s | t Exp. Regular para AFN Para st Para s* Exemplo R = (a|b)*abb st s* s|t SAÍDA DO ANALISADOR LÉXICO Saída do Analisador Léxico Fornece dois elementos para cada símbolo Símbolo propriamente dito (posição na memória) Ou apontando para ele Um número que identifica a classe do símbolo Saída do Analisador Léxico Tabela de Símbolos (exemplo) begin SÍMBOLO ID_CLASSE Indefinido 0 Identificador 1 Inteiro 2 Begin ab + (x2*y)/35 /* expressão aritmética */ end CHAMADA SAÍDA SIGNIFICADO 3 1ª 3, “begin” begin Abs 4 2ª 1, “ab” ab End 5 3ª 8, “+” + ( 6 4ª 6, “(“ ( ) 7 5ª 1, “x2” x2 + 8 6ª 10, “*” * - 9 7ª 1, “y” y * 10 8ª 7, “)” ) / 11 9ª 11, “/” / ** 12 10 2, “35” 35 := 13 11ª 5, “end” end O ANALISADOR SINTÁTICO O Analisador Sintático O analisador sintático obtém uma cadeia de tokens proveniente do analisador léxico O Analisador Sintático Verifica se esta cadeia pode ser gerada pela gramática da linguagem-fonte O Analisador Sintático Relata erros de sintaxe Recupera-se do erro para que a compilação continue Função do analisador sintático Verificar se as construções usadas no programa estão gramaticalmente corretas Em uma linguagem natural é semelhante a avaliar a construção frasal que obriga ter, por exemplo, sujeito, verbo e predicado Analisador Sintático Já estudamos previamente os principal artefatos de investigação utilizados pelo Analisador Sintático Árvores de decisão e Gramáticas Analisador Sintático Existem duas formas de realizar a análise sintática Análise descendente (top-down) Análise ascendente (bottom-up) Constroem as árvores de cima para baixo (raiz para folhas) Constroem as árvores de baixo para cima (folhas para raiz) Em ambos os casos, a entrada é varrida da esquerda para a direita, um símbolo de cada vez Analisador Sintático Normalmente, as estruturas sintáticas válidas são especificadas através de uma gramática livre de contexto Descreve as regras de formação de sentenças da linguagem A gramática é formada por regras de produções Cada produção é uma regra de formação, mostrando como um símbolo pode gerar (ou produzir) outros Gramática Livre de Contexto Produções na forma Por que “Livre de Contexto”? A→a Não terminal A pode ser substituído por a em qualquer contexto, sem depender de qualquer análise dos símbolos que sucedem ou antecedem A Diferente das gramáticas sensíveis ao contexto a → b, com a ∈ (N U T)+ e b ∈ (N U T)* Gramática Livre de Contexto Qualquer gramática G = {N, T, P, S} N – Conjunto de símbolos não terminais T – Conjunto de símbolos terminais P – Conjunto de regras S – Símbolo inicial Gramática Livre de Contexto Exemplo G = ({E}, {+, -, *, /, ), (, x}, P, E} P = E → E + E | E – E | E * E | E / E | (E) Sentença: x+x*x E E + E x E * x E x |x Gramática Livre de Contexto Exemplo G = ({<num>, <digit>}, {0, 1, ..., 9}, P, <num>) P = <num> → <num><digit> | <digit> <digit> → 0, 1, ..., 9 Sentença: 45 <num> <num> <digit> <digit> 5 4 Derivação mais à esquerda É a seqüência de formas sentenciais que se obtém derivando sempre o símbolo nãoterminal mais à esquerda Exemplo G = ({E}, {+, -, *, /, ), (, x}, P, E} P = E → E + E | E – E | E * E | E / E | (E) Sentença: x+x*x E→E+E→ x+E→x+E*E→x+x*E →x+x*x |x Derivação mais à direita É a sequencia de formas sentenciais que se obtém derivando sempre o símbolo nãoterminal mais à direita Exemplo G = ({E}, {+, -, *, /, ), (, x}, P, E} P = E → E + E | E – E | E * E | E / E | (E) |x Sentença: x+x*x E→E+E→ E+E*E→E+E*x →E+x*x→x+x*x Gramática Ambígua É a gramática que permite construir mais de uma árvore de derivação para uma mesma sentença Exemplo G = ({E}, {+, -, *, /, ), (, x}, P, E} P = E → E + E | E – E | E * E | E / E | (E) E E E x + * E x |x E E E + E x x E * x E x Gramáticas Ambíguas Qual o problema de uma gramática ambígua? Reconhecedores de linguagens exigem derivações unívocas para obter um bom desempenho E também para concluir a derivação sintática Gramáticas Ambíguas Qual o problema lógico, de interpretação, nas duas árvores de derivação a seguir? E E E x + * E E E E + E x x E * x + é executado em primeiro lugar x E x * é executado em primeiro lugar Gramáticas Ambíguas Resolução de ambiguidade Não existe um procedimento geral para retirar ambigüidade de uma linguagem Além disso, existem gramáticas em que é impossível eliminar produções ambíguas Linguagens Inerentemente Ambíguas LINGUAGENS INERENTEMENTE AMBÍGUAS Linguagens Inerentemente Ambíguas São aquelas que qualquer GLC que a descreva é ambígua Exemplo { w | w = anbncmdm | anbmcmdn, n ≥ 1, m ≤ 1} Para n =1, m = 2 w = abc2d2 ou ab2c2d RECURSIVIDADE Gramática recursiva à esquerda Permite a derivação A → Aa para algum A ∈ N Um não terminal (A) deriva ele mesmo, de forma direta ou indireta, como símbolo mais à esquerda Reconhecedores top-down exigem que a gramática não seja recursiva à esquerda Quando a recursão é direta, a eliminação é simples Gramática recursiva à esquerda Quando a recursão é indireta, a eliminação requer que a gramática seja inicialmente simplificada Gramática simplificada É uma GLC que não apresenta símbolos inúteis TRANSFORMAÇÃO DE GLCS Transformação de GLCs O processo de transformação de uma GLC se caracteriza por transformar uma gramática sem que ela perca a qualidade de gerar a mesma linguagem Gramáticas que geram mesma linguagem utilizando regras de produção diferentes são chamadas de gramáticas equivalentes ELIMINAÇÃO DE RECURSIVIDADE À ESQUERDA Eliminação de Recursividade à Esquerda Para recursividade direta Pode ser eliminada manualmente Para recursividade indireta Primeiramente, a gramática deve ser simplificada Recursividade à Esquerda Eliminação da recursividade direta Substituir cada regra da forma A → Aa1 | Aa2 | ... | Aan| b1 | b2 | ... | bm onde nenhum bi começa por A, por A → b1X | b2X | ... | bmX X → a1X | a2X | ... | anX | E Se produções vazias não são permitidas, a substituição deve ser: A → b1 | b2 | ... | bm | b1X | b2X | ... | bmX X → a1 | a2 | ... | an | a1X | a2X | ... | anX Recursividade à Esquerda (Exemplo 1) Linguagem: b(a)* Com recursividade A → Aa | b b, ba, baa, baaa, ... 1º Passo: Identificar recursão Recursividade à Esquerda (Exemplo 1) Linguagem: b(a)* Com recursividade A → Aa | b A → bA’ b, ba, baa, baaa, ... 1º Passo: Identificar recursão 2º Passo: Para cada produção com recursão 2.1: O não terminal que gera a regra de produção deve receber agora a parte não recursiva concatenada com um novo não terminal A → bA’ Recursividade à Esquerda (Exemplo 1) Linguagem: b(a)* Com recursividade A → Aa | b A → bA’ A’ → aA’ | E b, ba, baa, baaa, ... 1º Passo: Identificar recursão 2º Passo: Para cada produção com recursão 2.1: O não terminal que gera a regra de produção deve receber agora a parte não recursiva concatenada com um novo não terminal A → bA’ 2.2: O novo não terminal deve receber a direita da produção recursiva concatenada com o próprio novo não terminal e também a regra gerando vazio A’ → aA’ | E Recursividade à Esquerda (Exemplo 2) E→E+T|T T→T*F|F F → (E) | id 1º Passo: Identificar recursão Recursividade à Esquerda (Exemplo 2) E→E+T|T T→T*F|F F → (E) | id E → TE’ E’ → +TE’ | E 1º Passo: Identificar recursão 2º Passo: Para cada produção com recursão 2.1: O não terminal que gera a regra de produção deve receber agora a parte não recursiva concatenada com um novo não terminal E → TE’ 2.2: O novo não terminal deve receber a direita da produção recursiva concatenada com o próprio novo não terminal e também a regra gerando vazio E’ → +TE’ | E Recursividade à Esquerda (Exemplo 2) E→E+T|T T→T*F|F F → (E) | id E → TE’ E’ → +TE’ | E T → FT’ T’ → *FT’ | E F → (E) | id 1º Passo: Identificar recursão 2º Passo: Para cada produção com recursão 2.1: O não terminal que gera a regra de produção deve receber agora a parte não recursiva concatenada com um novo não terminal T → FT’ 2.2: O novo não terminal deve receber a direita da produção recursiva concatenada com o próprio novo não terminal e também a regra gerando vazio T’ → *FT’ | E