Como construir um compilador utilizando ferramentas Java

Propaganda
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
Download