Como construir um compilador utilizando ferramentas Java Aula 10 – Exibição da árvore sintática Prof. Márcio Delamaro [email protected] Como construir um compilador utilizando ferramentas Java – p. 1/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Como construir um compilador utilizando ferramentas Java – p. 2/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Introdução às demais fases do nosso compilador. Como construir um compilador utilizando ferramentas Java – p. 2/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Introdução às demais fases do nosso compilador. Não utilizaremos mais o arquivo .jj para fazermos nossas implementações. Como construir um compilador utilizando ferramentas Java – p. 2/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Introdução às demais fases do nosso compilador. Não utilizaremos mais o arquivo .jj para fazermos nossas implementações. A exibição da árvore sintática é efetuada por um conjunto de métodos que analisam os nós da árvore e adotam as ações necessárias para exibi-los. Como construir um compilador utilizando ferramentas Java – p. 2/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Introdução às demais fases do nosso compilador. Não utilizaremos mais o arquivo .jj para fazermos nossas implementações. A exibição da árvore sintática é efetuada por um conjunto de métodos que analisam os nós da árvore e adotam as ações necessárias para exibi-los. Para cada tipo de nó, existe um método correspondente. Como construir um compilador utilizando ferramentas Java – p. 2/2 Por que visualisar Verificar se nossa implementação da árvore sintática está correta. Introdução às demais fases do nosso compilador. Não utilizaremos mais o arquivo .jj para fazermos nossas implementações. A exibição da árvore sintática é efetuada por um conjunto de métodos que analisam os nós da árvore e adotam as ações necessárias para exibi-los. Para cada tipo de nó, existe um método correspondente. A análise semântica e a geração de código se processam exatamente da mesma forma. Como construir um compilador utilizando ferramentas Java – p. 2/2 Como vamos exibir Forma textual. Como construir um compilador utilizando ferramentas Java – p. 3/2 Como vamos exibir Forma textual. Cada nó é numerado. Como construir um compilador utilizando ferramentas Java – p. 3/2 Como vamos exibir Forma textual. Cada nó é numerado. Filhos são numerados (visita em profundidade) Como construir um compilador utilizando ferramentas Java – p. 3/2 Como vamos exibir Forma textual. Cada nó é numerado. Filhos são numerados (visita em profundidade) Exibe-se para cada nó: seu número, tipo, número dos nós filhos Como construir um compilador utilizando ferramentas Java – p. 3/2 Exemplo class a { string b; constructor(int c) { b = c + ""; } int m() { print "b: " + b; } } Como construir um compilador utilizando ferramentas Java – p. 4/2 Exemplo (1)ListNode (2)ClassDeclNode Token: a Token: string (3)ClassBodyNode (4)ListNode (8)ListNode (22)ListNode (5)VarDeclNode (9)ConstructDeclNode (23)MethodDeclNode (6)ListNode (10)MethodBodyNode Token: int Token: m (7)VarNode (11)ListNode (15)BlockNode (25)BlockNode Token: b (12)VarDeclNode (16)ListNode (26)ListNode Token: int (13)ListNode (17)AtribNode (27)PrintNode (14)VarNode (18)VarNode Token: c Token: b (19)AddNode (20)VarNode Token: + Token: c (24)MethodBodyNode (28)AddNode (29)StringConstNode (21)StringConstNode Token: ”b: ” Token: + (30)VarNode Token: b Token: ” ” Como construir um compilador utilizando ferramentas Java – p. 5/2 Exemplo 1: ListNode (ClassDeclNode) ===> 2 null 2: ClassDeclNode ===> a null 3 3: ClassBodyNode ===> null 4 8 22 4: ListNode (VarDeclNode) ===> 5 null 5: VarDeclNode ===> string 6 6: ListNode (VarNode) ===> 7 null 7: VarNode ===> b 8: ListNode (ConstructDeclNode) ===> 9 null 9: ConstructDeclNode ===> 10 10: MethodBodyNode ===> 11 15 11: ListNode (VarDeclNode) ===> 12 null 12: VarDeclNode ===> int 13 13: ListNode (VarNode) ===> 14 null 14: VarNode ===> c 15: BlockNode ===> 16 16: ListNode (StatementNode) ===> 17 null 17: AtribNode ===> 18 19 18: VarNode ===> b 19: AddNode ===> 20 + 21 20: VarNode ===> c Como construir um compilador utilizando ferramentas Java – p. 6/2 Observações Token não é numerado. Como construir um compilador utilizando ferramentas Java – p. 7/2 Observações Token não é numerado. Junto com um ListNode é exibido o tipo do nó contido na lista. Como construir um compilador utilizando ferramentas Java – p. 7/2 Observações Token não é numerado. Junto com um ListNode é exibido o tipo do nó contido na lista. Quando algum dos filhos não existe, utiliza-se “null” na exibição. Como construir um compilador utilizando ferramentas Java – p. 7/2 Observações Token não é numerado. Junto com um ListNode é exibido o tipo do nó contido na lista. Quando algum dos filhos não existe, utiliza-se “null” na exibição. Pequenas modificações devem ser feitas no método main no arquivo .jj Como construir um compilador utilizando ferramentas Java – p. 7/2 Argumento na chamada for (i = 0; i < args.length - 1; i++) { . . . if (args[i].equals("-print_tree") ) print_tree = true; . . . } Como construir um compilador utilizando ferramentas Java – p. 8/2 Exibição if ( parser.token_source.foundLexError() + parser.contParseError == 0 && print_tree) { PrintTree prt = new PrintTree(); prt.printRoot(root); } Como construir um compilador utilizando ferramentas Java – p. 9/2 Classe PrintTree Dentro do pacote syntacticTree Nessa única classe estão os métodos para numerar e exibir cada tipo de nó. Um método para numerar ClassDeclNode, um para numerar ClassbodyNode, um para cada tipo de ListNode, etc. O mesmo para exibir. O ponto de entrada na classe é o método printRoot que recebe um ListNode que é a raiz da árvore sintática. Como construir um compilador utilizando ferramentas Java – p. 10/2 Básicos da classe public class PrintTree { int kk; public PrintTree() { kk = 1; // inicializa contador de nós } public void printRoot(ListNode x) { if ( x == null ) System.out.println("Empty syntatic tree."); else { numberClassDeclListNode(x); printClassDeclListNode(x); } System.out.println(); } Como construir um compilador utilizando ferramentas Java – p. 11/2 Métodos que numeram atribuir ao nó que lhe foi passado como argumento o valor da variável kk; Como construir um compilador utilizando ferramentas Java – p. 12/2 Métodos que numeram atribuir ao nó que lhe foi passado como argumento o valor da variável kk; incrementar kk; Como construir um compilador utilizando ferramentas Java – p. 12/2 Métodos que numeram atribuir ao nó que lhe foi passado como argumento o valor da variável kk; incrementar kk; chamar os métodos para numeração, passando como argumento os filhos do nó que lhe foi passado como argumento. Como construir um compilador utilizando ferramentas Java – p. 12/2 Métodos que numeram atribuir ao nó que lhe foi passado como argumento o valor da variável kk; incrementar kk; chamar os métodos para numeração, passando como argumento os filhos do nó que lhe foi passado como argumento. Como armazenar o número do nó? Como construir um compilador utilizando ferramentas Java – p. 12/2 GeneralNode package syntacticTree; import Token; abstract public class GeneralNode { public Token position; public int number; public GeneralNode(Token x) { position = x; number = 0; } } Como construir um compilador utilizando ferramentas Java – p. 13/2 ClassBodyNode public void numberClassBodyNode(ClassBodyNode { if ( x == null ) return; x.number = kk++; numberClassDeclListNode(x.clist); numberVarDeclListNode(x.vlist); numberConstructDeclListNode(x.ctlist); numberMethodDeclListNode(x.mlist); } Como construir um compilador utilizando ferramentas Java – p. 14/2 Especial: ListNode public void numberListNode(ListNode x) { if ( x == null ) return; // numera x.node numberListNode(x.next); } Como construir um compilador utilizando ferramentas Java – p. 15/2 Especial: ListNode Ao visitarmos um nó desse tipo, queremos visitar cada elemento que compõe a lista. Precisamos saber qual é o tipo do nó filho. Sáo assim saberemos qual método chamar. Solução: um método para cada tipo possível de lista. Por exemplo: numberClassDeclListNode Como construir um compilador utilizando ferramentas Java – p. 16/2 numberClassDeclListNode public void numberClassDeclListNode(ListNode x) { if(x == null) return; x.number = kk++; numberClassDeclNode((ClassDeclNode)x.node); numberClassDeclListNode(x.next); } Como construir um compilador utilizando ferramentas Java – p. 17/2 Sete listas numberClassDeclListNode (lista de ClassDeclNode) numberVarDeclListNode (lista de VarDeclNode) numberVarListNode (lista de VarNode) numberConstructDeclListNode (lista de ConstructDeclNode) numberMethodDeclListNode (lista de MethodDeclNode) numberStatementListNode (lista de statementNode) numberExpreListNode (lista de ExpreNode). Como construir um compilador utilizando ferramentas Java – p. 18/2 Especial II: StatementNode public void numberMethodBodyNode( MethodBodyNode x) { if (x == null) return; x.number = kk++; numberVarDeclListNode(x.param); numberStatementNode(x.stat); } Como construir um compilador utilizando ferramentas Java – p. 19/2 Especial II: StatementNode O que deve fazer numberStatementNode? Descobrir qual é o tipo real do nó. Redirecionar para o método correto como: numberBlockNode, numberIfNode, numberForNode, numberPrintNode, etc Como construir um compilador utilizando ferramentas Java – p. 20/2 Especial II: StatementNode public void numberStatementNode(StatementNode x) { if (x instanceof BlockNode) numberBlockNode( (BlockNode) x); else if (x instanceof VarDeclNode) numberVarDeclNode( (VarDeclNode) x); else if (x instanceof AtribNode) numberAtribNode( (AtribNode) x); else if (x instanceof IfNode) numberIfNode( (IfNode) x); else Como construir um compilador utilizando ferramentas Java – p. 21/2 Especial III: ExpreNode O mesmo problema acontece quando um ExpreNode aparece como filho de um nó como, por exemplo, o IfNode. Existe um numberExpreNode que redireciona a chamada para o método correto, de acordo com o tipo real do nó. Como construir um compilador utilizando ferramentas Java – p. 22/2 Especial III: ExpreNode public void numberExpreNode(ExpreNode x) { if (x instanceof NewObjectNode) numberNewObjectNode( (NewObjectNode) x); else if (x instanceof NewArrayNode) numberNewArrayNode( (NewArrayNode) x); else if (x instanceof RelationalNode) numberRelationalNode( (RelationalNode) x); else if (x instanceof AddNode) numberAddNode( (AddNode) x); else Como construir um compilador utilizando ferramentas Java – p. 23/2 Exibição dos nós Aplica-se quase tudo que comentamos em relação a sua numeração. Para cada tipo de nó, temos um, ou em alguns casos, alguns métodos que tratam desse tipo de nó. A diferença reside nas ações que são tomadas. Queremos mostrar qual é o tipo de nó e quais são os seus filhos. Como construir um compilador utilizando ferramentas Java – p. 24/2 Exemplo: ClassBodyNode public void printClassBodyNode(ClassBodyNode x) { if ( x == null ) return; System.out.println(); System.out.print(x.number + ": ClassBodyNode ===> " + (x.clist == null ? "null" : String.valueOf(x.clist.number)) + " " + (x.vlist == null ? "null" : String.valueOf(x.vlist.number)) + " " + (x.ctlist == null ? "null" : String.valueOf(x.ctlist.number)) + " " + (x.mlist == null ? "null" : String.valueOf(x.mlist.number)) ); printClassDeclListNode(x.clist); printVarDeclListNode(x.vlist); printConstructDeclListNode(x.ctlist); printMethodDeclListNode(x.mlist); } Como construir um compilador utilizando ferramentas Java – p. 25/2 Exibição: Token Como esses nós não possuem numeração, quando aparecem na árvore sintática, exibimos diretamente seu conteúdo junto com o seu pai, ou seja, o conteúdo da sua variável image que mostra qual foi o símbolo consumido na entrada e que originou o token. Como construir um compilador utilizando ferramentas Java – p. 26/2 Exemplo: printClassDeclNode public void printClassDeclNode(ClassDeclNode x) { if ( x == null ) return; System.out.println(); System.out.print(x.number + ": ClassDeclNode ===> " + x.name.image + " " + (x.supername == null ? "null": x.supername.image) + " " + (x.body == null ? "null": String.valueOf(x.body.number)) ); printClassBodyNode(x.body); } Como construir um compilador utilizando ferramentas Java – p. 27/2 Outras operações Programa de “pretty-print” que produz como saída o programa-fonte formatado de acordo com algumas regras de indentação. Construção do grafo de fluxo de controle do programa. Esse tipo de grafo é muito útil para a atividade de teste, principalmente quando a este se associa informação sobre a utilização das variáveis. Cálculo da complexidade do programa, como número de linhas de código, complexidade ciclomática, complexidade de Halstead etc. Como construir um compilador utilizando ferramentas Java – p. 28/2 Exercício Faça o download dos arquivos do capítulo 7 do livro. Procure na Internet e faça o download do programa GraphViz. Determine como o GraphViz pode ser usado para gerar uma saída gráfica da árvore sintática. Crie uma nova classe PrintGraphTree que gera um arquivo no formato que possa ser processado pela GraphViz Adicione no seu compilador uma opção -graph_tree que habilita a geração desse arquivo. Como construir um compilador utilizando ferramentas Java – p. 29/2