A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

1 Esquemas de Tradução Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife.

Apresentações semelhantes


Apresentação em tema: "1 Esquemas de Tradução Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife."— Transcrição da apresentação:

1 1 Esquemas de Tradução Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife

2 Contatos n Prof. Guilherme Alexandre Monteiro Reinaldo n Apelido: Alexandre Cordel n /gtalk: n Site: n Celular: (81)

3 3 Traduções Dirigidas por Sintaxe n As produções de uma gramática são suas “regras sintáticas” e definem construções relevantes da linguagem n Traduções Dirigidas por Sintaxe associam regras semânticas a cada uma dessas regras sintáticas, com algum objetivo n As regras semânticas definem a saída correspondente a cada produção

4 4 Traduções Dirigidas por Sintaxe n Possíveis aplicações Criação da árvore sintática em memória Verificação de tipos Geração de código intermediário Etc. n Enfim, ela pode ser usada em todo o restante das etapas do front-end...

5 5 Traduções Dirigidas por Sintaxe n Existem dois tipos Definição Dirigida por Sintaxe – assumindo que cada nó da árvore possui atributos, define os valores que eles devem receber Esquemas de Tradução – associam código qualquer a cada produção, para ser executado durante a análise sintática (parsing) n A distinção é um pouco confusa...

6 6 Traduções Dirigidas por Sintaxe n “Definição Dirigida por Sintaxe” é uma descrição mais abstrata e formal de uma tradução Especifica a tradução n Já um “Esquema de Tradução” é a descrição concreta do código que vai ser executado para cada produção Implementa uma definição dirigida por sintaxe Usa trechos de código

7 Definição Dirigida por Sintaxe

8 8 n É a gramática livre de contexto da linguagem acrescida de Descrição dos atributos que cada símbolo (terminal ou não-terminal) possui Regras semânticas, associadas a cada produção, para definir os valores dos atributos n Chamaremos SDD (Syntax-Directed Definition)

9 9 Exemplo 1 n Considere a seguinte gramática: L → E ; E → T + E 1 E → T T → F * T 1 T → F F → digit

10 10 Exemplo 1 n Com base em uma gramática de expressões, o objetivo do exemplo é avaliar o valor numérico das expressões Para os não-terminais L, E, T e F, vamos considerar que possuem o atributo “val” O símbolo terminal digit terá um atributo “lexval”, com o seu valor numérico O símbolo terminal ; (ponto-e-vírgula) não tem importância nesta tradução

11 11 Exemplo 1 ProduçãoRegra Semântica L → E ; L.val = E.val E → T + E 1 E.val = T.val + E 1.val E → T E.val = T.val T → F * T 1 T.val = F.val * T 1.val T → F T.val = F.val F → digit F.val = digit.lexval

12 12 Exemplo 2 n Considere a seguinte gramática: E → E1 + T E → E1 - T E → T T → ( E ) T → num T → identifier

13 13 Exemplo 2 n Este exemplo usa uma gramática de expressões com soma e subtração apenas n O objetivo da SDD neste exemplo é construir a árvore sintática Cada não-terminal tem um atributo “node” que representa o nó da árvore que representa aquela ocorrência do não- terminal

14 14 Exemplo 2 ProduçãoRegra Semântica E → E 1 + T E.node = new Op(‘+’, E 1.node, T.node) E → E 1 - T E.node = new Op(‘-’, E 1.node, T.node) E → T E.node = T.node T → ( E ) T.node = E.node T → num T.node = new Leaf(num) T → identifier T.node = new Leaf(identifier)

15 15 Definição Dirigida por Sintaxe n Não se preocupa com detalhes, como a ordem de definição dos atributos n Sua principal aplicação é para especificar traduções mais simples Mais abstrata

16 Esquema de Tradução

17 17 Esquema de Tradução n É uma extensão do conceito de SDD Possui trechos de código como regras semânticas (que passam a ser chamadas ações semânticas) Controla a ordem de execução das ações semânticas n Implementação da tradução (ou da SDD) Mais concreta

18 18 Esquema de Tradução n Assim, um Esquema de Tradução é uma gramática livre acrescida de Descrição dos atributos que cada símbolo (terminal ou não-terminal) possui Ações semânticas, associadas a cada produção -Descritas na forma de trechos de código de uma linguagem de programação real -Posicionadas dentro da produção como se fossem um símbolo, para indicar o momento exato de executar a ação

