Como construir um compilador utilizando
ferramentas Java
Aula 12 – Análise Semântica
Prof. M ´arcio Delamaro
O que é
Preocupa com o significado de cada construção.
O que é
Preocupa com o significado de cada construção.
Depende da linguagem.
O que é
Preocupa com o significado de cada construção.
Depende da linguagem.
Passeio(s) na árvore sintática
O que é
Preocupa com o significado de cada construção.
Depende da linguagem.
Passeio(s) na árvore sintática
Realizada em diversas fases, cada um relativa a
diferentes aspectos.
Por que em fases?
class A {
B varB;
}
class B {
}
(1)ListNode (2)ClassDeclNode (8)ListNode Token: A (3)ClassBodyNode (9)ClassDeclNode(4)ListNode Token: B (10)ClassBodyNode
(5)VarDeclNode Token: B (6)ListNode
(7)VarNode Token: varB
Por que em fases?
a. visita ao nó 1
b. visita ao nó 2, insere a
classe
A
c. visita ao nó 3
d. visita ao nó 4
e. visita ao nó 5 e
veri-fica declaração
f. visita ao nó 8
g. visita ao nó 9 e insere
classe
B
h. visita ao nó 10
(1)ListNode (2)ClassDeclNode (8)ListNode Token: A (3)ClassBodyNode (9)ClassDeclNode(4)ListNode Token: B (10)ClassBodyNode (5)VarDeclNode
Token: B (6)ListNode (7)VarNode Token: varB
Por que em fases?
Fase 1:
a. visita ao nó 1
b. visita ao nó 2, insere a
classe
A
c. visita ao nó 3
d. visita ao nó 4
e. visita ao nó 5
f. visita ao nó 8
g. visita ao nó 9 e inserre
classe
B
h. visita ao nó 10.
(1)ListNode (2)ClassDeclNode (8)ListNode Token: A (3)ClassBodyNode (9)ClassDeclNode(4)ListNode Token: B (10)ClassBodyNode (5)VarDeclNode
Token: B (6)ListNode (7)VarNode Token: varB
Por que em fases?
Fase 2:
a. visita ao nó 1
b. visita ao nó 2
c. visita ao nó 3
d. visita ao nó 4
e. visita ao nó 5 e
veri-fica declaração
f. visita ao nó 8
g. visita ao nó 9
h. visita ao nó 10
(1)ListNode (2)ClassDeclNode (8)ListNode Token: A (3)ClassBodyNode (9)ClassDeclNode(4)ListNode Token: B (10)ClassBodyNode (5)VarDeclNode
Token: B (6)ListNode (7)VarNode Token: varB
analisador semântico: parte 1
Analisa a declaração de classes.
analisador semântico: parte 1
Analisa a declaração de classes.
Constrói tabela de símbolos.
analisador semântico: parte 1
Analisa a declaração de classes.
Constrói tabela de símbolos.
Ao encontrar um nó
ClassDeclNode
, o analisador
semântico deve incluir a classe correspondente na
tabela de símbolos.
analisador semântico: parte 1
Analisa a declaração de classes.
Constrói tabela de símbolos.
Ao encontrar um nó
ClassDeclNode
, o analisador
semântico deve incluir a classe correspondente na
tabela de símbolos.
A árvore sintática não precisa ser completamente
percorrida, somente os seus níveis mais altos.
analisador semântico: parte 1
Analisa a declaração de classes.
Constrói tabela de símbolos.
Ao encontrar um nó
ClassDeclNode
, o analisador
semântico deve incluir a classe correspondente na
tabela de símbolos.
A árvore sintática não precisa ser completamente
percorrida, somente os seus níveis mais altos.
Tratamento de classes aninhadas.
Tratamento das classes
ListNode ClassDeclNode class1 ListNode ClassDeclNode ClassBodyNode ClassBodyNode class2 Symtable class1 class2 class class1 { } class class2 { }Tratamento das classes aninhadas
ListNode ClassDeclNode class1 ListNode ClassDeclNode ListNode ClassDeclNode aninhada ListNode ClassDeclNode ClassBodyNode ClassBodyNode class2 ClassBodyNode ClassBodyNode Symtable class1 class2 aninhada aninhada aninhada Symtable Symtable class class1 { class aninhada{ } } class class2 { class aninhada { } }Erros semânticos...
Nessa fase da análise semântica, somente um tipo de erro
semântico pode ser detectado: quando uma classe que já
foi definida num determinado escopo é redefinida.
class class1
{
class class1 {
}
}
Implementação:
main
if ( parser.token_source.foundLexError() + parser.contParseError == 0) {
if (print_tree) // exibir a ´arvore {
PrintTree prt = new PrintTree(); prt.printRoot(root);
}
ClassCheck tc = new ClassCheck(); try {
tc.ClassCheckRoot(root);
System.out.println("0 Semantic error found"); } catch (SemanticException e) { System.out.println(e.getMessage()); } }
ClassCheck
package semanalysis; import symtable.*;
import syntacticTree.*; public class ClassCheck {
Symtable Maintable; // tabela de mais alto n´ıvel
protected Symtable Curtable; // apontador para a tb corrente int foundSemanticError;
public ClassCheck() {
EntrySimple k;
foundSemanticError = 0;
Maintable = new Symtable(); // cria tabela principal k = new EntrySimple("int"); // insere tipos b´asicos Maintable.add(k);
k = new EntrySimple("string"); Maintable.add(k);
}
Tratando da raiz
public void ClassCheckRoot(ListNode x) throws SemanticException {
Curtable = Maintable; // tabela corrente = principal // chama an´alise para raiz da ´arvore
ClassCheckClassDeclListNode(x); // se houve erro, lanc¸a excec¸˜ao if (foundSemanticError != 0)
throw new SemanticException(foundSemanticError +
" Semantic Errors found (phase 1)"); }
Tratando lista de classes
public void ClassCheckClassDeclListNode(ListNode x) {
if (x == null) return; try {
ClassCheckClassDeclNode( (ClassDeclNode) x.node); }
catch (SemanticException e)
{ // se um erro ocorreu na an´alise da classe,
// d´a a mensagem, mas faz a an´alise para pr´oxima classe System.out.println(e.getMessage());
foundSemanticError++; }
ClassCheckClassDeclListNode(x.next); }
Tratando declaração de uma classe
public void ClassCheckClassDeclNode(ClassDeclNode x) throws SemanticException {
// salva apontador p/ tabela corrente Symtable temphold = Curtable;
EntryClass nc;
if (x == null) return;
// procura classe na tabela
nc = (EntryClass) Curtable.classFindUp(x.name.image); if (nc != null) // j´a declarada, ERRO
{
throw new SemanticException(x.name,
"Class "+ x.name.image + " already declared"); }
// inclui classe na tabela corrente
Curtable.add(nc = new EntryClass(x.name.image, Curtable)); Curtable = nc.nested; // tabela corrente = tabela da classe ClassCheckClassBodyNode(x.body);
Curtable = temphold; // recupera apontador p/ tabela corrente }
Errata
O erro reportado no slide anterior deveria ser verificado
também na fase 2 apenas. No exemplo abaixo, B ainda não
estaria na tabela de símbolos, mas o erro deveria ser
apontado. Na fase i verifica-se a partir da tabela corrente.
Na fase 2 a partir da tabela do nível anterior.
class A {
class B{}
}
class B {}
Como fica a tabela de símbolos
int 1 0 string int 1 0 string int 1 0 string Maintable Curtable A Próx. livre Maintable Curtable Próx. livre A Maintable Próx. livre Curtable (a) (b) (c) 2 2 2 3Regras de escopo
Verifica-se se no escopo corrente já existe uma classe
com o mesmo nome da classe sendo declarada.
Regras de escopo
Verifica-se se no escopo corrente já existe uma classe
com o mesmo nome da classe sendo declarada.
Essa procura é feita por meio do método
Symtable.classFindUp
Regras de escopo
Verifica-se se no escopo corrente já existe uma classe
com o mesmo nome da classe sendo declarada.
Essa procura é feita por meio do método
Symtable.classFindUp
Procura a classe na tabela corrente.
Regras de escopo
Verifica-se se no escopo corrente já existe uma classe
com o mesmo nome da classe sendo declarada.
Essa procura é feita por meio do método
Symtable.classFindUp
Procura a classe na tabela corrente.
Caso não tenha encontrado, chama recursivamente a
pesquisa utilizando a tabela de nível superior.
classFindUp
public EntryTable classFindUp(String x) {
EntryTable p = top;
// para cada elemento da tabela corrente while (p != null)
{
// verifica se ´e uma entrada de classe ou tipo simples // e ent˜ao compara o nome
if ( ((p instanceof EntryClass) || (p instanceof EntrySimple)) && p.name.equals(x))
return p;
p = p.next; // pr´oxima entrada }
if (levelup == null) // se n˜ao achou e ´e o n´ıvel mais externo return null; // retorna null
// procura no n´ıvel mais externo
return levelup.mytable.classFindUp(x); }
Tratando o corpo da classe
Só interessa o corpo da classe se dentro dele houver
declaração de classe aninhada.
Tratando o corpo da classe
Só interessa o corpo da classe se dentro dele houver
declaração de classe aninhada.
Então somente a lista de classes é que interessa.
Tratando o corpo da classe
Só interessa o corpo da classe se dentro dele houver
declaração de classe aninhada.
Então somente a lista de classes é que interessa.
Dentro da declaração de variáveis, métodos ou
construtores, não existem declarações de classes.
Tratando o corpo da classe
public void ClassCheckClassBodyNode(
ClassBodyNode x)
{
if (x == null) return;
ClassCheckClassDeclListNode(x.clist);
}
Exercícios
Diga como ficaria a tabela de símbolos após a primeira fase da
analisador semântico ser concluída. Mostre também qual o
programa fonte que gerou cada árvore.
Exercícios
Exercícios
Exercícios
Exercícios
Exercícios
Análise semântica: parte 2
Nova classe
VarCheck
Análise semântica: parte 2
Nova classe
VarCheck
Usa a estrutura montada na parte 1
Análise semântica: parte 2
Nova classe
VarCheck
Usa a estrutura montada na parte 1
Faz outras verificações em relação a classes e
declaraçoes de variáveis.
Análise semântica: parte 2
Nova classe
VarCheck
Usa a estrutura montada na parte 1
Faz outras verificações em relação a classes e
declaraçoes de variáveis.
Não requer a análise de toda a árvore sintática.
Método
main
if ( parser.token_source.foundLexError() + parser.contParseError == 0) {
if (print_tree) // exibir a ´arvore {
PrintTree prt = new PrintTree();
prt.printRoot(root); // chama m´etodo para imprimir ´arvore }
VarCheck tc = new VarCheck(); try {
tc.VarCheckRoot(root);
System.out.println("0 Semantic Errors found"); } catch (SemanticException e) { System.out.println(e.getMessage()); } }
VarCheck
package semanalysis; import symtable.*;
import syntacticTree.*;
public class VarCheck extends ClassCheck { public VarCheck()
{
super(); }
public void VarCheckRoot(ListNode x) throws SemanticException {
ClassCheckRoot(x); // faz an´alise das classes VarCheckClassDeclListNode(x);
if (foundSemanticError != 0) // se houve erro, lanc¸a excec¸˜ao throw new SemanticException(foundSemanticError +
" Semantic Errors found (phase 2)"); }
VarCheck
: observações
É subclasse de
ClassCheck
VarCheck
: observações
É subclasse de
ClassCheck
Ou seja, ao criar um objeto dessa classe, são herdados
os métodos vistos na parte 1 da analisador semântico.
VarCheck
: observações
É subclasse de
ClassCheck
Ou seja, ao criar um objeto dessa classe, são herdados
os métodos vistos na parte 1 da analisador semântico.
Antes de iniciar a análise, é chamado o método
ClassCheckRoot(x)
que realiza a primeira parte da
análise.
Análise de uma lista de classes
public void VarCheckClassDeclListNode(ListNode x) {
if (x == null) return; try {
VarCheckClassDeclNode( (ClassDeclNode) x.node); }
catch (SemanticException e)
{ // se um erro ocorreu na an´alise da classe,
// d´a a mensagem, mas faz a an´alise para pr´oxima classe System.out.println(e.getMessage());
foundSemanticError++; }
VarCheckClassDeclListNode(x.next); }
Análise de uma declaração de classe
Se uma superclasse foi definida, verifica se a
superclasse existe.
Análise de uma declaração de classe
Se uma superclasse foi definida, verifica se a
superclasse existe.
Se existe, atualiza a tabela de símbolos.
Análise de uma declaração de classe
Se uma superclasse foi definida, verifica se a
superclasse existe.
Se existe, atualiza a tabela de símbolos.
Não verifica (ainda) circularidade
Análise de uma declaração de classe
Se uma superclasse foi definida, verifica se a
superclasse existe.
Se existe, atualiza a tabela de símbolos.
Não verifica (ainda) circularidade
class A extends B
class B extends C
class C extends A
Análise de uma declaração de classe
public void VarCheckClassDeclNode(ClassDeclNode x) throws SemanticException {
Symtable temphold = Curtable; // salva tabela corrente EntryClass c = null;
EntryClass nc;
if (x == null) return;
if (x.supername != null) { // verifica se superclasse foi definida c = (EntryClass) Curtable.classFindUp(x.supername.image);
if (c == null) { // Se n˜ao achou superclasse, ERRO
throw new SemanticException(x.position, "Superclass "+ x.supername.image + " not found");
} }
nc = (EntryClass) Curtable.classFindUp(x.name.image);
nc.parent = c; // coloca na tabela o apontador p/ superclasse Curtable = nc.nested; // tabela corrente = tabela da classe
VarCheckClassBodyNode(x.body);
Curtable = temphold; // recupera tabela corrente }
Análise de uma declaração de classe
// procura classe na tabela
nc = (EntryClass) Curtable.classFindUp(x.name.image); // procura nos niveis mais externos
if ( Curtable.levelup != null ) {
Symtable oneUp = Curtable.levelup.mytable;
EntryClass nc1 = (EntryClass) oneUp.classFindUp(x.name.image); if (nc1 != null) { // j´a declarada, ERRO
throw new SemanticException(x.name,
"Class " + x.name.image + " already declared"); }
}
nc.parent = c; // coloca na tabela o apontador p/ superclasse Curtable = nc.nested; // tabela corrente = tabela da classe VarCheckClassBodyNode(x.body);
Curtable = temphold; // recupera tabela corrente }
Outras declarações
Dentro de uma classe, existem declarações
Classes aninhadas
Variáveis
Construtores
Métodos
Trata o corpo de uma classe
public void VarCheckClassBodyNode(ClassBodyNode x) {
if (x == null) return;
VarCheckClassDeclListNode(x.clist); VarCheckVarDeclListNode(x.vlist);
VarCheckConstructDeclListNode(x.ctlist);
// se n˜ao existe constructor(), insere um falso
if ( Curtable.methodFindInclass("constructor", null) == null) { Curtable.add(new EntryMethod("constructor", Curtable.levelup, true)); } VarCheckMethodDeclListNode(x.mlist); }
Obs: construtor falso.
Declaração de variáveis
MyClass x, y;
Declaração de variáveis
MyClass x, y;
Verificar se
MyClass
existe na T.S.
Declaração de variáveis
MyClass x, y;
Verificar se
MyClass
existe na T.S.
Funciona para
int
ou
string
?
Declaração de variáveis
MyClass x, y;
Verificar se
MyClass
existe na T.S.
Funciona para
int
ou
string
?
Cada variável na declaração é inserida na T.S. corrente.
Declaração de variáveis
MyClass x, y;
Verificar se
MyClass
existe na T.S.
Funciona para
int
ou
string
?
Cada variável na declaração é inserida na T.S. corrente.
Declarações repetidas?
Declaração de variáveis
MyClass x, y;
Verificar se
MyClass
existe na T.S.
Funciona para
int
ou
string
?
Cada variável na declaração é inserida na T.S. corrente.
Declarações repetidas?
Não são verificadas pois não é possível ainda verificar
se na superclasse existe uma variável com o mesmo
nome.
Declaração de variáveis
public void VarCheckVarDeclNode(VarDeclNode x) throws SemanticException { EntryTable c;
ListNode p;
if (x == null) return;
// acha entrada do tipo da vari´avel
c = Curtable.classFindUp(x.position.image); // se n˜ao achou, ERRO
if (c == null)
throw new SemanticException(x.position, "Class "+ x.position.image + " not found");
// para cada vari´avel da declarac˜ao, cria uma entrada na tabela for (p = x.vars; p != null; p = p.next) {
VarNode q = (VarNode) p.node;
Curtable.add(new EntryVar(q.position.image, c, q.dim)); }
}
Declaração de construtor
Verifica o tipo de cada parâmetro.
Declaração de construtor
Verifica o tipo de cada parâmetro.
Cria uma
Entryrec
com os tipos dos parâmetros.
Declaração de construtor
Verifica o tipo de cada parâmetro.
Cria uma
Entryrec
com os tipos dos parâmetros.
Procura um construtor igual apenas na classe
corrente.
Declaração de construtor
Verifica o tipo de cada parâmetro.
Cria uma
Entryrec
com os tipos dos parâmetros.
Procura um construtor igual apenas na classe
corrente.
Insere um método com nome “constructor” na tabela de
símboloscorrente.
Declaração de construtor
public void VarCheckConstructDeclNode(ConstructDeclNode x) throws SemanticException { EntryMethod c; EntryRec r = null; EntryTable e; ListNode p; VarDeclNode q; VarNode u; int n; if (x == null) return; p = x.body.param; n = 0;
Declaração de construtor
while (p != null) // para cada parˆametro do construtor {
q = (VarDeclNode) p.node; // q = no com a declarac˜ao do parˆametro u = (VarNode) q.vars.node; // u = no com o nome e dimens˜ao
n++;
// acha a entrada do tipo na tabela
e = Curtable.classFindUp(q.position.image); // se n˜ao achou: ERRO
if (e == null)
throw new SemanticException(q.position, "Class " + q.position.image + " not found");
// constr´oi a lista com os parˆametros r = new EntryRec(e, u.dim, n, r);
p = p.next; }
if (r != null)
r = r.inverte(); // inverte a lista
Declaração de construtor
// procura construtor com essa assinatura dentro da mesma classe c = Curtable.methodFindInclass("constructor", r);
if (c == null)
{ // se n˜ao achou, insere
c = new EntryMethod("constructor", Curtable.levelup,0 ,r); Curtable.add(c);
}
else // construtor j´a definido na mesma classe: ERRO
throw new SemanticException(x.position, "Constructor " + Curtable.levelup.name +
"(" + (r == null? "" : r.toStr()) + ")" + " already declared");
}
Declaração de método
Como declaração de construtor
Declaração de método
Como declaração de construtor
Usa o nome do método em vez da palavra “constructor”
Declaração de método
Como declaração de construtor
Usa o nome do método em vez da palavra “constructor”
Procura o tipo de retorno para ver se foi declarado
Declaração de método
Como declaração de construtor
Usa o nome do método em vez da palavra “constructor”
Procura o tipo de retorno para ver se foi declarado
Insere na tabela normalmente
Análise semântica: parte 3
É a mais complexa das três.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Declaração de classes e variáveis.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Declaração de classes e variáveis.
Comandos.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Declaração de classes e variáveis.
Comandos.
Expressões.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Declaração de classes e variáveis.
Comandos.
Expressões.
Particularmente importante é a chacagem de tipos.
Análise semântica: parte 3
É a mais complexa das três.
Diversos aspectos são tratados.
Declaração de classes e variáveis.
Comandos.
Expressões.
Particularmente importante é a chacagem de tipos.
Ou seja: abrange toda a árvore sintática.
Checagem de tipo
if ( expr )
comando 1;
else
comando 2;
if ( b )
return 0;
Checagem de tipo
IfNode
VarNode
ReturnNode
Token: b
IntConstNode
Token: 0
procurar a variável b na tabela de símbolos
pegar o tipo com que a variável foi declarada
lançar uma exceção caso o tipo não seja int
Outros tipos de expressão
Nem sempre expressão é apenas uma variável.
Existem 13 tipos de
ExpreNode
como:
IntConstNode
,
VarNode
,
AddNode
,
MultNode
,
RelationalNode
Expressões podem ser compostas de subexpressões.
Cada método que analisa um desses nós deve ser
capaz de computar o tipo correspondente.
Exemplo:
if ( a + b > 10 )
return 0;
Exemplo
IfNode
RelationalNode
ReturnNode
AddNode
Token:
>
IntConstNode IntConstNode
VarNode Token: +
VarNode
Token: 10
Token: 0
Token: a
Token: b
Tipo de uma expressão
Antes de saber qual o tipo da expressão de controle
RelationalNode
, é necessário calcular o tipo de cada
subexpressão.
Tipo de uma expressão
Antes de saber qual o tipo da expressão de controle
RelationalNode
, é necessário calcular o tipo de cada
subexpressão.
É preciso saber se “a + b” e “10” são expressões do tipo
inteiro para poderem ser comparadas por meio do
operador
>
.
Tipo de uma expressão
Antes de saber qual o tipo da expressão de controle
RelationalNode
, é necessário calcular o tipo de cada
subexpressão.
É preciso saber se “a + b” e “10” são expressões do tipo
inteiro para poderem ser comparadas por meio do
operador
>
.
É preciso saber se as variáveis “a” e “b” são do tipo
inteiro para poderem ser somadas e produzir um
resultado inteiro.
Tipo de uma expressão
Antes de saber qual o tipo da expressão de controle
RelationalNode
, é necessário calcular o tipo de cada
subexpressão.
É preciso saber se “a + b” e “10” são expressões do tipo
inteiro para poderem ser comparadas por meio do
operador
>
.
É preciso saber se as variáveis “a” e “b” são do tipo
inteiro para poderem ser somadas e produzir um
resultado inteiro.
O tipo é calculado “de baixo para cima”, a partir das
subesxpressões mais simples.
Tipo de uma expressão
Antes de saber qual o tipo da expressão de controle
RelationalNode
, é necessário calcular o tipo de cada
subexpressão.
É preciso saber se “a + b” e “10” são expressões do tipo
inteiro para poderem ser comparadas por meio do
operador
>
.
É preciso saber se as variáveis “a” e “b” são do tipo
inteiro para poderem ser somadas e produzir um
resultado inteiro.
O tipo é calculado “de baixo para cima”, a partir das
subesxpressões mais simples.
O método que analisa uma expressão retorna o seu tipo.
Regras do
RelationalNode
se os dois operandos forem inteiros, a expressão está
OK e o seu tipo é int;
Regras do
RelationalNode
se os dois operandos forem inteiros, a expressão está
OK e o seu tipo é int;
se os dois operandos forem string, a expressão é válida
somente se o operador for de igualdade ou
desigualdade;
Regras do
RelationalNode
se os dois operandos forem inteiros, a expressão está
OK e o seu tipo é int;
se os dois operandos forem string, a expressão é válida
somente se o operador for de igualdade ou
desigualdade;
idem para dois objetos de tipos comparáveis (tipos
iguais ou um é subclasse do outro);
Regras do
RelationalNode
se os dois operandos forem inteiros, a expressão está
OK e o seu tipo é int;
se os dois operandos forem string, a expressão é válida
somente se o operador for de igualdade ou
desigualdade;
idem para dois objetos de tipos comparáveis (tipos
iguais ou um é subclasse do outro);
strings e objetos podem ser comparados quanto à
igualdade e à desigualdade com um outro operando que
seja null.
Geração de código
MyClass x;
a = x.myMethod( b + c);
criar as instruções para somar esses valores e produzir
um resultado inteiro;
chamar o método MyClass.myMethod(int).
Geração de código
MyClass x;
a = x.myMethod( b + c);
transformar o valor inteiro de b em um string;
concatenar o valor de a com esse valor transformado,
produzindo como resultado um string;
chamar o método MyClass.myMethod(string).
Método principal
// verifica se pode operar sobre a ´arvore sint´atica if ( parser.token_source.foundLexError()
+ parser.contParseError == 0) {
if (print_tree) // exibir a ´arvore {
PrintTree prt = new PrintTree();
prt.printRoot(root); // chama m´etodo para imprimir ´arvore }
TypeCheck tc = new TypeCheck(); try {
tc.TypeCheckRoot(root);
System.out.println("0 Semantic Errors found"); }
catch (SemanticException e) {
System.out.println(e.getMessage()); }
Análise da raiz
public void TypeCheckRoot(ListNode x)
throws SemanticException
{
// faz an´
alise das vari´
aveis e m´
etodos
VarCheckRoot(x);
// faz an´
alise do corpo dos m´
etodos
TypeCheckClassDeclListNode(x);
if (foundSemanticError != 0) // se houve erro,
throw new SemanticException(foundSemanticError
" Semantic Errors found
}
Declaração de classe
public void TypeCheckClassDeclNode(ClassDeclNode x) throws SemanticException {
Symtable temphold = Curtable; // salva tabela corrente EntryClass nc;
if (x == null) return;
nc = (EntryClass) Curtable.classFindUp(x.name.image); if ( circularSuperclass(nc, nc.parent) )
{ // se existe declarac¸˜ao circular, ERRO nc.parent = null;
throw new SemanticException(x.position, "Circular inheritance"); }
Curtable = nc.nested; // tabela corrente = tabela da classe TypeCheckClassBodyNode(x.body);
Curtable = temphold; // recupera tabela corrente }
Herança circular
// verifica se existe referˆencia circular de superclasses
private boolean circularSuperclass(EntryClass orig, EntryClass e) {
if ( e == null) return false; if (orig == e )
return true;
return circularSuperclass(orig, e.parent); }
Análise de construtor
// acha a entrada do construtor na tabela t = Curtable.methodFind("constructor", r); CurMethod = t; // guarda m´etodo corrente // inicia um novo escopo na tabela corrente Curtable.beginScope();
// pega a entrada da classe corrente na tabela thisclass = (EntryClass) Curtable.levelup;
thisvar = new EntryVar("this", thisclass, 0);
Curtable.add(thisvar); // inclui vari´avel local "this" com no. 0 Returntype = null; // tipo de retorno do m´etodo = nenhum
nesting = 0; // n´ıvel de aninhamento de comandos for Nlocals = 1; // inicializa n´umero de vari´aveis locais TypeCheckMethodBodyNode(x.body);
t.totallocals = Nlocals; // n´umero de vari´aveis locais do m´etodo Curtable.endScope(); // retira vari´aveis locais da tabela
}
Tratamento dos comandos
A partir desse ponto “para baixo” é feito o tratamento
dos comandos que aparecem na árvore sintática.
Tratamento dos comandos
A partir desse ponto “para baixo” é feito o tratamento
dos comandos que aparecem na árvore sintática.
Cada tipo de nó (cada comando) diferente é tratado de
modo diferente.
Tratamento dos comandos
A partir desse ponto “para baixo” é feito o tratamento
dos comandos que aparecem na árvore sintática.
Cada tipo de nó (cada comando) diferente é tratado de
modo diferente.
Pode ser um tratamento muito simples (
BlockNode
,
PrintNode
) ou complexo (
VarDeclNode
).
BlockNode
public void TypeCheckBlockNode(BlockNode x) {
Curtable.beginScope(); // in´ıcio de um escopo TypeCheckStatementListNode(x.stats);
Curtable.endScope(); // final do escopo, libera vars. locais }
public void TypeCheckStatementListNode(ListNode x) { if (x == null) return;
try {
TypeCheckStatementNode( (StatementNode) x.node); } catch (SemanticException e) { System.out.println(e.getMessage()); foundSemanticError++; } TypeCheckStatementListNode(x.next); }
PrintNode
public void TypeCheckPrintNode(PrintNode x)
throws SemanticException {
type t;
if (x == null) return;
// t = tipo e dimens˜ao do resultado da express˜ao t = TypeCheckExpreNode(x.expr);
// tipo tem que ser string e dimens˜ao tem que ser 0 if ( t.ty != STRING_TYPE || t.dim != 0 )
throw new SemanticException(x.position,
"string expression required"); }
Notar os erros que podem ocorrer.
Declaração de variável local
public void TypeCheckLocalVarDeclNode(VarDeclNode x) throws SemanticException { ListNode p; VarNode q; EntryVar l, u; EntryTable c; if (x == null) return;
// procura tipo da declarac¸˜ao na tabela de s´ımbolos c = Curtable.classFindUp(x.position.image);
// se n˜ao achou, ERRO if (c == null)
throw new SemanticException(x.position, "Class "+ x.position.image + " not found.");
Verifica se tipo existe.
Declaração de variável local
for (p = x.vars; p != null; p = p.next) {
q = (VarNode) p.node;
l = Curtable.varFind(q.position.image);
// se vari´avel j´a existe ´e preciso saber que tipo de vari´avel ´e if ( l != null)
{
// verifica se ´e local, definida no escopo corrente if (l.scope == Curtable.scptr) // se for, ERRO
throw new SemanticException(q.position, "Variable "+ p.position.image + " already declared");
Declaração de variáveis locais
Procura a variável na tabela de símbolos.
Declaração de variáveis locais
Procura a variável na tabela de símbolos.
Se achou, pode ser um erro (ou não).
Declaração de variáveis locais
Procura a variável na tabela de símbolos.
Se achou, pode ser um erro (ou não).
l.scope
indica em qual scopo foi inserida a variável.
Declaração de variáveis locais
Procura a variável na tabela de símbolos.
Se achou, pode ser um erro (ou não).
l.scope
indica em qual scopo foi inserida a variável.
Curtable.scptr
indica qual o scopo corrente.
Declaração de variáveis locais
Procura a variável na tabela de símbolos.
Se achou, pode ser um erro (ou não).
l.scope
indica em qual scopo foi inserida a variável.
Curtable.scptr
indica qual o scopo corrente.
Se forem iguais, significa que variável já existe no
escopo corrente.
Declaração de variáveis locais
// c.c. verifica se ´e uma vari´avel de classe
if (l.localcount < 0) // se for, d´a uma advertˆencia
System.out.println("Line " + q.position.beginLine + " Column " + q.position.beginColumn +
" Warning: Variable " + q.position.image + " hides a class variable");
else // sen˜ao, ´e uma vari´avel local em outro escopo
System.out.println("Line " + q.position.beginLine + " Column " + q.position.beginColumn +
" Warning: Variable " + q.position.image + " hides a parameter or a local variable");
Advertência: esconde variável já definida.
Declaração de variáveis locais
Curtable.add(
new EntryVar(q.position.image, c, q.dim, Nlocals++)
);
Insere na tabela.
Comando de atribuição
public void TypeCheckAtribNode(AtribNode x)
throws SemanticException {
type t1, t2; EntryVar v;
if (x == null) return;
// verifica se o n´o filho tem um tipo v´alido if ( ! (x.expr1 instanceof DotNode ||
x.expr1 instanceof IndexNode || x.expr1 instanceof VarNode) )
throw new SemanticException(x.position,
"Invalid left side of assignment");
Comando de atribuição
// verifica se ´e uma atribuic¸˜ao para "this" if ( x.expr instanceof VarNode )
{
EntryVar v = Curtable.varFind(x.expr.position.image);
if ( v != null && v.localcount == 0) // ´e a vari´avel local 0? {
throw new SemanticException(x.position,
"Assigning to variable \"this\" is not legal"); }
}
Comando de atribuição
t1 = TypeCheckExpreNode(x.expr1); t2 = TypeCheckExpreNode(x.expr2); // verifica tipos das express˜oes // verifica dimens˜oes
if ( t1.dim != t2.dim )
throw new SemanticException(x.position,
"Invalid dimensions in assignment");
Compatibilidade de tipos.
int[][] x, y;
x = new int[10][10];
y = x[0];
Comando de atribuição
// verifica se lado esquerdo ´e uma classe e direito ´e null, OK if (t1.ty instanceof EntryClass && t2.ty == NULL_TYPE )
return;
// verifica se t2 ´e subclasse de t1
if ( ! ( isSubClass(t2.ty,t1.ty) || isSubClass(t1.ty,t2.ty) ) ) throw new SemanticException(x.position,
"Incompatible types for assignment ");
Atribuição de subclasses
Nesse último caso, vale uma explicação sobre a semântica
que queremos dar a este comando. Primeiro, se o tipo do
lado direito for uma subclasse do tipo do lado esquerdo,
então a atribuição é feita naturalmente, sem problemas. No
caso inverso, antes de fazer a atribuição, o sistema de
execução faz por conta própria a coerção dos tipos.
Obviamente, se a coerção não puder ser feita, um erro de
execução ocorre.
Atribuição de subclasse
class A extends C {
int methA() {
C var1;
A var2;
B var3;
var1 = new A(); // OK
var2 = var1;
// OK c/ coerção
var3 = var1;
// ERRO
}
}
class B extends C ...
class C ...
Análise das expressões
Uma expressão em
X
++
pode ser uma simples
constante ou variável, ou uma expressão composta de
diversas expressões mais simples.
Análise das expressões
Uma expressão em
X
++
pode ser uma simples
constante ou variável, ou uma expressão composta de
diversas expressões mais simples.
O tipo de uma expressão é calculado com base nos
tipos das suas subexpressões.
Análise das expressões
Uma expressão em
X
++
pode ser uma simples
constante ou variável, ou uma expressão composta de
diversas expressões mais simples.
O tipo de uma expressão é calculado com base nos
tipos das suas subexpressões.
O método que trata uma expressão deve computar e
retornar um objeto do tipo “type”.
Classe
type
public class type {
public EntryTable ty;
// entrada na tabela
public int dim;
// dimens˜
ao
public type(EntryTable t, int d)
{
ty = t;
dim = d;
}
Tipo de uma constante
Para as constantes, obter o seu tipo é trivial.
Tipo de uma constante
Para as constantes, obter o seu tipo é trivial.
O próprio tipo do nó da árvore sintática determina qual o
tipo da constante.
Tipo de uma constante
Para as constantes, obter o seu tipo é trivial.
O próprio tipo do nó da árvore sintática determina qual o
tipo da constante.
Somente no caso de uma constante inteira é necessária
uma verificação extra.
Tipo de uma constante
Para as constantes, obter o seu tipo é trivial.
O próprio tipo do nó da árvore sintática determina qual o
tipo da constante.
Somente no caso de uma constante inteira é necessária
uma verificação extra.
Para verificar se é uma constante válida, utilizamos uma
chamada ao método
Integer.parseInt
da API Java.
Constante inteira
public type TypeCheckIntConstNode(IntConstNode x) throws SemanticException {
int k;
if (x == null) return null;
// tenta transformar imagem em n´umero inteiro try
{
k = Integer.parseInt(x.position.image); }
catch(NumberFormatException e)
{ // se deu erro, formato ´e inv´alido // (possivelmente fora dos limites)
throw new SemanticException(x.position, "Invalid int constant"); }
return new type(INT_TYPE, 0); }
Constante string ou null
public type TypeCheckStringConstNode(StringConstNode x) {
if (x == null) return null;
return new type( STRING_TYPE, 0); }
public type TypeCheckNullConstNode(NullConstNode x) {
if (x == null) return null;
return new type( NULL_TYPE, 0); }
Tipo de uma variável
Para uma variável também não é difícil calcular seu tipo.
Tipo de uma variável
Para uma variável também não é difícil calcular seu tipo.
Basta consultar a tabela de símbolos.
Tipo de uma variável
Para uma variável também não é difícil calcular seu tipo.
Basta consultar a tabela de símbolos.
Isto é feito utilizando o conhecido método
Symtable.varFind
Tipo de uma variável
Para uma variável também não é difícil calcular seu tipo.
Basta consultar a tabela de símbolos.
Isto é feito utilizando o conhecido método
Symtable.varFind
O nome está no nó
VarNode
sendo analisado.
Tipo de um
VarNode
public type TypeCheckVarNode(VarNode x) throws SemanticException {
EntryVar p;
if (x == null) return null; // procura vari´avel na tabela
p = Curtable.varFind(x.position.image); // se n˜ao achou, ERRO
if (p == null)
throw new SemanticException(x.position, "Variable " +
x.position.image + " not found"); return new type(p.type, p.dim);
}
Chamada de método
calcula o tipo da expressão que está no seu primeiro
filho e que representa a expressão à esquerda do “.” na
chamada do método
Chamada de método
calcula o tipo da expressão que está no seu primeiro
filho e que representa a expressão à esquerda do “.” na
chamada do método
se a dimensão é maior que zero. Caso seja, um erro foi
encontrado, pois um array não pode ter um método
associado a ele;
Chamada de método
calcula o tipo da expressão que está no seu primeiro
filho e que representa a expressão à esquerda do “.” na
chamada do método
se a dimensão é maior que zero. Caso seja, um erro foi
encontrado, pois um array não pode ter um método
associado a ele;
se o tipo calculado corresponde a uma classe. Caso
não seja, um erro foi encontrado, pois tipos simples não
podem ter métodos.
Tipo de um
CallNode
public type TypeCheckCallNode(CallNode x) throws SemanticException { EntryClass c;
EntryMethod m; type t1, t2;
if (x == null) return null;
// calcula tipo do primeiro filho t1 = TypeCheckExpreNode(x.expr); // se for array, ERRO
if ( t1.dim > 0 )
throw new SemanticException(x.position,
"Arrays do not have methods"); // se n˜ao for uma classe, ERRO
if (! (t1.ty instanceof EntryClass))
throw new SemanticException(x.position, "Type " + t1.ty.name + " does not have methods");
Chamada de método
Em seguida são calculados os tipos para cada um dos
argumentos.
Chamada de método
Em seguida são calculados os tipos para cada um dos
argumentos.
Utilizando o nome do método, que é um dos filhos do nó
corrente, e a lista de tipos dos argumentos, realiza-se
uma busca na tabela de símbolos para achar o método
adequado.
Chamada de método
Em seguida são calculados os tipos para cada um dos
argumentos.
Utilizando o nome do método, que é um dos filhos do nó
corrente, e a lista de tipos dos argumentos, realiza-se
uma busca na tabela de símbolos para achar o método
adequado.
A busca deve ser feita na classe adequada, ou seja, na
classe que foi calculada no início.
Chamada de método
Em seguida são calculados os tipos para cada um dos
argumentos.
Utilizando o nome do método, que é um dos filhos do nó
corrente, e a lista de tipos dos argumentos, realiza-se
uma busca na tabela de símbolos para achar o método
adequado.
A busca deve ser feita na classe adequada, ou seja, na
classe que foi calculada no início.
A entrada do método na tabela de símbolos diz-nos qual
é o tipo retornado pela chamada.
Tipo de um
CallNode
// pega tipos dos argumentos
t2 = TypeCheckExpreListNode(x.args);
// procura o m´etodo desejado na classe t1.ty c = (EntryClass) t1.ty;
m = c.nested.methodFind(x.meth.image, (EntryRec) t2.ty); // se n˜ao achou, ERRO
if (m == null)
throw new SemanticException(x.position, "Method " + x.meth.image
+ "(" + (t2.ty == null ? "" : ((EntryRec) t2.ty).toStr()) + ") not found in class " + c.name);
return new type(m.type, m.dim); }
Expressão de adição/subtração
AddNode
possui dois filhos
ExpreNode
e o tipo de
operação a ser executada.
Expressão de adição/subtração
AddNode
possui dois filhos
ExpreNode
e o tipo de
operação a ser executada.
São calculados os tipos das subexpressões.
Expressão de adição/subtração
AddNode
possui dois filhos
ExpreNode
e o tipo de
operação a ser executada.
São calculados os tipos das subexpressões.
Expressões devem ter tipo sem dimensão.
Expressão de adição/subtração
AddNode
possui dois filhos
ExpreNode
e o tipo de
operação a ser executada.
São calculados os tipos das subexpressões.
Expressões devem ter tipo sem dimensão.
Dois inteiros podem ser somados ou subtraídos.
Expressão de adição/subtração
AddNode
possui dois filhos
ExpreNode
e o tipo de
operação a ser executada.
São calculados os tipos das subexpressões.
Expressões devem ter tipo sem dimensão.
Dois inteiros podem ser somados ou subtraídos.
Soma pode ser realizada entre strings e inteiros.
Tipo de um
AddNode
public type TypeCheckAddNode(AddNode x)
throws SemanticException { type t1, t2;
int op; // operac¸˜ao int i, j;
if (x == null) return null; op = x.position.kind;
t1 = TypeCheckExpreNode(x.expr1); t2 = TypeCheckExpreNode(x.expr2); // se dimens˜ao > 0, ERRO
if ( t1.dim > 0 || t2.dim > 0 )
throw new SemanticException(x.position, "Can not use " + x.position.image + " for arrays");
Tipo de um
AddNode
i = j = 0;
if (t1.ty == INT_TYPE) i++;
else if (t1.ty == STRING_TYPE) j++;
if (t2.ty == INT_TYPE) i++;
else if (t2.ty == STRING_TYPE) j++;
// dois operadores inteiro, OK if (i == 2)
return new type(INT_TYPE, 0);
// um inteiro e um string. S´o pode somar if ( op == langXConstants.PLUS && i+j == 2)
return new type(STRING_TYPE, 0);
throw new SemanticException(x.position, "Invalid types for " + x.position.image);
}