Últimas notícias:
12 de Abril
Ao
entregar o segundo trabalho (tradução de Simples para C), coloque a nota que
você merece na primeira página do trabalho. Se o trabalho satisfaz todas as
exigências que pedi, dê 10.
4 de Abril
Havia
dois testes errados: ok-sem01.s e
ok-ger14.s. Eles foram corrigidos e os testes corretos estão aqui. O teste ok-ger13.s não deve ser utilizado. Corrigi x.bat para que ele não utilize este teste.
28 de Março
Está pronto o programa que analisará o
seu compilador e avisará quantos erros ele deixou de apontar nos exemplos e
quantos erros ele apontou e que não existem. Para utilizá-lo, faça o seguinte:
copie x.bat e degree para o
diretório onde estão os 150 testes. Tenha a certeza de
que o seu compilador está em um diretório citado no classpath. Descomprima
degree.zip e execute x.bat. Ele criará arquivos ok-*.txt e er-*.txt. Agora
chame o programa degree da seguinte forma:
Este
programa criará um arquivo out.txt. Veja este arquivo com more:
more out.txt
Em out.txt estarão
descritos os erros do seu compilador.
Naturalmente, assume-se que o seu
compilador possa ser chamado pela linha de comando
java comp Hello.s
onde comp é o nome
do compilador. Observe que não pode ser outro nome. Tem que ser comp.
Por
curiosidade, mostrarei a geração de código de Green. A partir de uma classe
Green A, do arquivo A.g, o compilador produz uma
interface A.gi e arquivos em Java _A.java e $co$A.java.
Este dois últimos contém o código compilado de A.g. São produzidos também
arquivos contendo interfaces, um arquivo para cada método declarado na classe
A. O código compilado é complexo porque ele contém suporte à biblioteca de
reflexão introspectiva de Green. Esta biblioteca permite ao programa descobrir
que classes o compõem, quais os métodos de cada classe ou objeto, os parâmetros
de dado método, o tipo de cada variável de instância de certa classe, etc.
27 de Março
Esqueçam a observação do dia 20 de
Março sobre o segundo trabalho. Como não daria tempo mesmo, achei melhor pedir
apenas a tradução de um programa em Simples para C, manualmente. Faça um
pequeno programa em Simples e o traduza para C. O programa deve ter:
a) uma
herança. Então devem existir pelo menos duas classes;
b) uma
redefinição de método na subclasse. Isto é, se B herda de A e A possui método
m, B deve ter um método m;
c) um envio
de mensagem a super;
d) um envio
de mensagem a self;
e) duas
variáveis de instância em classes diferentes.
f) envios de mensagem, atribuições, criações de
objetos, etc
A data de entrega é 12 de Abril. Se tiverem
dificuldade, me procurem. Estou acreditando que vocês não gastarão mais do que
duas horas para fazer este trabalho. Avisem-me se estiver mais difícil.
Alguém
tem um CD com o compilador C++ da Borland para me emprestar ? Prefiro a versão
4.52.
Estou
disponibilizando 150 testes para o compilador de
Simples. Gostaria que vocês testassem o vosso compilador utilizando estes
testes. Provavelmente amanhã, Quinta, disponibilizarei um programa que os
auxiliará a testar o compilador com todos os testes. Há testes para o
analisador léxico, sintático e semântico. Um teste chamado er-sin04.s contém um
erro e testa o analisador sintático. É o quarto teste deste tipo. Da mesma
forma, um teste ok-lex03.s testa o analisador léxico, não contém um erro (está
ok) e é o terceiro teste deste tipo.
Todos os grupos deverão marcar uma
entrevista comigo até o dia 12 de Abril. Os
elementos que não apareceram na primeira entrevista deverão obrigatoriamente
vir nesta. Na entrevista testarei os programas com os 150 testes, o que será
decisivo para a nota. O grupo deve trazer um disquete com o trabalho pronto
para ser executado. Isto é, os arquivos devem estar compilados e nos diretórios
corretos. Lembrem-se de que um programa em Simples deve ser compilado pela
linha de comando
java comp Hello.s
onde comp é o nome do compilador e Hello.s o
nome do programa a ser compilado. O compilador deve ainda produzir um arquivo
chamado result.txt contendo 0 ou 1. Estas duas condições são fundamentais para
que eu teste o compilador e sem as quais me será impossível dar a nota. Se
necessário, modifiquem o compilador que entregaram para que ele pegue o maior
número de erros possível.
20 de Março
O
segundo trabalho é a construção de um gerador de código para Simples cuja saída
é C. A tradução de Simples para C é descrita no artigo “Geração
e Otimização de Código Orientado a Objetos”. Este artigo não possui
as figuras 1 e 7, que podem ser
obtidas aqui.
Teremos
aula na Segunda dia 25 de Março. O número das salas é 157, 191, 172, 159 para
os horários de 8-10, 10-12, 14-16 e 16-18, respectivamente.
18 de Março
Por
causa de inúmeros pedidos, decidi adiar a data de entrega dos trabalhos para o
dia 22 de Março. Possivelmente
teremos aula na Segunda feira dia 25 de Março: eu explicarei como gerar código
em C para Simples. Mas aguardem outro comunicado amanhã, Terça ou no máximo
Quarta feira.
Alguns
grupos não apareceram para a entrevista. Eles receberão nota 1 na primeira
parte do trabalho, que valia 3.
Alguns
grupos estão me devendo a listagem da primeira parte do trabalho, que eu pedi na
entrevista. Entreguem-na o mais rápido possível. Se eu não pedi, não precisa
entregar.
Esqueçam
a organização das classes MessageSend dada no dia 4 de Março (veja abaixo). É
melhor fazer MessageSend herdar de Expression. Vocês descobrirão porque na hora
de gerar código: um envio de mensagem quando é um “Statement” exige
um “;” no final e como expressão, não. Então é melhor fazer o mais
complexo, MessageSend como Statement, utilizar o mais simples, MessageSend como
Expression. Assim, a organização das classes ficaria
abstract class MessageSend extends Expression { ... }
class
MessageSendToVariable extends MessageSend { ... }
class
MessageSendToSelf extends MessageSend
{ ... }
class
MessageSendToSuper extends MessageSend
{ ... }
class MessageSendStatement extends
Statement {
MessageSend messageSend;
public void gen( PrintWriter out ) {
ws.print(“”);
messageSend.gen(out);
out.println(“;”);
}
....
}
Java exige que variáveis sejam iniciadas antes de
serem utilizadas. Simples não. Assuma então que todas as variáveis dos
programas em Simples sejam iniciadas antes da utilização, mesmo que a linguagem
não exija isto. Isto é, assuma que o seguinte trecho de um programa em Simples
seja ilegal:
var a, b : integer;
begin
a = b; // não
iniciou o b
...
end
Não é necessário que você confira se as
variáveis foram iniciadas ou não.
4 de Março
Pessoal,
seria melhor organizar as classes de envios de mensagem assim:
abstract class
MessageSend extends Statement { ... }
class
MessageSendToVariable extends MessageSend { ... }
class
MessageSendToSelf extends MessageSend
{ ... }
class
MessageSendToSuper extends MessageSend
{ ... }
class
MessageSendExpr extends Expression {
MessageSend messageSend;
....
}
teríamos então um MessageSendToVariable que substitui o MessageSend anterior. E seria acrescentada uma
nova classe abstrata MessageSend, superclasse de todo mundo. Desta forma o código fica melhor
organizado. Quem já fez da maneira anterior e está funcionando, pode deixar.
Quem não fez, utilize o esquema acima.
Muita
gente fez uma classe ProcHeading. Ela é desnecessária. Coloquem dentro da classe Method tudo o que está em ProcHeading.
1 de Março
Imprimam os próximos trabalhos em fonte courier. Assim podemos ver ser a tabulação
está correta. Para quem não sabe, letras em courier ocupam sempre o mesmo espaço
horizontal, independente do tamanho da letra. O mesmo não ocorre com outras
fontes, onde o “i”, por exemplo, ocupa menos espaço do que o
“m” e outras letras mais gordinhas.
27 de Fevereiro
O trabalho foi adiado para o dia 15 de Março, impreterivelmente.
Coloque três tipos de envio de mensagem: MessageSend, MessageSendToSelf, MessageSendToSuper. A primeira é para envios de mensagens para variáveis, como “x.m()”. A segunda é para envios de mensagens para “self” ou para ninguém, como “m()”. O terceiro tipo é para envios para super, como “super.m()”. Você possivelmente precisará utilizar uma classe MessageSendExpr que contém um ponteiro para MessageSend. Esta classe deve ser utilizada quando um envio de mensagem for uma expressão, como em “a = x.m()”. Você pode organizar as classes assim:
class MessageSend
extends Statement { ... }
class
MessageSendToSelf extends MessageSend { ... }
class
MessageSendToSuper extends MessageSend {
... }
class
MessageSendExpr extends Expression {
MessageSend messageSend;
....
}
Ou se você quiser pode inverter as coisas: fazer
MessageSend herdar de Expression e criar uma classe MessageSendStatement que
contém um ponteiro para MessageSend. Aí todas as instruções que são envios de
mensagem, como “x.m();” serão representadas por uma instrução
MessageSendStatement.
Note
que há um envio de mensagem que não deve ser considerado um envio de mensagem:
é a criação de objetos, com new:
a = A.new();
Aqui, devemos criar um objeto de uma classe
ObjetCreation ou MessageSendNew (você escolhe o nome). Em qualquer caso, a
classe deve herdar de Expression, não de MessageSend. Ou talvez você consiga
fazer funcionar herdando de MessageSend.
Na tabela de símbolos, não há
necessidade de colocar os métodos. Coloque apenas as variáveis locais,
parâmetros (primeiro nível), variáveis de instância (segundo nível) e classes
(terceiro nível). Os métodos deverão ser procurados por um método searchMethod
da classe ClassDec (que representa uma classe de Simples). Quando houver um
envio de mensagem, como em
x.m();
deve-se procurar por método “m” na classe de “x”. Assim:
classOf_x.searchMethod(“m”);
Onde
classOf_x foi obtido por uma busca na tabela de símbolos pela classe
“A”, assim:
classOf_x = symbolTable.getInClass(“A”);
Assume-se
que x tenha sido declarado como
var x : A;
e que
método getInClass da tabela de símbolos procure por um símbolo apenas nas
classes da tabela.
A classe ClassDec (que representa
uma classe de Simples), deve ser algo como
class ClassDec
public ClassDec( String name ) {
this.name = name;
}
private String name, superclassName;
private InstanceVariableList
instanceVariableList;
private MethodList publicMethodList,
privateMethodList;
// métodos públicos get e set para obter
e iniciar as variáveis acima,
// entre
outros métodos
}
Não deve haver variáveis como publicPart ou
privatePart. Nem deve haver classes PublicPart e PrivatePart. Nem deve existir
classe UnPubPri.
ClassDec deve herdar de Type para que
a classe Variable e suas subclasses funcionem corretamente:
class Variable
private String name;
private Type type;
...
}
Como type é do tipo Type, esta variável de
instância pode apontar para objetos de Type e suas subclasses, o que inclui ClassDec.
Assim, o tipo de uma variável pode ser “integer” (objeto de Type),
“boolean” (objeto de Type)
ou uma classe (objeto de ClassDec).
O
construtor de ClassDec deve ter um único parâmetro, o nome da classe. Assim,
pode-se criar um objeto de ClassDec tão logo saibamos o nome da classe. Isto é
necessário pois o objeto que representa a classe deve logo ser inserido na
Tabela de Símbolos, pois uma classe pode declarar um objeto dela mesma:
class A
private:
var x : A;
...
end
Assim, ao
encontar o “x”, haverá uma busca na tabela de símbolos e lá será
encontrado o objeto de ClassDec que representa a classe A, que foi inserido lá
tão logo o nome da classe se tornou disponível.
A mesma observação vale para
MethodDec: podemos ter chamadas recursivas !
Para comparar strings em Java,
utilize compareTo:
if (
methodId.compareTo(“new”) == 0 )
...
25 de Fevereiro
Seria
interessante que vocês lessem um artigo sobre o
compilador Green que estou submetendo ao Simpósio Brasileiro de Linguagens
de Programação. Fala sobre algumas de minhas experiências na construção do
compilador.
Não
deve haver um método IdList no programa. A produção IdList na gramática é
utilizada para três coisas diferentes: análise de parâmetros, variáveis de
instância e variáveis locais. Em cada caso, o método IdList correspondente à
produção IdList teria que criar objetos de Parameter, InstanceVariable e
Variable. Então, crie três métodos iguais ao seu IdList correspondentes a cada
uma das classes Parameter, InstanceVariable e Variable. Veja no compilador
Green como foi feito.
18 de Fevereiro
O
comando loop-end existe na gramática, mas não está definido no texto. Ele
funciona da seguinte forma:
loop
...
end
Os comandos entre loop e end
repetem-se até que um comando break seja executado. É idêntico a
while
( true ) {
...
}
de Java.
Convoco
todos os grupos a me mostrar o trabalho até o fim da semana que vem, de
preferência o mais cedo possível. Gostaria de conversar com as pessoas, com a
listagem do código em mãos, para que eu possa dar sugestões de como adiantar o
trabalho, para que ninguém perca mais tempo. Enviem-me um e-mail para marcarmos
um horário. Meus horários livres são:
Se vocês me encontrarem no
departamento, podem conversar comigo em qualquer horário. Notem que esta
convocação é obrigatória e contará
como entrevista do trabalho, embora o objetivo principal seja facilitar o vosso trabalho e não avaliar o vosso
desempenho. Em tempo: estarei com a listagem dos trabalhos que vocês entregarem
na minha sala. Assim, não é necessário tirar outra cópia. E lembrem-se de que
vocês podem e devem utilizar o fineprint.
14 de Fevereiro
Pessoal, tinha esquecido de colocar
a gramática Green com o CUP. Ela está incompleta,
pois desisti de fazer o Green usando o CUP. É muito complicado para mim.
31 de Janeiro
Quando alguém
quiser tirar dúvidas e não me encontrar na minha sala, envie-me um email.
Leio-os todos os dias e podemos marcar uma "reunião" para o dia
seguinte. Preciso saber das dúvidas das pessoas para que eu possa colocar aqui
explicações que ajudaram a todos os grupos.
A classe ws, descrita abaixo , não está boa. Esta classe
será utilizada para fazer a saída do compilador. No nosso caso, o código em
Java gerado. A saída é feita para uma variável de PrintWriter em métodos,
digamos, chamados gen :
void gen( PrintWriter out ) {
ws.print("if (");
ifExpr.gen(out);
out.println(") {")
...
}
O problema é que estamos misturando uma saída
feita por um parâmetro, out, com outra feita por uma classe que funciona com
variável global. Inconsistente. O correto seria fazer tudo com parâmetros. Para
tanto, deveríamos modificar a classe ws tornando todos os seus métodos
não estáticos. E depois podemos passar dois parâmetros ao método gen, out e um
objeto de ws, ou colocar a funcionalidade de PrintWriter dentro da classe ws, o
que é muito melhor. Assim, teríamos que simplesmente acrescentar um método a ws
que imprime como o print e println de out. Só isso. Ou criar uma classe, fazê-la
herdar de PrintWriter e definir nela novos métodos equivalentes ao add,
sub, set, print e println de ws. Eu ficaria imensamente contente se algum grupo
fizesse essas modificações.
Interessante, mas ninguém
até agora notou uma terrível inconsistência no nome dos métodos dos
analisadores sintáticos que eu apresentei como exemplos. Lembram dos nomes dos
métodos ? São expr, ifStat, whileStat, varDec, etc. Absurdamente errado. Estes
nomes são substantivos. Métodos designam ações e portanto devem ter nomes
verbais. Os nomes corretos seriam analyzeExpr, analyzeIfStat, etc, dizendo
"analise uma expressão", ... Eu esqueci de fazer esta observação
durante o primeiro curso. Naturalmente, utizamos expr no lugar de analyzeExpr
por um motivo de economia de digitação. Mas no vosso trabalho vocês não
devem repetir este erro em outras classes que não o analisador sintático. O
guia de programação recomenda que vocês coloquem nomes significativos nos
métodos e isto significa colocar nomes verbais.
30 de Janeiro
Nas últimas semanas eu
estive muitíssimo ocupado e foi difícil de me encontar. Agora estou um pouco
mais livre e estarei mais no DC. Os horários mais prováveis de me encontrar são
das 11:30 às 12 horas e das 16 às 18 horas. Como o trabalho que tenho a fazer é
teórico (não no computador), não posso fazê-lo no DC, tenho que trabalhar em
casa.
Muitas pessoas estão reinventando a roda ao fazer o
trabalho. Por exemplo, tem gente fazendo o analisador léxico desde o início
quando poderia simplesmente modificar um dos analisadores exemplo do semestre
passado. É trabalho para um dia, no máximo. Peguem o máximo possível de código
dos trabalhos exemplo que deixei na apostila. E peguem o máximo do compilador
Green que agora está disponível nesta página:
Todo o compilador
O analisador sintático
O analisador léxico
A árvore de sintaxe abstrata
Alguns vão achar difícil de entender o
compilador, pois ele possui muitas outras coisas além do que vocês precisam.
Mas ainda assim vale a pena vê-lo. Vocês podem utilizar as classes que
representam expressões da ASA de Green, pois as expressões em Green são muito
semelhantes ou iguais às de Simples.
Algumas dicas para fazer o
trabalho:
A data da entrega da primeira parte do trabalho foi mudada para o dia 18 de
Fevereiro.
28 de Janeiro
Na produção
ReadStat ::= "read"
"(" LeftValue { LeftValue } ")"
Leia-se
ReadStat ::= "read"
"(" LeftValue { "," LeftValue }
")"
Na leitura de um valor inteiro (só inteiros podem ser lidos), você deve utilizar um método de Java que faz a leitura. Este método não está pronto. Utilize a classe abaixo
import java.io.*;
class Leia {
public static int readInt() {
int i = 0;
try {
BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
i =
Integer.valueOf(br.readLine()).intValue();
} catch (Exception e ) {
System.out.println("Read error !!!!");
System.exit(1);
}
return i;
}
}
A instrução em simples
read(a, b, c)
deve ser traduzida para
Leia.readInt(a);
Leia.readInt(b);
Leia.readInt(c);
em Java.
10 de Janeiro
Pessoal, vocês podem utilizar o programa Creation
para criar automaticamente um arquivo com as declarações de constantes do
léxico. Funciona assim: suponha que você tenha feito o analisador sintático e
lá tenha utilizado variáveis de uma classe Sym :
if ( lexer.getToken ().tk != Sym.END )
Você ainda não declarou a classe Sym mas
precisará criá-la, o que pode ser feito com o programa Creation. Chame-o com
C:\>java Creation Parser.java
Sym
onde Parser. java é o nome do seu analisador
sintático e Sym é o nome da classe Sym. Este programa criará uma classe Sym em
um arquivo “Sym .java” que conterá as declarações de todos os
símbolos. Lembre-se de que o analisador léxico deve estar em um outro arquivo
que não “ Sym.java ”. O Creation irá sobreescrever qualquer arquivo
“ Sym.java ” já existente.
Lembre-se de que o diretório onde você colocou
o programa Creation deve estar na variável “ classpath ”.
7 de
Janeiro
Temos 17 grupos fazendo o compilador com o CUP e 13 sem.
Para equilibrar a relação, dois grupos que estão utilizando o CUP utilizarão o
método recursivo descendente. O primeiro grupo que me procurou e pediu a
troca já foi contemplado. Quem quiser mudar do recursivo descendente para CUP deve
me enviar um e-mail o mais rápido possível --- ainda temos uma
"vaga".
19 de Dezembro
A maioria dos grupos ainda não me procurou para pegar
o seu peixe. Ou não me comunicaram que peixe pegaram. Assim, permitirei que
**alguns** grupos troquem o CUP pelo recursivo descendente para equilibrar a
relação
número de grupos com CUP/número de
grupos com recursivo descendente
Há mais grupos, na minha relação, com o CUP do que sem ele. Naturalmente, os
grupos que já me deram a lista de integrantes/peixe terão preferência na troca.
18 de Dezembro
A nova data para a parte I do trabalho é 1 de Março,
sendo que até o dia 11 de Fevereiro todos deverão me entregar a listagem do
código que já tiverem feito (isto valerá 3 dos 10 pontos do primeiro trabalho).
Ao imprimir a listagem, é recomendável utilizar o fineprint para economizar
papel e tinta. Se você não tiver este software, me procure.
A maioria dos grupos ainda não me enviou a listagem dos
integrantes. Isto já deveria ter sido feito há muito. Confira se o
seu grupo já foi cadastrado . Tenho os integrantes mas não o peixe de alguns grupos. Se tiver
curiosidade, procure informações seu peixe em um destes sites .
Algumas pessoas me procuraram querendo mudar o trabalho do
CUP para Recursivo Descendente. Gostaria que vocês trocassem os peixes enter si
de tal forma que metada da turma utilize o CUP e a outra não. Apesar do CUP ser
chato, o seu equivalente procedimental, o YACC, é utilizado nas empresas. Então
seria muito bom que pelo menos alguns de vocês soubessem utilizá-lo. Poderá ser
útil no futuro e teremos uma base de comparação das duas formas de construir um
compilador. De qualquer forma, quando as pessoas me mandarem os nomes de todos
os grupos com os respectivos peixes, poderei balancear os trabalhos CUP/sem
CUP. Pelas informações que tenho, há oito grupos com CUP e dois sem.
Recomendo fortemente uma segunda leitura da descrição do trabalho que também contém algumas
observações técnicas. Não se esqueça também do Guia de Correção dos Trabalhos .
10 de Dezembro
Pessoal, o semestre recomeçou oficialmente hoje. Mas tenho
a impressão, como seria de se esperar, de que a maioria dos alunos ainda não
retornou. Por causa disso, só marcarei novos prazos de entrega dos trabalhos em
Janeiro. Eu acho até possível que a UFSCar não considere estas duas semanas no
cômputo do semestre. Seria muito razoável.
A maior parte dos alunos ainda não me comunicou a
composição de seus grupos e sequer vieram pegar a senha para o trabalho. As
senhas só poderão ser pegas comigo, por e-mail ou pessoalmente. Os grupos
poderão trocar as senhas entre si.
Creio que todos vocês estão animadíssimos para continuar o
trabalho de compiladores, com toda a energia acumulada em cem dias de greve.
Vamos ao trabalho ! Se tiverem dúvidas, e elas serão muitas, estarei em
minha sala quase todo o tempo, principalmente
às tardes. Se alguém não conseguir me encontrar, mande-me um e-mail para
marcarmos um horário.
19 de
Setembro
Para os que estão fazendo o compilador com
o CUP: como colocar o + e - unários com maior precedência do que os operadores
restantes ?
Coloque normalmente a precedência dos operadores e acrescente um operador
inexistente UMINUS e UPLUS:
precedence
left OR;
precedence left
XOR;
...
// outros operadores
precedence nonassoc
LEFTSHIFT, RIGHTSHIFT;
precedence right NOT, UMINUS,
UPLUS, BINNOT, PLUSPLUS, MINUSMINUS;
Na regra com o operador
unário, utilize % prec :
Expr ::=
Expr:left OR Expr:right {:
RESULT = new BooleanCompositeExpr(left, Sym.OR, right);
:}
|
Expr:left XOR Expr:right {:
RESULT = new BooleanCompositeExpr(left, Sym.XOR, right);
:}
|
... // outras
regras
MINUS Expr:right {:
RESULT = new ArithmeticUnaryExpr( Sym.MINUS, right);
:} %prec UMINUS
|
PLUS Expr:right {:
RESULT = new ArithmeticUnaryExpr( Sym.PLUS, right);
:} %prec UPLUS
;
20 de Agosto
Está
disponível a lista que associa a senha ao tipo de trabalho . "Recursivo descendente"
quer dizer "Análise recursiva descendente e análise léxica feita sem
auxílio de ferramentas" e CUP significa "Utilize o CUP e JLex".
A partir de Quarta feira, as senhas só poderão ser pegas
comigo, pessoalmente ou por e-mail.
Comecem a fazer o trabalho. Lembrem -se de que fazer a
análise léxica será fácil. Fazer a análise sintática será fácil. Construir a
ASA será razoavelmente fácil. Gerar código em Java será fácil. Mas fazer a
análise semântica será difícil, embora vocês tenham perfeitas condições de
fazê-la. Não deixem para começar perto do fim do prazo.
Trabalhos (pdf)
Capa
dos Trabalhos
(pdf)
A Linguagem Simples ( ps ) ( pdf )
Guia
de Correção dos Trabalhos
O artigo "Geração de
Código em C para Simples" será colocado nesta página assim que estiver
corrigido.