19 19 Esquema de Tradução n Um Esquema de Tradução pode ser implementado junto com a análise sintática Ações semânticas disparadas sempre que o parser identifica uma produção n Ou percorrendo a árvore de derivação Primeiro, a árvore é construída por um Esquema de Tradução realizado durante a análise sintática Depois, a árvore é percorrida, disparando as ações semânticas no momento adequado

20 Usando Esquemas de Tradução

21 21 Introdução n Esquemas de Tradução são um tipo de Tradução Dirigida por Sintaxe Ações semânticas (trechos de código) associados às produções n Pode ser realizada de duas maneiras Junto com a análise sintática -Veremos no CUP e em parsers descendentes Percorrendo a árvore de derivação

22 22 Sumário n Esquemas de Tradução no CUP n Esquemas de Tradução em Parsers Descendentes n Construção da Árvore n Esquemas de Tradução na Árvore Sintática

23 23 Tradução na Análise Sintática n As ações semânticas são disparadas sempre que o parser identifica uma produção n Veremos como é feita em dois casos Esquema de tradução em parsers ascedentes (como o CUP) Esquema de tradução em parsers de descida recursiva

24 Esquemas de Tradução no CUP

25 25 Tradução Usando o CUP n Em geral, basta colocar um trechos de código em meio às produções delimitando-os por {: e :} comand ::= expr PT_VIRG {: System.out.println("Expressão!"); :} ; expr ::=...

26 26 Tradução Usando o CUP n Em alguns casos, é possível colocar a ação semântica em meio aos símbolos Ação executada antes de reconhecer o PT_VIRG n Em outros casos, o CUP pode indicar que é incapaz de identificar o momento em que a ação deve ser executada comand ::= expr {: System.out.println("Expressão!"); :} PT_VIRG ;

27 27 Tradução Usando o CUP n O CUP permite associar classes aos símbolos (terminais ou não-terminais) n Pensando no conceito de Definição Dirigida por Sintaxe, é como se Cada símbolo tivesse um único atributo O tipo desse atributo é a classe em questão n Funcionam como atributos sintetizados Não permite atributos herdados

28 28 Tradução Usando o CUP n Para associar classes aos símbolos terminais e não-terminais, basta indicá-las na seção de declaração de símbolos Ocorrências do símbolo terminal NUMERO serão representadas por objetos da classe String Ocorrências do não-terminal expr representadas pela classe Integer terminal String NUMERO; non terminal Integer expr;

29 29 Integração Lexer/CUP n Atenção: o tipo com que você declara um símbolo terminal deve ser o mesmo tipo retornado pelo lexer no segundo parâmetro do construtor de “Symbol” Ok, pois yytext() retorna uma String [0-9]+ { return new Symbol(sym.NUMERO, yytext()); }

30 30 Tradução Usando o CUP n Para ter acesso aos objetos que representam os atributos dos símbolos filhos, basta colocar dois pontos seguido de um nome qualquer A ação poderá usar esse nome como uma variável daquele tipo É como se val fosse o atributo de expr comand ::= expr:val PT_VIRG {: System.out.println("Valor: " + val); :} ;

31 31 Tradução Usando o CUP n Para atribuir valor ao objeto que representa o não-terminal pai (lado esquerdo), é preciso usar a variável RESULT O RESULT é como um atributo sintetizado (que depende apenas dos filhos) de expr expr ::= expr:e1 MAIS expr:e2 {: int soma = e1.intValue() + e2.intValue(); RESULT = new Integer(soma); :}

32 32 Tradução Usando o CUP n Para um exemplo completo de uso do CUP junto com ações semânticas será disponibilizado no oro-aro Implementa um Esquema de Tradução para interpretar expressões, retornando seus valores n Veremos agora como usar um Esquema de Tradução com um parser de descida recursiva

33 Esquemas de Tradução em Parsers Descendentes

34 34 Tradução em Parsers de Descida Recursiva n Relembrando a técnica O reconhecimento de cada não-terminal X está associado a um procedimento parseX() Dentro de parseX() é feita a discriminação entre as diferentes produções de X n Como fazer para associar ações semânticas a cada produção?

35 35 Tradução em Parsers de Descida Recursiva n O caso mais simples é se o não-terminal tem uma só produção e a ação deve ser executada no final da produção n Por exemplo, para essa tradução... comand ::= expr ";" { System.out.println("Expressão!"); }

36 36 Tradução em Parsers de Descida Recursiva n...o método parseComando() ficaria assim void parseComand() { parseExpr(); acceptToken(PT_VIRG); System.out.println("Expressão!"); }

37 37 Tradução em Parsers de Descida Recursiva n Se o não-terminal tem apenas uma produção e a ação tiver que ser executada no meio da produção... comand ::= expr {System.out.println("Expressão!"); } ";"

