Tradução Dirigida por Sintaxe • Pode ser descrita de duas formas: – Definições dirigidas por sintaxe: mais abstratas – Esquemas de tradução: especificam ordem de avaliação E E1 + T E.code E1.code || T.code || ‘+’ E E1 + T { print ‘+’; } Tradução Dirigida por Sintaxe • Conceitualmente, realiza o parsing, constrói parse tree, e atravessa a árvore sob demanda para avaliar as regras semânticas nos nós da parse tree. • Avaliação das regras semânticas pode ser usada para gerar código, guardar informações na tabela de símbolos, emitir mensagens de erro etc. Tradução dirigida por sintaxe Programa fonte parse tree grafo de dependência ordem de avaliação para regras semânticas Definições dirigidas por sintaxe • Generalização de gramática livre de contexto em que cada símbolo da gramática é associado a um conjunto de atributos. • Dois tipos de atributos: sintetizados e herdados Tipos de atributos • Atributos sintetizados: computados a partir dos atributos dos nós-filhos (abaixo do próprio nó). • Atributos herdados: computados a partir de nós-pais ou nós-irmãos (acima ou ao lado do próprio nó). Parse tree anotada • Mostra os valores dos atributos em cada nó. • O processo de avaliação dos atributos é chamado “anotar” ou “decorar” a parse tree. Definição dirigida por sintaxe exemplo Produção L g E ‘\n’ E g E1 + T EgT T g T1 * F TgF Fg(E) F g digit Regra semântica print (E.val) E.val = E1.val + T.val E.val = T.val T.val = T1.val * F.val T.val = F.val F.val = E.val F.val = digit.lexval Exemplo em yacc … line : ; expr : | ; term : | ; factor : | ; … expr '\n'{ printf("%d\n", $1); } expr '+' term term { $$ = $1 + $3; } term '*' factor { $$ = $1 * $3; } factor '(' expr ')' DIGIT { $$ = $2; } Em definições dirigidas por sintaxe • Terminais possuem apenas atributos sintetizados (pelo analisador léxico). Atributos Sintetizados • Muito usados na prática. • Uma definição que usa apenas atributos sintetizados é chamada de S-attributed definition. • Definições S-attributed podem sempre ser anotadas através da avaliação das regras semânticas em cada nó, atravessando a parse tree bottom-up, a partir das folhas. Exemplo –parse tree anotada para 3 * 5 + 4 \n E.val = 19 E.val = 15 + T.val = 4 T.val = 15 F.val = 4 T.val = 3 F.val = 3 digit.lexval = 3 * F.val = 5 digit.lexval = 4 digit.lexval = 5 Atributos Herdados • Definidos a partir dos nós-pai e/ou dos nósirmãos. • Úteis para especificar dependência do contexto, por exemplo se um identificador aparece à esquerda ou direita de uma atribuição. • É sempre possível trabalhar apenas com atributos sintetizados. Atributos herdados - exemplo Produção DgTL T g int T g real L g L1 , id L g id Regra semântica L.inh = T.type T.type = integer T.type = real L1.inh = L.inh addtype(id.entry, L.inh) addtype(id.entry, L.inh) Exemplo – atributos herdados D T.type = real L.inh = real real L.inh = real L.inh = real id1 , , id2 id3 Grafos de dependência • Úteis para determinar a ordem de avaliação dos atributos: 1. Gerar grafo de dependência 2. Fazer sort topológico – ordenação dos nós de um grafo acíclico dirigido em que todas as arestas vão de um nó anterior para nós posteriores. Construção de árvores sintáticas • A construção de árvores sintáticas como representação intermediária permite separar o processo de tradução do processo de parsing. Construção de árvores sintáticas • • Uma gramática adequada para parsing pode não ser adequada para refletir a hierarquia natural das construções de uma linguagem. Ex: sequência de statements vs. expressões aninhadas em FORTRAN. Alem disso, o método de parsing pode não ser adequado para a construção de uma parse tree. Árvores sintáticas (abstratas) • • Uma árvore sintática (abstrata) é uma forma condensada de parse tree adequada para representar os construtores de uma linguagem. Operadores e palavras chaves (que são terminais) normalmente não aparecem como folhas, e sim associados a um nó. Árvores sintáticas - exemplo If-then-else B S1 S2 + while * B 4 S1 3 5 Construindo Árvores Sintáticas • • • • Semelhante à tradução para notação pós-fixa: criar sub-árvores criando um nó para cada operando e operador. Cada nó pode ser representado por um registro com vários campos. Operador: um campo identifica o tipo do operador, e os outros campos são apontadores para os nós dos operandos. Podem existir campos adicionais para guardar atributos. Construindo uma árvore sintática para expressões • • • • Funções auxiliares: Node(op,left,right) Leaf(id, entry) Leaf(num, val) Construindo uma árvore sintática para expressões - exemplo • • Contruir a árvore para a expressão: a–4+c p1 = new Leaf(id, entry_a); p2 = new Leaf(num, 4); p3 = new Node(‘-’,p1,p2); p4 = new Leaf(id, entry_c); p5 = new Node(‘+’, p3, p4); Definição dirigida por sintaxe – construindo uma árvore Produção Regra semântica E g E1 + T E g E1 - T EgT Tg(E) T g id T g num E.node = new Node(‘+’, E1.node,T.node) E.node = new Node(‘-’, E1.node,T.node) E.node = T.node T.node = E.node T.node = new Leaf(id,id.entry) T.node = new Leaf(num,num.val)