implementação de tipos abstratos de dados no ambiente...
TRANSCRIPT
Trabalho de Conclusão de Curso
Implementação de Tipos Abstratos de Dados no Ambiente FURBOL
Autor: André Luís GarliniOrientador: José Roque Voltolini da Silva
Roteiro
• Introdução
� Objetivos do trabalho
• Fundamentação teórica
• Desenvolvimento
� Requisitos do sistema
� Especificação
� Implementação
� Operacionalidade
• Conclusões
Trabalho de Conclusão de Curso
Introdução
Introdução
• Linguagem de Programação (LP)
Serve como meio de comunicação entre o individuo que deseja resolver um problema e o computador escolhido para ajudá-lo na solução.
• Compiladores
Para realizar esta comunicação entre o individuo e o computador existem programas chamados de compiladores.
• Tipos Abstratos de Dados (TADs)
Toda LP apresenta seu próprio conjunto de símbolos e regras para formação de programas. Algumas oferecem a possibilidade da criação de TADs definidos pelo usuário.
• FURBOL
É uma LP desenvolvida na FURB que ainda não oferece suporte a TADs.
• Objetivo do trabalho
Este trabalho propõe-se a estender o FURBOL, a partir da implementação de Silva (2002), adicionando o suporte a TADs.
Objetivos do trabalho
• O objetivo deste trabalho é estender a LP FURBOL.
• O objetivo específico do trabalho é adicionar a possibilidade da criação de TADs pelos usuários do FURBOL.
Trabalho de Conclusão de Curso
Fundamentação teórica
Paradigmas de linguagens de programação
• Conjunto de características que servem para categorizar um grupo de LPs
Fonte: Varejão (2004, p. 17).
• Imperativo� Especificam como o computador deve realizar uma tarefa.� Orientação a objetos – Evolução dos TADs.
• Declarativo� Especificam o que é a tarefa a ser realizada.
Tipos Abstratos de Dados
• Conjuntos de valores (atributos) e operações executadas sobre esses valores (métodos). Exemplo - classe em C++ (sem herança/polimorfismo).
• Algumas vantagens
� Diminui a complexidade dos programas.
� Abstração. Representação interna fica “escondida” do usuário do TAD.
• Quatro tipos de operações
� Construtoras – inicializam os valores do TAD.
� Consultoras – usadas para obter informações do TAD.
� Atualizadoras – permitem a alteração dos valores do TAD.
� Destrutoras – qualquer atividade de finalização do TAD.
Exemplo de TAD
class pilha {private: //** Estes membros são visíveis somente a outros membros
//** e amigosint *ptr_pilha ;int tam_max ;int top_ptr ;
public: //** Estes membros são visíveis aos clientespilha () { //** Um construtor
ptr_pilha = new int [ 100 ];tam_max = 99;top_ptr = -1;
}~pilha () {delete [] ptr_pilha;}; //** Um destrutor~pilha () {delete [] ptr_pilha;}; //** Um destrutorvoid push (int numero) {
if (top_ptr == tam_max)cout << “Erro no pop – a pilha esta cheia\n”;
else ptr_pilha[++top_ptr] = numero;}void pop () {
if (top_ptr == -1)cout << “Erro no pop – a pilha esta vazia\n”;
else top_ptr--;}int top () {return (ptr_pilha[top_ptr]);}int empty () {return (top_ptr == -1);}
}
Fonte: adaptado de Sebesta (2000, p. 408-409).
Compiladores
• Programa tradutor que mapeia programas escritos em uma LP de alto nível para programas equivalentes em linguagem simbólica (assembly) ou linguagem de máquina.
• Etapas
� Análise léxica – faz a leitura do programa fonte e o traduz em símbolos léxicos (tokens). Exemplos - identificadores e palavras reservadas.
� Análise sintática – verifica se as construções usadas no programa estão gramaticalmente corretas.
� Análise semântica – determina se as estruturas sintáticas analisadas fazem sentido. Exemplo – compatibilidade entre operandos de uma expressão.
� Geração de código – nesta etapa é gerado código para a máquina alvo.
Tradução dirigida pela sintaxe
• Técnica que permite realizar a tradução do programa simultaneamente a análise sintática.
• Esquema de tradução
Extensão de uma Gramática Livre de Contexto (GLC) que associa atributos aos símbolos gramaticais e de ações semânticas (envolvidas entre chaves) às regras de produção.
• Atributos - qualquer informação necessária para a tradução de um programa. Exemplo – tipo de dado de uma variável. São classificados em dois tipos:
� Sintetizados – são calculados pela função. Fluem de filho para pai na árvore de derivação.
� Herdados – são entradas da função. Fluem de pai ou irmão na árvore de derivação.
Exemplo de um esquema de tradução
E � T RR � Op T { print(Op. simbol ) } R | Є
T � num { print(num. lexval )}
Fonte: adaptado de Price e Toscani (2001, p. 88).
Projeto de um tradutor preditivo
• Algoritmo
Entrada: um esquema de tradução (o esquema deve ser baseado numa gramática apropriada para análise preditiva).
Resultado: código de um tradutor dirigido por sintaxe.
Método:1) Para cada não-terminal A, construa uma função que tenha um parâmetro formal para cada atributo herdado de A e que retorne os valores dos atributos sintetizados de A. Além disso, a função para A deve ter uma variável local para cada atributo de símbolo gramatical que aparece nas produções de A.nas produções de A.2) O código para o não-terminal A deve decidir qual produção usar, baseado no símbolo corrente da entrada. Considerando o lado direito da produção a ser usada, da esquerda para a direita, o código associado deve implementar o seguinte:i) para cada token X, verificar se X é o token lido e avançar a leitura;ii) para cada não-terminal B, gerar uma atribuição c := B(b1, b2, ..., bk), sendo b1, b2, ..., bk variáveis para os atributos herdados de B, e c a variável para o atributo sintetizado de B;iii) para cada ação semântica, copiar o código correspondente, substituindo cada referência a atributo pela variável desse atributo.
Fonte: adaptado de Price e Toscani (2001, p. 110).
Código intermediário
• Forma intermediária de código independente de máquina.� Código intermediário de três endereços – tipo de código intermediário onde cada instrução faz referência no máximo a três variáveis (endereços de memória).
Geração de código-alvo
• Fase final de um compilador.
• Gerar código para a máquina alvo (FURBOL - Microprocessador 8088).
Microprocessador 8088
• Chip que executa os programas armazenados na memória.
• Desenvolvido pela empresa Intel Corporation, sendo uma versão do modelo 8086.
• Processador de 16 bits.
Memória do 8088
• 216 (65.536) - 220 (1.048.576)
• Esquema de endereçamento de 20 bits
• Endereços segmentados� Divide o espaço de memória endereçável em segmentos (64 KB).� Endereça a memória usando dois registradores. Um para o segmento e outro para o deslocamento (offset) dentro do deslocamento. deslocamento.
• Pilha – Segmento de memória. Algumas utilidades:� Salvar valores de registradores que serão utilizados.� Salvar endereço de retorno de um método.� Parâmetros e variáveis locais de um método.
Registradores do 8088
• Quatorze registradores de 16 bits
Registradores de propósito geral AX, BX, CX e DX
Registradores de ponteiros e de índices BP, SP, SI, DI
Registradores de segmento CS, DS, SS, ES
Registrador de ponteiro de instrução IP
Registrador de sinalizadores FLAGS
• Propósito geral - operações aritméticas e lógicas.
• Ponteiros e de índices – deslocamento dentro dos segmentos.
• Segmentos – identificam os quatro segmentos endereçáveis em um programa.
� CS– segmento de código� DSe ES – segmentos de dados� SS – segmento de pilha
• Ponteiro de instrução – indica o deslocamento da instrução que está sendo executada dentro do segmento de código.
• Sinalizadores – indicam resultados da última operação executada.
Algumas instruções do 8088
Instrução Formato Propósito
CALL CALL alvo Chamar uma sub-rotina.
INT INT tipo Alterar o fluxo de execução do programa, desviando-se para uma rotina de interrupção.
MOV MOV destino, fonte Copiar o conteúdo do operando fonte para o destino.
POP POP destino Retirar a palavra armazenada no topo da pilha colocando-a no registrador ou posição de memória especificada por destino.
PUSH PUSH fonte Colocar no topo da pilha o valor de fonte.
RET RET [dado] Encerrar uma sub-rotina, transferindo o fluxo do processamento para a RET RET [dado] Encerrar uma sub-rotina, transferindo o fluxo do processamento para a instrução seguinte à chamada da sub-rotina. O valor [dado] é opcional. Nele pode-se especificar um valor que após o retorno da sub-rotina será adicionado ao SP.
Fonte: adaptado de Santos e Raymundi (1989, p. 33-92).
FURBOL
• Vem sendo desenvolvida por vários integrantes do curso de Ciências da Computação da FURB.
• Características �adota o paradigma imperativo.� comandos em língua portuguesa.� comando de condição e repetição.� unidades de programas concorrentes.� mecanismo de sincronização da comunicação entre unidades � mecanismo de sincronização da comunicação entre unidades concorrentes do tipo semáforo.
• Gera código de montagem (assembly) compatível com microprocessadores 8088.
• Silva 2002 – unidades de programas concorrentes.
Trabalho de Conclusão de Curso
Desenvolvimento
Requisitos do Sistema
• Manter os seguintes requisitos do ambiente de Silva (2002):� possuir um editor para os arquivos fonte (Requisito Funcional – RF)� compilar o código fonte FURBOL, gerando como saída código de
montagem (assembly) compatível com microprocessadores 8088 (RF)
� emitir mensagens com os resultados da compilação (RF)� permitir a visualização do código intermediário de três endereços
gerado (RF)� permitir a visualização do código de montagem (assembly) gerado � permitir a visualização do código de montagem (assembly) gerado
(RF)� invocar o montador Turbo Assembler e o ligador Turbo Link para a
geração de código de máquina executável em microprocessadores 8088 (RF)
• Permitir a definição de TADs pelos usuários (RF)
• Usar esquemas de tradução para representar a semântica (Requisito Não-Funcional - RNF)
• Ser implementado usando o ambiente Borland Delphi 7.0 (RNF)
Especificação dos TADs (BNF Extendida)
TAD → id Se nãoSimbolos.SimboloRedeclarado(id.nome) entãoid.simbobj := TSimbolo.Create(id.nome, tsClasse);Simbolos.Instalar(id.simbobj);id.simbobj.TabelaMembros := Símbolos.AbrirEscopo(id.nome);
AtributosTAD
MetodosTAD
‘fim’ TAD.codigo := MetodosTAD.codigo;TAD.codasm := MetodosTAD.codasm;Simbolos.FecharEscopo;
';'
Especificação de um método (BNF Extendida)
MetodoTAD → id Se nãoSimbolos.SimboloRedeclarado(id.nome) entãoid.simbobj := TSimbolo.Create(id.nome, tsMetodo);Simbolos.Instalar(id.simbobj);id.simbobj.TabelaAgregada := Símbolos.AbrirEscopo(id.nome);id.simbobj.TipoMetodo := MetodoTAD.TipoMetodo;ParamOculto := TSimbolo.Create(‘esse’, tsObjeto);Símbolos.Instalar(ParamOculto);
ParamFormais
‘;’
EstruturaDados
CComposto MetodoTAD.codigo := id.nome || ‘proc near’ || CRLF ||CComposto.codigo || CRLF ||‘ret’ || CRLF ||id.nome || ‘endp’;MetodoTAD.codasm := id.nome || ‘proc near’ || CRLF ||‘push bp’|| CRLF ||‘mov bp, sp’|| CRLF ||‘sub sp, ’ || Símbolos.EscopoAtual.LarguraVariaveis || CRLF ||CComposto.codasm ||‘mov sp, bp’|| CRLF ||‘pop bp’ || CRLF ||‘ret’ || Símbolos.EscopoAtual.LarguraParametros + 2 || CRLF ||id.nome || ‘endp’;Símbolos.FecharEscopo;
';'
Esboço da tabela de símbolos para um programa em FURBOL
programa Retangulo;
classe TRetanguloesquerda, topo, direita, fundo: inteiro;
construtor constroi (esquerda, topo, direita, fundo: inteiro);inicio
imprime("Construindo um retangulo");esse.esquerda := esquerda;esse.topo := topo; esse.direita := direita;esse.fundo := fundo;
fim;
procedimento Area ;var
largura, altura, area: inteiro;inicio
imprime("Area do Retangulo:");largura := direita - esquerda;largura := direita - esquerda;altura := fundo - topo;area := largura * altura;imprime(area);
fim;
destrutor destroi ;inicio
imprime("Destruindo um retangulo");fim;
fim;
vargRet : TRetangulo;
iniciocriarobj(gRet, constroi(0, 0, 20, 20));gRet.Area;destruirobj(gRet, destroi);
fim.
Gerencia de memória dos TADs
• Registro de ativação dos métodos encontra-se na pilha.
• Atributos do objeto encontram-se na heap (memória alocada pelo comando criarobj ).
classe TRetanguloesquerda, topo, direita, fundo: inteiro;
construtor constroi (esquerda, topo, direita, fundo: inteiro);inicio
imprime("Construindo um retangulo");esse.esquerda := esquerda;esse.topo := topo; esse.direita := direita;esse.fundo := fundo;
Atributos –heap
Parâmetros – pilha
esse.fundo := fundo; fim;
procedimento Area ;var
largura, altura, area: inteiro;inicio
imprime("Area do Retangulo:");largura := direita - esquerda;altura := fundo - topo;area := largura * altura;imprime(area);
fim;
destrutor destroi ;inicio
imprime("Destruindo um retangulo");fim;
fim;
Variáveis locais – pilha
Criação de objetos
Furbol assembly
classe TPontox, y: inteiro;construtor constroi(x, y: inteiro);inicio
esse.x := x;esse.y := y;
fim;fim;
varponto1: TPonto;ponto2: TPonto;
ponto1 dw ?ponto2 dw ?
Furbol assembly
� Parâmetro do procedimento criarobj .� Tamanho da representação do TAD (atributos).
Furbol assembly
criarobj (ponto1);
(* chamada do construtor é opcional *)
1) push ax2) push 43) call criarobj4) mov ponto1,ax5) pop ax
Furbol assembly
criarobj(ponto2, constroi(gi, gj)); 01) push ax02) push 403) call criarobj04) mov ponto2,ax05) pop ax06) push gj07) push gi08) push ponto209) push bp10) call TPonto@constroi
TAD (atributos).
Parâmetro oculto esse
• Usado para acessar os atributos do objeto.
• Similar ao this do C++.
• É sempre o primeiro parâmetro do método, portanto sua posição na pilha é sempre a mesma.
Chamada de métodos
01)programa teste;02)03)classe TPonto04) x, y: inteiro;05) procedimento setXY(x, y: inteiro);06) inicio07) esse.x := x;08) esse.y := y;09) fim;
• Parâmetros empilhados da direita para a esquerda.
• Em seguida o conteúdo da variável do tipo objeto que está sendo referenciada também é empilhado (parâmetro oculto esse).
09) fim;10)fim;11)12)var13) ponto1: TPonto;14) gi, gj: inteiro;15)inicio16)(...)17) ponto1.setXY(gi, gj);18)(...)19)fim.
Furbol assembly
ponto1.setXY(gi, gj); 1) push gj2) push gi3) push ponto14) push bp5) call TPonto@setXY
Acesso aos atributos
• ES esse
• ES:[deslocamento_do_atributo]
Acesso aos atributos
classe TRetangulotopo, esquerda, fundo, direita : inteiro;
construtor constroi;inicio
topo := 7;esquerda := 77;fundo := 777;direita := 7777;
fim;fim;
Furbol assembly
� Deslocamento calculado pelo compilador consultado a tabela de simbolos do TAD.
� Descolamentos 0, 2, 4 e 6, respectivamente
construtor constroi;inicio
topo := 7;
esquerda := 77;
(...)fim;
01) TRetangulo@constroi proc near02) push bp03) mov bp, sp04) sub sp, 005)06) mov ax,707) mov es,word ptr [bp+6]08) mov word ptr es:[0],ax09)10) mov ax,7711) mov es,word ptr [bp+6]12) mov word ptr es:[2],ax13)14) (...)15) TRetangulo@constroi endp
Palavra reservada nulo
01)programa teste;02)03)classe TPonto04)(...)05)fim;06)07)var08) ponto: TPonto;09)
• Usada para indicar que uma referência a um TAD é inválida (não aponta para um endereço de memória válido).
• Para o compilador é equivalente ao valor 0.
09)10)inicio11) (...) 12) 13) destruirobj(ponto);14) ponto := nulo;15)16) (...)17)fim.
Furbol assembly
ponto := nulo; 1) mov ax,02) mov ponto,ax
Exclusão de objetos
Furbol assembly
destruirobj (ponto1);
( * chamada do destrutor é opcional *)
1) push ax2) mov ax,ponto13) push ax4) call destruirobj5) pop ax
Furbol assembly
destruirobj(ponto2, destroi); 1) push ponto22) push bp3) call TPonto@destroi4) push ax4) push ax5) mov ax,ponto26) push ax7) call destruirobj8) pop ax
Diagrama de casos de uso
Caso de uso compilar
COMPILAR
•Descrição: usuário solicita que o programa seja compilado.
•Ator principal : usuário.
•Cenário principal : compilara) através da interface o usuário escolhe a opção Compilar;b) o sistema compila o programa fonte;c) o sistema invoca o montador Turbo Assembler;d) o sistema invoca o ligador Turbo Link;e) o sistema exibe a mensagem “Programa compilado com sucesso”.
•Cenário deexceção: errodecompilação•Cenário deexceção: errodecompilação•Caso o programa fonte apresente algum erro o sistema encerra a compilação e apresenta qual é o problema para ousuário.
•Cenário de exceção: erro na geração de código de máquina•Caso ocorra algum erro durante a geração do código de máquina o sistema apresenta uma mensagem de erro para ousuário.
•Pré-condição: programa escrito em LP FURBOL.
•Pós-condição: programa em código de máquina criado.
Diagrama de classes
Diagrama de seqüências para caso de uso compilar
Implementação
• Código de Silva (2002) totalmente reaproveitado
• Interface não foi alterada
• Analisador Léxico – novas palavras reservadas relacionadas aos TADs� criarobj� destruirobj� classe� construtor� construtor� destrutor� esse� nulo
• Analisador Sintático – adaptado para seguir a nova especificação da LP
Implementação do não-terminal TAD
01)function TAnalisadorSintatico._TAD(var CodigoAsm : string): string;02)var03) TADName: string;04) MetodosTADCodigo,05) MetodosTADCodAsm: string;06) Simb: TSimbolo;07)begin08) if FLexico.Token = tkIdentificador then begin09)10) if FSimbolos.SimboloRedeclarado(FLexico.Lexe ma) then11) raise ESinErro.CreateFmt(strErrSinIdentDup licado, [FLexico.Linha, FLexico.Coluna, 12)FLexico. Lexema]);13)14) TADName := FLexico.Lexema;15)16) FLexico.ProximoToken;17)18) Simb := TSimbolo.Create(TADName, TipoSimbolo Classe);19) FSimbolos.Instalar(Simb);20) Simb.TabelaMembros := FSimbolos.AbrirEscopo( TADName);21)22) _AtributosTAD;22) _AtributosTAD;23)24) MetodosTADCodigo := _MetodosTAD(Simb, Metodo sTADCodAsm);25)26) if (FLexico.Token = tkReservada) and (FLexic o.Reservada = prFim) then begin27) FLexico.ProximoToken;28) end29) else30) raise ESinErro.CreateFmt(strErrSinTokenEsp erado, [FLexico.Linha, FLexico.Coluna, 31)strLexRes ervadas[prFim]]);32)33) FSimbolos.FecharEscopo;34)35) Result := MetodosTADCodigo;36) CodigoAsm := MetodosTADCodAsm;37)38) if (FLexico.Token = tkEspecial) and (FLexico .Lexema = ';') then begin39) FLexico.ProximoToken;40) end41) else42) raise ESinErro.CreateFmt(strErrSinTokenEsp erado, [FLexico.Linha, FLexico.Coluna, 43)';']);44) end45) else46) raise ESinErro.CreateFmt(strErrSinIdentEsper ado, [FLexico.Linha, FLexico.Coluna]);47)end;
Operacionalidade do sistema
Interface exibindo código intermediário
Interface exibindo código de montagem
Trabalho de Conclusão de Curso
Conclusões
Conclusões
• O objetivo do trabalho foi alcançado� Definir TADs� Quatro tipos de operações� Declarar referências para os TADs em outras unidades do programa � Criar instâncias destes TADs
• Outras contribuições� consistências e correção de bugs� implementação de um procedimento para imprimir inteiros
• As ferramentas mostraram-se adequadas
• Relevância do trabalho� Contribuir com um trabalho de pesquisa realizado pela FURB
Limitações
01)programa limitacoes_arrays;02)03)classe TPonto04) x, y: inteiro;05) procedimento setXY(x, y: inteiro);06) inicio07) esse.x := x;08) esse.y := y;09) fim;10)fim;11)12)classe TPilha13) fPilha: matriz; (* não compila *)14)fim;15)15)16)var17) gPontos: matriz[1..120]: TPonto;18)inicio19) criarobj(gPontos[1]); (* não compila *)20) gPontos[1].setXY(7, 120); (* não compila *)21) destruirobj(gPontos[1]); (* não compila *)22)fim.
Limitações
01)programa limitacao_simbolo_nao_definido;02)03)classe TRetangulo04) topo_esquerda, 05) fundo_direita: TPonto; (* não compila – Tponto ainda não foi definido *)06) 07) (...)08)fim; 09)10)classe TPonto11) x, y: inteiro;12) 13) construtor constroi(x, y: inteiro);14) inicio15) setXY(x, y); (* não compila – setXY ainda não foi definido *)16) fim;16) fim;17) 18) procedimento setXY(x, y: inteiro);19) inicio20) esse.x := x;21) esse.y := y;22) fim;24)fim; 23)24)inicio25) (...)26)fim.
Extensões
• Ampliar a LP para oferecer suporte a orientação a objetos.
• Criar uma biblioteca com funções de entrada e saída para vários dispositivos.
• Implementar a recuperação de erros de compilação.
• Otimizar o código gerado.• Otimizar o código gerado.
• Ampliar a LP para permitir a definição de funções.
• Gerar código para outras plataformas (microcontroladores, .NET, entre outros).
Trabalho de Conclusão de Curso
FIM