38 38 Tradução em Parsers de Descida Recursiva n...o resultado é este void parseComand() { parseExpr(); System.out.println("Expressão!"); PT_VIRG }

39 39 Tradução em Parsers de Descida Recursiva n Se tiver mais de uma produção... comand ::= "while" {System.out.println("While!");} "(" expr ")" comand | "do" comand {System.out.println(“Do-While!");} "while (" expr ");" |...

40 40 Tradução em Parsers de Descida Recursiva n...basta posicionar a ação semântica dentro do bloco que trata a produção desejada void parseLoopComand() { if (token.getType() == WHILE) { acceptToken(); System.out.println(“While!");... } else if (token.getType() == DO) { acceptToken(); parseComand(); System.out.println(“Do-While!");... }

41 41 Tradução em Parsers de Descida Recursiva n Em alguns casos, pode não ser possível posicionar a ação adequadamente, pois ainda não se sabe qual é a produção n Por exemplo: se tiver mais de uma produção e a ação de alguma delas acontece antes do primeiro símbolo n Mesma limitação do CUP

42 42 Tradução em Parsers de Descida Recursiva n Como trabalhar com atributos para os símbolos? Por exemplo, implementar a tradução abaixo n Primeiro veremos como associar um objeto a um símbolo (representando o atributo val) expr ::= termo + expr 1 {expr.val = termo.val + expr 1.val} | termo {expr.val = termo.val}

43 43 Tradução em Parsers de Descida Recursiva n Para associar uma classe ao não-terminal X, basta fazer o método parseX() retornar a classe n Para os terminais, é só retornar um atributo da classe desejada junto com o Token Integer parseExpr() {... }

44 44 Tradução em Parsers de Descida Recursiva n Para acessar os valores dos filhos basta receber (e guardar) os valores de retorno Atributos sintetizados Integer parseExpr() { Integer termoVal = parseTermo(); if (token.getType() == MAIS) { acceptToken(); Integer expr1Val = parseExpr(); return termoVal + expr1Val; }

45 45 Tradução em Parsers de Descida Recursiva n Em alguns casos, pode ser necessário passar valores por parâmetro Atributos herdados n Isso acontece, por exemplo, em uma gramática recursiva à esquerda, após transformá-la em uma sem a recursão

46 46 Tradução em Parsers de Descida Recursiva n Gramática original Seria fácil criar uma tradução para calcular o valor de expressões aqui... expr ::= expr “*” termo | termo termo ::= NUMBER

47 47 Tradução em Parsers de Descida Recursiva n Gramática sem recursão É preciso passar o valor do “termo” do lado esquerdo para o “restoExpr” fazer a multiplicação expr ::= termo restoExpr restoExpr ::= “*” termo restoExpr | ε termo ::= NUMBER

48 48 Tradução em Parsers de Descida Recursiva n A tradução ficaria assim Integer parseExpr() { Integer termoVal = parseTermo(); parseRestoExpr(termoVal); } Integer parseRestoExpr(Integer esq) { if (token.getType() == VEZES) { Integer dir = parseTermo(); Integer produto = esq * dir; return parseRestoExpr(produto); } else { return esq; }

49 Construção da Árvore

50 50 Construção da Árvore n Relembrando... Árvore de derivação – guarda todos os símbolos, inclusive sinais especiais, de cada produção -Feita com base na gramática concreta Árvore sintática – guarda só o que é importante de cada produção -Feita com base na gramática abstrata n É mais adequado construir a árvore sintática

51 51 Construção da Árvore n Não são árvores homogêneas, como as que são vistas nas disciplinas de estruturas de dados n Cada nó dessa árvore pode ser de um tipo diferente Classes diferentes para cada símbolo não- terminal Classes diferentes para cada produção

52 52 Construção da Árvore n Se o não-terminal tiver uma só produção Usar uma só classe e colocar como atributos dela os símbolos importantes que aparecem no lado direito Exemplo de produção no CUP -Criar classe Atribuicao com o atributo identificador (do tipo String) e o atributo expressao (do tipo que for associado a esse não-terminal) atrib ::= IDENTIFIER EQ expr

53 53 Construção da Árvore n Se o não-terminal tiver uma só produção (cont.) Por fim, colocar a ação no CUP para instanciar esse objeto atrib ::= IDENTIFIER:id EQ expr:e {: RESULT = new Atribuicao(id,e); :}

54 54 Construção da Árvore n Não-terminal com mais de uma produção Criar uma classe abstrata ou interface para representar o não-terminal Criar uma classe (herdada) para cada produção Exemplos de produções no CUP expr ::= expr MAIS expr | expr VEZES expr | NUM

55 55 Construção da Árvore n Não-terminal com mais de uma produção (cont.) Criar interface Expr Criar classes filhas Soma, Produto e ExprNum Expr SomaProdutoExprNum

56 56 Construção da Árvore n Não-terminal com mais de uma produção (cont.) Colocar as ações no CUP para instanciar as classes expr ::= expr:e1 MAIS expr:e2 {: RESULT = new Soma(e1,e2); :} | expr:e1 VEZES expr:e2 {: RESULT = new Produto(e1,e2); :} | NUM:n {: RESULT = new ExprNum(n); :}

57 57 Construção da Árvore n Em alguns casos, uma mesma classe pode ser usada para mais de uma produção Uma só classe para "if" sem "else" e para "if" com "else" Uma só classe para todas as expressões binárias Uma só classe para todas as expressões unárias “Usar o bom senso...”

58 Esquemas de Tradução na Árvore de Derivação

59 59 Tradução na Análise Sintática n Já vimos como usar Esquemas de Tradução junto com a análise sintática n Esquemas desse tipo têm algumas limitações Parsers ascendentes (como o CUP) permitem apenas atributos sintetizados Parser descendentes permitem atributos sintetizados e herdados, mas com algumas restrições

60 60 Tradução na Árvore n Outra maneira de se usar Esquemas de Tradução é usando a árvore n Essa estratégia é mais geral do que traduções que acontecem durante a análise sintática Permite implementar qualquer tradução, mesmo com atributos herdados

61 61 Esquema de Tradução na Árvore de Derivação n A primeira etapa é construir a árvore sintática Acabamos de ver como fazer isso durante a análise sintática... n Em seguida, basta percorrer a árvore, executando as ações semânticas no momento desejado

62 62 Esquema de Tradução na Árvore de Derivação n Uma maneira simples de implementar uma tradução é criar métodos em cada classe da árvore que representar uma produção (ou um não-terminal) Tudo inicia chamando o método do nó raiz No momento adequado, cada nó chama os métodos equivalentes dos filhos

63 63 Exemplo 1: Tradução para a Forma Pré-fixada n Este é o Esquema de Tradução desejado Visa passar a expressão para a forma prefixada n Vamos supor que a árvore tenha sido criada com as classes Soma, Produto e ExprNum, todas filhas de Expr expr → { print("+"); } expr + expr | { print("*"); } expr * expr | NUM { print(NUM.lexval); }

64 64 Exemplo 1: Tradução para a Forma Pré-fixada n A tradução é feita assim class ExprNum extends Expr { int lexval; public void toPrefixed() { print(lexval); }

65 65 Exemplo 1: Tradução para a Forma Pré-fixada n E assim Fazer análogo na classe Produto class Soma extends Expr { private Expr expr1, expr2; public void toPrefixed() { print("+"); expr1.toPrefixed(); expr2.toPrefixed(); }

66 66 Exemplo 2: Verificação Semântica n Criar um método verificaSemantica() em cada classe da árvore n O início seria no método verificarSemantica() da classe Program n Esse método iria chamar o método verificarSemantica() da classe ListaDecl e, depois, o da classe Bloco n O método da classe ListaDecl iria chamar o método verificarSemantica() de cada objeto Declaracao n E assim sucessivamente...

67 67 Esquema de Tradução na Árvore de Derivação n Outra maneira de percorrer a árvore é usando o design pattern "Visitor" n A árvore implementa apenas as chamadas a métodos de um Visitor genérico n Classes Visitor de próposito específico podem ser criadas para implementar uma tradução n Ver

68 68 Visitor n Visitor é um padrão de projeto catalogado pelos “quatro” mosqueteiros da engenharia de software, Gamma, Helm, Johnson e Vlissides (Gang of Four - GoF), como um padrão de projeto comportamental n Seu objetivo principal é permitir que sejam adicionadas novas funcionalidades a classes existentes, de maneira plugável, sem que haja a necessidade de se alterar a hierarquia dessas classes

69 69 Bibliografia n AHO, A., LAM, M. S., SETHI, R., ULLMAN, J. D., Compiladores: princípios, técnicas e ferramentas. Ed. Addison Wesley. 2a Edição, 2008 (Capítulo 4)


Carregar ppt "1 Esquemas de Tradução Prof. Alexandre Monteiro Baseado em material cedido pelo Prof. Euclides Arcoverde Recife."

Apresentações semelhantes


Anúncios Google