Como construir um compilador utilizando ferramentas Java Aula 9 – Construção da árvore sintática Prof. Márcio Delamaro [email protected] Como construir um compilador utilizando ferramentas Java – p. 1/4 O que temos até agora JavaCC javac prog.x Erros sintáticos kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk langX Analisador Sintático kfdfdjkfdsjkfdsjkfdkfdsjk Não erros Como construir um compilador utilizando ferramentas Java – p. 2/4 O que queremos JavaCC javac prog.x Erros sintáticos kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk kfdfdjkfdsjkfdsjkfdkfdsjk langX Analisador Sintático kfdfdjkfdsjkfdsjkfdkfdsjk Não erros Como construir um compilador utilizando ferramentas Java – p. 3/4 O que é árvore sintática Dada a GLC, uma árvore sintática é uma árvore rotulada cuja raiz tem sempre o não-terminal inicial como rótulo. Numa derivação S ⇒ α1 α2 ...αn o nó S tem como filhos n nós rotulados α1 até αn . Como construir um compilador utilizando ferramentas Java – p. 4/4 Exemplo class test { } class test2 { } hprogrami hclasslisti EOF hclassdecli class hclasslisti test hclassbodyi { } hclassdecli class test2 hclassbodyi { } Como construir um compilador utilizando ferramentas Java – p. 5/4 Árvore sintática abstrata hprogrami hclasslisti hclassdecli test hclasslisti hclassbodyi λ hclassdecli test2 hclassbodyi λ Como construir um compilador utilizando ferramentas Java – p. 6/4 Construção da árvore À medida que um não terminal é reconhecido, um nó da árvore é criado De baixo para cima Cada execução de um dos métodos associados aos não-terminais cria um nó da árvore e “pendura” nele os nós filhos. Como construir um compilador utilizando ferramentas Java – p. 7/4 Construção da árvore Tokens reconhecidos naquele método e pelos outros nós criados pelas chamadas a outro métodos de não-terminais. Cada nó da árvore é representado por um objeto Java que possui referências a outro objetos, que são seus filhos. Nós diferentes são representados por objetos de diferentes classes. Como construir um compilador utilizando ferramentas Java – p. 8/4 Hierarquia de classes Todas as classes que representam os nós têm uma superclasse em comum Como construir um compilador utilizando ferramentas Java – p. 9/4 Hierarquia de classes Todas as classes que representam os nós têm uma superclasse em comum GeneralNode ClassDeclNode ListNode Como construir um compilador utilizando ferramentas Java – p. 9/4 GeneralNode package syntacticTree; import Token; abstract public class GeneralNode { public Token position; public GeneralNode(Token x) { position = x; } } Como construir um compilador utilizando ferramentas Java – p. 10/4 Modificações no .jj cada método correspondente aos não-terminais pode retornar um valor. Cada um desses métodos retorna o nó que construiu, permitindo que o método que fez a chamada possa utilizar esse nó; Como construir um compilador utilizando ferramentas Java – p. 11/4 Modificações no .jj cada método correspondente aos não-terminais pode retornar um valor. Cada um desses métodos retorna o nó que construiu, permitindo que o método que fez a chamada possa utilizar esse nó; cada token consumido pelo AS pode ser utilizado pelos métodos dos não-terminais para construir o nó da árvore. Para isso, basta “atribuir” o token que aparece na definição BNF para uma variável e, depois, utilizá-la na construção do nó; Como construir um compilador utilizando ferramentas Java – p. 11/4 Modificações no .jj cada método correspondente aos não-terminais pode retornar um valor. Cada um desses métodos retorna o nó que construiu, permitindo que o método que fez a chamada possa utilizar esse nó; cada token consumido pelo AS pode ser utilizado pelos métodos dos não-terminais para construir o nó da árvore. Para isso, basta “atribuir” o token que aparece na definição BNF para uma variável e, depois, utilizá-la na construção do nó; a cada token e a cada chamada de um método de um não-terminal que aparecem nas definições BNF é possível associar código Java que é executado. Como construir um compilador utilizando ferramentas Java – p. 11/4 classdecl – retorno ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : {} { try { <CLASS> <IDENT> [ <EXTENDS> <IDENT> ] classbody(g) } catch (ParseException e) { consumeUntil(g, e, "classdecl"); } } Como construir um compilador utilizando ferramentas Java – p. 12/4 classdecl – tokens ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null; } { try { t1 = <CLASS> <IDENT> [ <EXTENDS> <IDENT> ] classbody(g) } catch (ParseException e) { consumeUntil(g, e, "classdecl"); } } Como construir um compilador utilizando ferramentas Java – p. 13/4 classdecl – tokens ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null, t2 = null, t3 = null; } { try { t1 = <CLASS> t2 = <IDENT> [ <EXTENDS> t3 = <IDENT> ] classbody(g) } catch (ParseException e) { consumeUntil(g, e, "classdecl"); } } Como construir um compilador utilizando ferramentas Java – p. 14/4 classdecl – nós filhos ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null, t2 = null, t3 = null; ClassBodyNode c1 = null; } { try { t1 = <CLASS> t2 = <IDENT> [ <EXTENDS> t3 = <IDENT> ] c1 = classbody(g) } catch (ParseException e) { consumeUntil(g, e, "classdecl"); } } Como construir um compilador utilizando ferramentas Java – p. 15/4 classdecl – retorno ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null, t2 = null, t3 = null; ClassBodyNode c1 = null; } { try { t1 = <CLASS> t2 = <IDENT> [ <EXTENDS> t3 = <IDENT> ] c1 = classbody(g) { return new ClassDeclNode(t1, t2, t3, c1); } } catch (ParseException e) { consumeUntil(g, e, "classdecl"); } } Como construir um compilador utilizando ferramentas Java – p. 16/4 classdecl – erro sintático ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null, t2 = null, t3 = null; ClassBodyNode c1 = null; } { try { t1 = <CLASS> t2 = <IDENT> [ <EXTENDS> t3 = <IDENT> ] c1 = classbody(g) { return new ClassDeclNode(t1, t2, t3, c1); } } catch (ParseException e) { consumeUntil(g, e, "classdecl"); return new ClassDeclNode(t1, t2, t3, c1); } } Como construir um compilador utilizando ferramentas Java – p. 17/4 classdecl ClassDeclNode classdecl(RecoverySet g) throws ParseEOFException : { Token t1 = null, t2 = null, t3 = null; ClassBodyNode c1 = null; } { try { t1 = <CLASS> t2 = <IDENT> [ <EXTENDS> t3 = <IDENT> ] c1 = classbody(g) { return new ClassDeclNode(t1, t2, t3, c1); } } catch (ParseException e) { consumeUntil(g, e, "classdecl"); return new ClassDeclNode(t1, t2, t3, c1); } } Como construir um compilador utilizando ferramentas Java – p. 18/4 ClassDeclNode package syntacticTree; import Token; public public public public class ClassDeclNode extends GeneralNode { Token name; Token supername; ClassBodyNode body; public ClassDeclNode(Token t1, Token t2, Token t3, ClassBodyNode c) { //passa token de referência para construtor da superclasse super(t1); name = t2; supername = t3; body = c; } } Como construir um compilador utilizando ferramentas Java – p. 19/4 ClassDeclNode package syntacticTree; import Token; public public public public class ClassDeclNode extends GeneralNode { Token name; Token supername; ClassBodyNode body; public ClassDeclNode(Token t1, Token t2, Token t3, ClassBodyNode c) { //passa token de referência para construtor da superclasse super(t1); name = t2; supername = t3; body = c; } } Como construir um compilador utilizando ferramentas Java – p. 20/4 ClassDeclNode package syntacticTree; import Token; public public public public class ClassDeclNode extends GeneralNode { Token name; Token supername; ClassBodyNode body; public ClassDeclNode(Token t1, Token t2, Token t3, ClassBodyNode c) { //passa token de referência para construtor da superclasse super(t1); name = t2; supername = t3; body = c; } } Como construir um compilador utilizando ferramentas Java – p. 21/4 classdecl – exemplo class a extends b { ... } ClassDeclNode Token: a Token: b ClassBodyNode Como construir um compilador utilizando ferramentas Java – p. 22/4 Nó inicial ListNode program() throws ParseEOFException : { RecoverySet g = First.program; ListNode l = null, d = null; } { <EOF> | ( l = classlist(g) try { <EOF> {return l;} } catch (ParseException e) { consumeUntil(g, e, "program"); } [ d = program() ] ) { return l;} } Como construir um compilador utilizando ferramentas Java – p. 23/4 ListNode ListNode GeneralNode ListNode GeneralNode ListNode GeneralNode Como construir um compilador utilizando ferramentas Java – p. 24/4 ListNode class a extends b { ... } class b { ... } class c { ...} ListNode ClassDeclNode ListNode ClassDeclNode ListNode ClassDeclNode Como construir um compilador utilizando ferramentas Java – p. 25/4 classlist ListNode classlist(RecoverySet g) throws ParseEOFException : { ClassDeclNode c = null; ListNode l = null; RecoverySet f = First.classlist.union(g); } { ( c = classdecl(f) [ l = classlist(g) ] ) { return new ListNode(c, l);} } Como construir um compilador utilizando ferramentas Java – p. 26/4 classbody ClassBodyNode classbody(RecoverySet g) throws ParseEOFException : { ListNode c = null, v = null, ct = null, m = null; VarDeclNode vd; ConstructDeclNode cd; MethodDeclNode md; Token t = null; Como construir um compilador utilizando ferramentas Java – p. 27/4 classbody try { t = <LBRACE> [c = classlist(f5)] (LOOKAHEAD(3) vd = vardecl(f2) <SEMICOLON> { if ( v == null) v = new ListNode(vd); else v.add(vd); } )* Como construir um compilador utilizando ferramentas Java – p. 28/4 classbody (cd = constructdecl(f4) { if ( ct == null) ct = new ListNode(cd); else ct.add(cd); } )* Como construir um compilador utilizando ferramentas Java – p. 29/4 classbody (md = methoddecl(f3) { if ( m == null) m = new ListNode(md); else m.add(md); } )* Como construir um compilador utilizando ferramentas Java – p. 30/4 classbody <RBRACE> { return new ClassBodyNode(t, c, v, ct, m); } } catch (ParseException e) { consumeUntil(g, e, "classbody"); return new ClassBodyNode(t, c, v, ct, m); } } Como construir um compilador utilizando ferramentas Java – p. 31/4 classbody – exemplo class teste { class a { ... } class b { ... } int c, d; string e, f; constructor (int g) { ... } int h() { ... } } Como construir um compilador utilizando ferramentas Java – p. 32/4 classbody – exemplo ClassDeclNode Token: teste ClassBodyNode ListNode ListNode ConstructDeclNode ListNode VarDeclNode ListNode ClassDeclNode ListNode VarDeclNode ListNode MethodDeclNode ClassDeclNode Como construir um compilador utilizando ferramentas Java – p. 33/4 Caso especial – StatementNode StatementNode GeneralNode VarDeclNode AtribNode IfNode PrintNode Como construir um compilador utilizando ferramentas Java – p. 34/4 statement StatementNode statement(RecoverySet g) throws ParseEOFException : { StatementNode s = null; } { try { ( s = vardecl(f1) <SEMICOLON> | s = atribstat(f1) <SEMICOLON> | s = printstat(f1) <SEMICOLON> | . . . ) {return s;} } Como construir um compilador utilizando ferramentas Java – p. 35/4 StatementNode – exemplo int[][] m(string b[], int c) { ; c = 0; } Como construir um compilador utilizando ferramentas Java – p. 36/4 StatementNode – exemplo MethodDeclNode Token: int Token: string Token: b 2 Token: m MethodBodyNode ListNode BlockNode VarDeclNode ListNode ListNode ListNode VarDeclNode NopNode ListNode VarNode Token: int ListNode AtribNode 1 VarNode Token: c 0 Como construir um compilador utilizando ferramentas Java – p. 37/4 StatementNode – exemplo II if ( a == b) if ( c < d ) a = 10; else { b = 0; c = 1024; } Como construir um compilador utilizando ferramentas Java – p. 38/4 StatementNode – exemplo II IfNode ExpreNode IfNode ExpreNode AtribNode BlockNode ListNode AtribNode ListNode AtribNode Como construir um compilador utilizando ferramentas Java – p. 39/4 StatementNode – exemplo III for ( i = 0 ; i < a; i = i + 1) for (j = i + 1; j < b; j = j + 1) { b = 0; c = 1024; } Como construir um compilador utilizando ferramentas Java – p. 40/4 StatementNode – exemplo III ForNode AtribNode ExpreNode AtribNode AtribNode ForNode ExpreNode AtribNode BlockNode ListNode AtribNode ListNode AtribNode Como construir um compilador utilizando ferramentas Java – p. 41/4 ExpreNode – outra exceção Assim como StatementNode, o ExpreNode é uma classe abstrata. Como construir um compilador utilizando ferramentas Java – p. 42/4 ExpreNode – outra exceção Assim como StatementNode, o ExpreNode é uma classe abstrata. Dela descendem tipos diferentes de nós. Como construir um compilador utilizando ferramentas Java – p. 42/4 ExpreNode – outra exceção Assim como StatementNode, o ExpreNode é uma classe abstrata. Dela descendem tipos diferentes de nós. CallNode, DotNode, IndexNode, NewObjectNode, AddNode, MultNode, RelationalNode, etc. Como construir um compilador utilizando ferramentas Java – p. 42/4 ExpreNode – exemplo a+b+c AddNode AddNode VarNode Token: a Token: + Token: + VarNode VarNode Token: c Token: b Como construir um compilador utilizando ferramentas Java – p. 43/4 ExpreNode – exemplo II a + b.x < -3 * c[2] RelationalNode AddNode Token: < VarNode Token: + DotNode Token: a VarNode Token: x UnaryNode Token: b Token: - IntConstNode MultNode Token: * IndexNode VarNode intConstNode Token: c Token: 2 Token: 3 Como construir um compilador utilizando ferramentas Java – p. 44/4