FACULDADE DE INFORMÁTICA DE PRESIDENTE PRUDENTE
SUPERIOR EM TECNOLOGIA EM DESENVOLVIMENTO WEB
DESENVOLVIMENTO DE UM COMPILADOR PARA
PSEUDOLINGUAGEM E FLUXOGRAMA
RODRIGO CESAR DE OLIVEIRA
Presidente Prudente – SP
2008
FACULDADE DE INFORMÁTICA DE PRESIDENTE PRUDENTE
SUPERIOR EM TECNOLOGIA EM DESENVOLVIMENTO WEB
DESENVOLVIMENTO DE UM COMPILADOR PARA
PSEUDOLINGUAGEM E FLUXOGRAMA
RODRIGO CESAR DE OLIVEIRA
Trabalho de Conclusão de Curso,
apresentado
à
Faculdade
de
Informática de Presidente Prudente,
Curso Superior em Tecnologia em
desenvolvimento Web, Universidade do
Oeste Paulista, como parte dos
requisitos para a sua conclusão.
Área:
Análise de Algoritmos e Complexidade
de Computação
Orientadores:
MSc. Francisco Assis da Silva
MSc. Ana Paula D. Parizoto Fabrin
MSc. Leandro Luiz de Almeida
Presidente Prudente – SP
2008
004
Oliveira, Rodrigo Cesar.
Desenvolvimento de um compilador para
Pseudolinguagem e Fluxograma / Rodrigo César
de Oliveira. – Presidente Prudente - SP:
UNOESTE, 2008.
58f.: il.
Trabalho de Conclusão de Curso (Graduação
em Superior em Tecnologia em desenvolvimento
Web) – Universidade do Oeste Paulista –
UNOESTE: Presidente Prudente – SP, 2008.
1. Construção de Algoritmos, 2.
Pseudolinguagem, 3. Fluxograma, I. Autor. II.
Título.
DEDICATÓRIA
Dedico este trabalho a todas as pessoas, que por intermédio de
Deus, puderam me ajudar nas horas difíceis e mostraram-me o caminho certo a
seguir, mesmo nas horas de dificuldades e incertezas, ao longo do
desenvolvimento deste trabalho.
AGRADECIMENTOS
Primeiramente a DEUS, que me permitiu conquistar mais essa
vitória, dando-me paciência, sabedoria e discernimento em todos os momentos
de dificuldade e desânimo durante a realização deste trabalho.
A todos os meus professores, que na rigidez de seus
ensinamentos fizeram aprimorar meus conhecimentos, em especial aos meus
orientadores, Francisco Assis da Silva, Ana Paula D. Parizoto Fabrin e Leandro
Luiz de Almeida, pelo incentivo, apoio, estímulo e amizade durante este longo
período de orientação para que eu pudesse concluir esta pesquisa.
Enfim,
a
todos
os
meus
companheiros
de
companheirismo e os muitos momentos de alegria compartilhados.
turma,
pelo
“A mente que se abre a uma nova idéia jamais voltará ao seu tamanho original.”
Albert Einstein
RESUMO
DESENVOLVIMENTO DE UM COMPILADOR PARA PSEUDOLINGUAGEM E
FLUXOGRAMA
Atualmente no curso Superior de Tecnologia em desenvolvimento Web o
ensino de algoritmo é feito de modo tradicional, baseado no ensinamento de
cada assunto e treino com exercícios. Pensa-se que a adição de novas técnicas
e o uso de ferramentas possam melhorar o aprendizado dos alunos. Portanto, o
objetivo deste trabalho é desenvolver uma ferramenta acadêmica que permite a
visualização de algoritmos por meio de compilação e tradução. A ferramenta
terá dois ambientes, um para ser digitado o portugol (pseudolinguagem) e outro
para ser desenhado o fluxograma. Após ser digitado ou desenhado, a
ferramenta irá compilar e traduzir o código para a linguagem JavaScript. O
compilador RAF, assim chamado, será usado pelos alunos para auxiliar a
compreensão dos algoritmos e desenvolver lógica de programação.
Palavras-Chave: Fluxograma, Pseudolinguagem, Compilador e Construção de
Algoritmo
ABSTRACT
DEVELOPING A COMPILER FOR PSEUDOLINGUAGE AND FLOW
Currently in the course of High Technology in Web development
algorithm of the teaching is done in the traditional way, based on the studying of
each subject and with training exercises. It is believed that the addition of new
techniques and the use of tools can improve the learning of students. Therefore,
the objective of this work is to develop an academic tool that allows the viewing
of algorithms through compilation and translation. The tool has two
environments, one to be spelled the pseudolinguage and another designed to be
the flow. After being typed or designed, the tool will compile and translate the
code for the JavaScript language. The compiler RAF will be used by pupils to
help develop understanding of algorithms and logic programming.
Keywords: Flow, Pseudolinguage, Compiler and Construction of Algorithm.
LISTA DE FIGURAS
Figura 1 – Ambiente do G-Portugol................................................................... 13
Figura 2 – Ambiente do Portugol IDE................................................................ 14
Figura 3 – Ambiente do CIFluxProg. ................................................................. 15
Figura 4 – Execução de um programa fonte. .................................................... 17
Figura 5 – Estrutura de um Compilador. ........................................................... 17
Figura 6 – Analisador Léxico. ............................................................................ 18
Figura 7 – Estrutura de uma árvore................................................................... 20
Figura 8 – Análise recursiva com retrocesso..................................................... 21
Figura 9 – Exemplo de fatoração. ..................................................................... 22
Figura 10 – Análise Redutiva. ........................................................................... 24
Figura 11 – Redução da sentença abbcde........................................................ 24
Figura 12 – Classe ExecutaPrograma............................................................... 36
Figura 13 – Classe Main ................................................................................... 36
Figura 14 – Classe Principal.............................................................................. 39
Figura 15 – Classe RedoAction......................................................................... 40
Figura 16 – Classe UndoAction......................................................................... 40
Figura 17 – Classe CodigoGerado. ................................................................... 41
Figura 18 – Funções adicionais........................................................................ 42
Figura 19 – Classe Token. ................................................................................ 44
Figura 20 – Classe Lexico. ................................................................................ 45
Figura 21 – Classe Sintatico.............................................................................. 52
Figura 22 – Classe Forma. ................................................................................ 55
Figura 23 – Ligações usadas no desenho de um fluxograma. .......................... 56
Figura 24 – Classe Ligacao............................................................................... 56
LISTA DE TABELAS
Tabela 1 – Tabela de Tokens, Padrões e Lexemas. ......................................... 19
Tabela 2 – Operadores aritméticos ................................................................... 28
Tabela 3 – Operadores Lógicos ........................................................................ 29
SUMÁRIO
1 INTRODUÇÃO.............................................................................................. 12
1.1 Trabalhos Correlatos................................................................................. 13
1.1.1 G-Portugol .............................................................................................. 13
1.1.2 Portugol IDE ........................................................................................... 14
1.1.3 CIFluxProg.............................................................................................. 14
1.2 Estrutura da Monografia............................................................................ 15
2 COMPILADORES ......................................................................................... 16
2.1 Analisador léxico ou Analise léxica ........................................................... 18
2.2 Tokens, padrões, lexemas ........................................................................ 18
2.3 Análise Sintática........................................................................................ 19
2.4 Tipo de Analisadores sintáticos................................................................. 20
2.5 Top-Down (Análise Descendente)............................................................. 20
2.5.1 Recursivo com retrocesso (backtracking)............................................... 21
2.5.2 Recursivo preditivo ................................................................................. 21
2.5.3 Tabular preditivo..................................................................................... 22
2.6 Bottom-Up (Análise redutiva) .................................................................... 23
2.7 Análise Semântica..................................................................................... 24
2.8 Geração de código .................................................................................... 25
2.8.1 Otimizador de Código............................................................................. 25
2.9 Especificação da BNF ............................................................................... 26
3 PORTUGUÊS ESTRUTURADO ................................................................... 27
3.2
3.3
3.4
3.5
3.6
3.7
3.8
3.9
Variável ..................................................................................................... 27
Atribuição .................................................................................................. 28
Operadores ............................................................................................... 28
Comando de Entrada e Saída ................................................................... 29
Corpo do algoritmo.................................................................................... 29
Estrutura de seleção ................................................................................. 29
Estrutura de repetição ............................................................................... 30
Exemplos de Algoritmos............................................................................ 31
4 IMPLEMENTAÇÃO (CLASSES) ................................................................... 35
4.1 Modelagem das classes em UML ............................................................. 35
4.2 Classe Executa programa ......................................................................... 36
4.3 Classe Main............................................................................................... 36
4.4 Classe Principal......................................................................................... 37
4.4.1 Classe RedoAction ................................................................................. 39
4.4.2 Classe UndoAction ................................................................................. 40
4.5 Classe CodigoGerado ............................................................................... 41
4.6 Classe Token ............................................................................................ 42
4.7 Classe Lexico ............................................................................................ 44
4.8 Classe Sintatico......................................................................................... 45
4.9 Classe Forma ............................................................................................ 53
4.10 Classe Ligacao.......................................................................................... 55
5 CONCLUSÕES............................................................................................. 57
REFERÊNCIAS BIBLIOGRÁFICAS .................................................................. 58
12
1 INTRODUÇÃO
Para tornar problemas do mundo mais fácies e rápidos de se
resolver, surgem linguagens e softwares na área da informática que auxiliam o
desenvolvimento de sistema para soluções de problemas, como: Sistemas
Operacionais, tradutores e aplicativos.
Os softwares são formados por um conjunto de código
padronizado conhecido como linguagem de máquina. Geralmente essa
linguagem não é manipulada pelo homem por causa da sua complexidade, mas
manipulada e gerada por tradutores.
A linguagem de máquina é muita complicada aos olhos humanos,
por isso foram criadas linguagens mais próximas do mundo real, conhecidas
como linguagens de programação ou linguagens de alto nível.
Um compilador é um programa que, a partir de um código escrito
em uma linguagem, cria um programa semanticamente equivalente, porém
escrito em outra linguagem.
O objetivo deste projeto é desenvolver uma ferramenta acadêmica
que auxilie na aprendizagem dos alunos de Tecnologia em Desenvolvimento
web. A ferramenta possui dois ambientes, um para a escrita do portugol e outro
para desenvolvimento de algoritmo na forma fluxograma. Ela possibilita a
exibição dos erros cometidos e a tradução para a linguagem JavaScript,
permitindo uma melhor visualização do resultado, sendo mais simples para os
alunos interagir e entender os processos de escrita e desenvolvimento de
soluções de problemas computacionais.
13
1.1 Trabalhos Correlatos
Nesta seção, resumem-se os resultados da investigação a
respeito da a área pesquisada, onde foi possível identificar trabalhos existentes,
relacionados a este. Os trabalhos são: G-Portugol, Portugol IDE e ClFluxProg.
1.1.1 G-Portugol
G-Portugol (2004) é um dialeto da linguagem portugol (ou
português estruturado), muito usado para descrever algoritmos de forma livre e
espontânea, em português. Em geral, livros dedicados ao ensino de algoritmos,
lógica e estruturas de dados incorporam alguma forma dessa linguagem.
A proposta do projeto é oferecer uma implementação para a
linguagem G-Portugol, fornecendo ferramentas que ofereçam recursos de
edição, compilação e execução de algoritmos, de forma a favorecer estudantes
que dão os primeiros passos no aprendizado de desenvolvimento de softwares,
bem como professores que ensinam disciplinas relacionadas. A Figura 1
apresenta o ambiente do G-Portugol.
Figura 1 – Ambiente do G-Portugol.
14
1.1.2 Portugol IDE
Portugol IDE (2008) é um simulador de linguagem algorítmica
desenvolvido para apoio às aulas de Introdução à Programação dos Cursos de
Engenharia da Escola Superior de Tecnologia de. A Figura 2 apresenta o
ambiente do Portugol IDE.
Figura 2 – Ambiente do Portugol IDE.
1.1.3 CIFluxProg
O CIFluxProg (Santiago, 2004) é uma ferramenta de apoio para as
disciplinas iniciais da área de programação, como por exemplo, as disciplinas
de algoritmos. Desenvolveu-se esta ferramenta que permite aos alunos
implementarem e testarem suas soluções lógicas de programação tanto em
Portugol como em Fluxograma. Contando com o auxílio do teste de mesa e
com a interpretação da solução, inclusos na ferramenta, a verificação de
integridade das soluções pode ser verificada. Esta ferramenta flexibiliza o
processo de treinamento dos alunos, uma vez que estes podem verificar o
funcionamento das suas soluções na prática, visualizando em detalhes os
passos e os resultados da sua solução. A Figura 3 apresenta o ambiente do
CIFluxProg.
15
Figura 3 – Ambiente do CIFluxProg.
1.2 Estrutura desta Monografia
Após o capítulo introdutório, a presente monografia está
organizada conforme a estrutura citada a seguir.
No
capítulo
2,
são
tratados
os
conceitos
referentes
a
Compiladores, Análises e Técnicas.
O capítulo 3 aborda assuntos relacionados a pseudolinguagem.
O capítulo 4 trata dos conceitos relacionados à implementação
das classes usada no projeto.
No capítulo 5, são abordadas as conclusões do projeto.
16
2 COMPILADORES
Neste Capítulo é abordada a evolução das linguagens de
programação e compiladores e suas funcionalidades.
A primeira linguagem de programação para computadores foi
provavelmente Plankalkül, criada por Konrad Zuse na Alemanha Nazista, mas
não teve nenhum impacto no futuro das linguagens de programação. A primeira
linguagem de programação de alto nível amplamente usada foi Fortran, criada
em 1954 (AHO, 1986).
Ao longo dos anos foram propostas muitas linguagens de
programação, algumas obtiveram sucesso e são conhecidas, como Basic, C,
C++, Cobol, Fortran, Java e Pascal. Outras tiveram grande influência
acadêmica, mas são conhecidas apenas por alguns ou por sua importância
histórica.
Todo software que converta ou traduz uma linguagem de
programação específica em uma linguagem interpretável pela máquina é
chamada de tradutor.
Definido em Aho (1995) como:
Um compilador é um programa que lê um programa escrito em uma
linguagem – a linguagem de origem – e o traduz em um programa
equivalente em outra linguagem – a linguagem destino. Como uma
importante parte no processo de tradução, o compilador reporta ao
seu usuário a presença de erros no programa origem.
Um Compilador é um tradutor que a partir de uma linguagem
escrita, traduz para outra linguagem, a linguagem objeto, que será interpretada
pela máquina. O intervalo de tempo no qual ocorre a conversão ou tradução de
um programa fonte para um programa objeto é chamado de tempo de
compilação. O programa objeto é executado no intervalo de tempo chamado de
tempo de execução. Os dois processos acontecem em tempos distintos. (AHO,
1986).
A Figura 4 ilustra a execução de um programa fonte.
17
Figura 4 – Execução de um programa fonte.
O programa fonte pode ser escrito em qualquer linguagem de alto
nível, por exemplo, Pascal, C++, Java, e o programa objeto em qualquer outra
linguagem de alto nível ou linguagem de máquina.
Um compilador pode ter várias partes como: analisador léxico,
analisador sintático, analisador semântico, otimizador e gerador de código. A
Figura 5 apresenta a estrutura de um compilador ilustrando as suas partes.
Figura 5 – Estrutura de um Compilador.
Fonte: Compiladores: princípios, técnicas e ferramentas (AHO, 1986).
18
2.1 Analisador léxico ou Análise léxica
Análise léxica é a primeira fase de um compilador, nela é
analisada a entrada de caracteres que produz uma seqüência de símbolos
chamados “símbolos léxicos” (lexical tokens), ou somente "símbolos" (tokens).
Os tokens são separados de duas maneiras: quando possui algum
significado para linguagem ou quando não faz parte da linguagem. Os tokens
que possuem algum significado geralmente são palavras reservadas,
identificadores, delimitadores entre outros. Os tokens que não fazem parte da
linguagem geralmente são espaços em brancos, tabulações, caracteres de
avanço de linha e comentários. Todos os tokens devem ser armazenados em
uma tabela interna, tanto para indicar erros léxicos como para servir de entrada
para o analisador sintático. A Figura 6 apresenta o funcionamento do analisador
léxico.
Figura 6 – Analisador Léxico.
Fonte: Compiladores: princípios, técnicas e ferramentas (AHO, 1986).
As
linhas
do
programa
fonte
devem
ser
controladas
e
armazenadas durante a varredura da análise léxica, pois os erros de análises
sintáticas (parse) e/ou léxicas podem estar associados ao programa fonte.
2.2 Tokens, padrões, lexemas
Não poderia deixar de ser abordados termos usados na análise
léxica, como tokens, padrões e lexemas.
19
Tokens são símbolos usados na gramática de uma linguagem. Na
maioria das linguagens de programação, as seguintes construções são tratadas
como tokens: palavras-chave, operadores, identificadores, constantes, cadeias
literais (strings) e símbolos de pontuação como parênteses, vírgulas e pontos.
Um padrão (pattern) é uma regra que descreve um conjunto de
lexemas que podem representar um token na linguagem. Estas regras
normalmente são descritas na forma de expressões regulares.
Lexema é o valor do token, muitas vezes aparecendo como um
atributo para as fases seguintes de compilação. Enquanto o analisador léxico
procura tokens, na geração do código precisa dos lexemas para produzir
significado. A Tabela 1 apresenta o exemplo de tokens, padrões e lexmas.
Tabela 1 – Tabela de Tokens, Padrões e Lexemas.
Token
Lexema
Padrão
Numero
3.1415
([+,-])([0-9])*(.([0-9])+)
O reconhecimento de tokens é realizado a partir de um documento
do tipo BNF (Backus-Naur-Form).
2.3 Análise Sintática
Segundo Aho (1995), o analisador sintático (parser) obtém uma
seqüência de tokens do analisador léxico e verifica se esta seqüência pode ser
gerada pela gramática da linguagem.
Segundo Price (2000), o analisador sintático identifica seqüências
de símbolos que constituem estruturas sintáticas (por exemplo, expressões,
comandos), por meio de uma varredura ou parsing da representação interna
(cadeia de tokens) do programa fonte. O analisador sintático produz uma
estrutura de árvore, chamado árvore de derivação, que exibe a estrutura
sintática do texto fonte, resultante da aplicação das regras gramaticais da
linguagem.
A árvore é composta por um elemento principal chamado raiz, que
possui ligações para outros elementos, que são denominados de galhos ou
filhos. Estes galhos levam a outros elementos que também possuem outros
20
galhos. O elemento que não possui galhos é conhecido como folha ou nó
terminal. A Figura 7 apresenta a estrutura de uma árvore
Figura 7 – Estrutura de uma árvore.
Todas as linguagens de programação possuem regras que
descrevem a estrutura sintática de programas. A sintaxe de uma linguagem de
programação pode ser descrita por meio de uma gramática livre de contexto ou
notação BNF.
2.4 Tipo de Analisadores sintáticos
A tarefa do analisador sintático é determinar se uma entrada de
dados pode ser derivada de um símbolo inicial com as regras de uma gramática
formal. Isso pode ser feito de duas maneiras:
• Top-Down ou descendente: analisa a gramática desde seu
início até o seu fim, construindo sua árvore de derivação a partir
do símbolo inicial da gramática, fazendo com que ela cresça até
atingir suas folhas;
• Bottom-Up ou redutiva: analisa a gramática do fim para o seu
começo, a partir dos tokens de derivação do código-fonte,
constrói a árvore até o símbolo inicial da gramática.
2.5 Top-Down (Análise Descendente)
O Analisador sintático de cima para baixo (Top-Down) tenta
deduzir as produções da gramática a partir do nó raíz. Ele lê a entrada de texto
da esquerda para a direita, e produz uma derivação mais à esquerda. Segundo
Aho (1986), a análise Top-Down pode ainda ser vista numa tentativa de se
21
construir uma árvore gramatical, para a cadeia de entrada, a partir da raiz,
criando nós da árvore gramatical em pré-ordem.
Existem três tipos de analisadores sintáticos descendentes:
• Recursivo com retrocesso (backtracking);
• Recursivo preditivo;
• Tabular preditivo.
Segundo Thosom (2004) um analisador sintático recursivo
preditivo tenta prever a construção seguinte na cadeia de entrada com base em
uma ou mais marcas de verificação à frente. Já um analisador sintático
recursivo com retrocesso testa diferentes possibilidades de análise sintática de
entrada, retrocedendo se alguma possibilidade falhar.
2.5.1 Recursivo com retrocesso (backtracking)
Análise recursiva com retrocesso pode ser vista como uma
tentativa de se encontrar uma derivação mais à esquerda para uma cadeia de
entrada. Equivalentemente, pode ser vista como uma tentativa de construir uma
árvore gramatical em pré-ordem. Caso o token não define distintamente a
produção a ser usada, então todas as alternativas vão ser tentadas até que se
obtenha sucesso ou falhe. A Figura 8 apresenta um exemplo da análise
recursiva com retrocesso
A aB | aC | aX
Figura 8 – Análise recursiva com retrocesso.
2.5.2 Recursivo preditivo
Segundo
Aho
(1986)
em
muitos
casos,
escrevendo-se
cuidadosamente uma gramática, eliminado-se recursão à esquerda e fatorandose à esquerda a gramática, será obtido uma nova gramática processável por
22
um analisador sintático de descendência recursiva que não necessite de
retrocesso, isto é, um analisador sintático preditivo.
Quando é construído um analisador sintático preditivo, é preciso
conhecer o símbolo corrente na entrada a e o não-terminal A a ser expandido,
qual das alternativas da produção A a1 | a2 ...| an é a única que deriva uma
cadeia começando por a. Ou seja, a alternativa adequada é detectar apenas
primeiro símbolo da mesma deriva e assim partir para os outros processo de
fatoração. As construções do controle são feita do seguinte modo de fatoração
da Figura 9:
A aY
Y 1| 2 | ... |n
Figura 9 – Exemplo de fatoração.
Com o processo de fatoração o compilador sempre caminhará
adiante e com menos tempo de execução.
2.5.3 Tabular preditivo
Na análise Preditiva Tabular é possível construir analisadores
preditivos não recursivos que utilizam uma pilha explícita ao invés de chamadas
recursivas (pilha implícita). Esse tipo de analisador implementa um autômato de
pilha controlado por uma tabela de análise. O princípio do reconhecimento
preditivo é a determinação da produção a ser aplicado, cujo lado direito irá
substituir o símbolo não-terminal que se encontra no topo da pilha. O analisador
busca a produção a ser aplicada na tabela de análise, levando em conta o nãoterminal no topo da pilha e o token sob o cabeçote de leitura. O analisador
preditivo compreende uma fita de entrada, uma pilha e uma tabela de análise. A
fita de entrada contém a sentença a ser analisada seguida de $, símbolo que
marca o fim da sentença. A tabela de análise é uma matriz M com n linhas e t+1
colunas, onde n é o número de símbolos não-terminais e t, o número de
terminais – a coluna extra corresponde ao $.
23
Segundo Price (2000), a implementação de um analisador
preditivo tabular tem como maior dificuldade a construção da tabela de análise.
Para construir essa tabela, é necessário computar duas funções associadas à
gramática: as funções FIRST e FOLLOW. Para computar FIRST(x) para um
símbolo x da gramática, aplicam-se regras até que não se possam adicionar
mais terminais ou ε ao conjunto em questão. As regras são:
1. Se a é terminal, então FIRST(a) = {a};
2. Se x → ε é uma produção, então adicione ε a FIRST(x);
3. Se x → y1y2...yk e, para algum i, todos y1y2...yi-1 derivam ε,
então FIRST(yi) está em FIRST(x). Se todo yj {j=1,2,...,k} deriva
ε, então ε está em FIRST(x).
Para computar FOLLOW(x), aplicam-se regras até que não se
possa adicionar mais símbolos ao conjunto em questão. As regras são:
1. Se S é símbolo inicial da gramática e $ é o marcador de fim da
sentença, então $ está em FOLLOW(S);
2. Se existe uma produção do tipo A → αXβ, então todos os
terminais de FIRST(β) faz parte de FOLLOW(X);
3. Se existe produção do tipo A → αX ou A → αXβ sendo que
β→*ε, então todos os terminais que estiverem em FOLLOW(A)
fazem parte de FOLLOW(x).
2.6 Bottom-Up (Análise redutiva)
Segundo Aho (1986) análise redutiva também conhecida como
análise de empilhar e reduzir, tenta construir uma árvore gramatical para uma
cadeia de entrada começando pelas folhas (o fundo) e trabalhando árvore
acima em direção a raiz (o topo). Pode-se pensar neste processo como o de
“reduzir” uma cadeia w ao símbolo de partida de uma gramática. A cada passo
de redução, uma sub-cadeia particular, que reconheça o lado direito de uma
produção, é substituída pelo símbolo à esquerda daquela produção e, se a subcadeia tiver sido escolhida corretamente a cada passo, uma derivação mais à
direita terá sido rastreada na ordem inversa. A Figura 10 apresenta a análise
redutiva.
24
S aABe
A Abc | b
Bd.
Figura 10 – Análise Redutiva.
A sentença abbcde pode ser reduzida a S mostrado na Figura 11.
abbcde
aAbcde
aAde
aABe
S
Figura 11 – Redução da sentença abbcde.
2.7 Análise Semântica
A análise semântica é utilizada para verificar cada comando, erros
semânticos no programa fonte e capturar as informações de tipo para a fase
subseqüente de geração de código.
As tarefas básicas desempenhadas durante a análise semântica
incluem a verificação de tipos, a verificação do fluxo de controle e a verificação
da unicidade da declaração de variáveis. Dependendo da linguagem de
programação, outros tipos de verificações podem ser necessários. Exemplo,
“Todas variáveis foram declaradas?”.
Segundo Aho (1995), a fase de análise semântica verifica o código
fonte para detectar erros de semântica e ao mesmo tempo coleta informações
de tipo para a geração de código. Usando a estrutura hierárquica gerada pela
fase de análise sintática, operadores e operandos de expressões e declarações
são identificados. Um importante componente da análise semântica é a
verificação de tipos. Nesta fase o compilador verifica se cada operador tem os
operandos permitidos pela especificação da linguagem. Um exemplo é a
utilização de números para índices de vetores. A maioria das linguagens
25
permite o uso apenas de números inteiros, sendo números reais tratados como
erro neste caso.
2.8 Geração de código
Na fase de geração de código a representação intermediária do
código é traduzida para a linguagem de máquina da máquina alvo, ou para a
linguagem destino. Entre as tarefas do gerador de código estão: gerenciamento
de memória, seleção de instruções e alocação de registradores entre outras.
2.8.1 Otimizador de Código
Segundo Aho (1995), compiladores devem produzir códigos tão
bons quanto se fossem escritos à mão. A realidade é que este objetivo só é
alcançado em poucos casos e com dificuldade. Entretanto, o código produzido
por compiladores pode quase sempre rodar mais rápido ou ocupar menos
espaço, ou ainda ambos. Esta melhoria é alcançada por transformações que
tradicionalmente são chamadas de “otimizações”, sendo o termo otimização
não muito preciso, já que não há garantias de que o código resultante é o
melhor possível.
26
2.9 Especificação da BNF
<comeco> programa nome_prog ; <bloco princ>.
<decl> variaveis <lista_id> | ξ
<lista_id> <tipox> : id <varios_id>; <contlista_id>
<tipox> id | <tipo_bas>
<contlista_id> <lista_id> | ξ
<varios_id> ξ | , id <varios_id>
<tipo_bas> inteiro | real | caracter | lógico
<tipo> tipo <tipo_cons> | ξ
<tipo_cons> id = vetor(num_int) de <tipo_bas> | matriz(num_int, num_int) de
<tipo_bas><tipo_cons>| ξ
<bloco_princ> inicio <tipo><decl><varios_cmds> fim
<varios_cmds> <cmd> ; <varios_cmds> | ξ
<cmd> <cmd_if> | <cmd_enquanto> | <cmd_para> | <cmd_faça> |
<cmd_atrib> | <cmd_ler> | <cmd_escrever> | <cmd_caso>
<cmd_enquanto>enquanto <exp_logica> faca <bloco>
<cmd_para> para id de <val3> ate <val3> passo <val3> faca <bloco>
<cmd_faça> faca <bloco> enquanto <exp_logica>
<bloco> inicio <varios_cmds> fim | <cmd>
<cmd_if> se (<exp_logica>) entao <bloco> <varios_if>
<varios_if> senao <bloco> | ξ
<cmd_atrib> id := <exp_arit> | <val_logico>
<exp_arit>  (<exp_arit>)<y> | <func_mat><y> | <val><y>
<y> <oper><exp_arit> | ξ
<func_mat> pot(<val>,<val>) | rad(<val>)
<val> id | num_int | num_real | <val5> | (<val>)
<val2> num_it | num_real | ID
<val3> id | num_it
<oper> + | - | / | * | mod | div
<cmd_ler> leia( id <váriosleia_id>)
<váriosleia_id> ξ | id <váriosleia_id>
<cmd_escrever> escreva (<varios_escrever>)
<varios_escrever> literal <varios_escrever2> | <exp_arit> <varios_escrever2>
<varios_escrever2> , <varios_escrever> | ξ
<exp_logica> <exp_arit> <operador_relacional> <exp_arit> <cont_exp> |
nao <exp_nao> <cont_exp> | <val5> <operx> <val5> <cont_exp>
<operx> = | <>
<val5> <val_logico> | literal
<cont_exp> <oper_logico> <exp_logica>| ξ
<exp_nao> (<exp_logica>) | id
<oper_logico> e | ou
<oper_relacional> > | < | >= | <= | = | <>
<val4> <val3> | literal | caracter | <val_logico>
<cmd_escolha> escolha id <bloco_escolha>
<bloco_escolha> inicio <cmd_casos> fim
<val_logico> verdadeiro | falso
<cmd_casos> caso <val4> <val_caso> : <bloco>;<casosw> | ξ
<casosw> <cmd_casos> | <cmd_casocontrario> | ξ
<cmd_casocontrario> casocontrario : <bloco>
<val_caso> ..<val4> | , <val_caso2> | ξ
<val_caso2> , <val4> <val_caso2> | ξ
27
3 PORTUGUÊS ESTRUTURADO
O Portugol, português estruturado ou pseudolinguagem é uma
representação didática em "português" do algoritmo. É usada em cursos de
informática, de forma a facilitar o aprendizado da programação a partir da
familiarização dos comandos mais usados nas linguagens de programação.
3.1 Tipos de dados
Os tipos de dados são:
• Inteiro: todo e qualquer informação numérica que pertence ao
conjunto dos números inteiros relativos (negativo, nulo ou
positivo);
• Real: todo e qualquer informação numérica que pertença ao
conjunto dos números reais (negativo, nulo ou positivo);
• Caracter: Todo e qualquer informação composta por um
conjunto de caracter alfanumérico [0..9] e/ou especiais (#, $,
%..);
• Lógico: Todo e qualquer informação que pode assumir duas
situações (Verdadeiro ou Falso);
• Matriz e Vetor: Uma matriz é uma coleção de variáveis de
mesmo tipo, acessíveis com um único nome e armazenados
contiguamente na memória. Os Vetores são matrizes de 1 só
dimensão.
3.2 Variável
Uma variável é um espaço reservado na memória do computador
para armazenar um tipo de dado determinado. Variáveis devem receber nomes
para poderem ser referenciadas e modificadas quando necessário. Fica
estabelecido o tamanho máximo de 32 caracteres para o tamanho do maior
nome válido.
Valores válidos: Alpha, x, B5, nota, media, xpto
Valores inválidos: 5x, a(19), C:D, nota/2
28
Exemplo de declaração de variáveis:
variaveis
inteiro: v1, v2, v3, s;
real: n;
3.3 Atribuição
A atribuição de valores é representada pelo símbolo :=. Só é
permitida a atribuição de um valor por vez.
Valores não aceitos: a:=b:=c:=0
Uma atribuição válida possui um identificador válido à esquerda e
uma expressão do mesmo tipo do identificador a direita.
Exemplos:
variaveis
real: nota1, nota2;
nota1 := 5.5;
nota2 := 9.5;
3.4 Operadores
A Tabela 2 mostra os operadores aritméticos utilizados na
linguagem portugol.
Tabela 2 – Operadores aritméticos
Operação
Adição
Subtração
Divisão
Multiplicação
Divisão inteira
Resto da divisão
Símbolo
+
/
*
div
mod
A Tabela3 mostra operadores Lógicos utilizados na
linguagem portugol.
29
Tabela 3 – Operadores Lógicos
3.5 Comando de Entrada e Saída
Os comandos que permitem a entrada manual via teclado e
exibição de informações são:
• leia: Comando de entrada que permite a leitura de Variáveis
de Entrada. Exemplo: leia(a);
• escreva: Comando de saída que exibe uma informação na tela
do monitor. Exemplo: escreva(a);
3.6 Corpo do algoritmo
Exemplo
da
estrutura
de
um
algoritmo
escrito
em
pseudolinguagem.
programa media;
inicio
variaveis
<<variaveis>>;
<<comandos>>;
fim.
3.7 Estrutura de seleção
Executa uma seqüência de comandos de acordo com o resultado
de um teste. A estrutura de decisão pode ser Simples ou Composta, baseada
em um resultado lógico.
Seleção Simples:
se <<condicao>> entao
<<comando1>>;
30
Seleção Composta:
se <<condicao>> entao
<<comando1>>
senao
<<comando1>>;
Composta com bloco (inicio – fim):
se <<condicao>> entao
inicio
<<comando1>>;
<<comandoN>>;
fim
senao inicio
<<comando1>>;
<<comandoN>>;
fim;
3.8 Estrutura de repetição
Quando houver uma seqüência de comandos que deverá ser
executada repetidas vezes, tem-se uma estrutura de repetição.
A estrutura de repetição, assim como a de seleção, envolve
sempre a avaliação de uma condição. Existem três formas de estruturas de
repetição: com teste no início (enquanto-faca), com teste no final (facaenquanto) e com variável de controle (para-ate-faca).
Repetição com teste no início:
enquanto (<<condicao>>) faca
inicio
<<comandos>>
fim;
Repetição com variável de controle:
para <<variavel>> de <<valor1>> ate <<valor2>> passo <<valor3>> faca
inicio
<<comandos>>
fim;
Repetição com teste no final:
faça
inicio
<<comandos>>
fim
enquanto (<<condicao>>);
31
3.9 Exemplos de Algoritmos
Nesta sessão são apresentados nove exemplos de algoritmos
escritos em pseudolinguagem.
O primeiro exemplo utiliza uma estrutura de seleção composta
com bloco (inicio-fim):
programa media;
inicio
variaveis
inteiro: v1, v2, v3, v4, m;
escreva(“este é um algoritmo que calcula a média e verifica se o
aluno foi ou não aprovado”);
escreva(“coloque as 4 notas”);
leia(v1, v2, v3, v4);
m:= (v1 + v2 + v3 + v4)/4;
se (m>6) entao
inicio
escreva(“aprovado”);
fim
senao
inicio
escreva(“reprovado”);
fim;
fim.
O segundo exemplo utiliza uma estrutura de seleção simples:
programa soma;
inicio
variaveis
inteiro: v1, v2, v3, s;
escreva(“este é um algoritmo que calculara a soma e verifica se é
maior que 30”);
escreva(“coloque 3 valores”);
leia(v1, v2, v3);
s:= v1 + v2 + v3;
se (s>30) entao
escreva(s, “é maior que 30”);
fim.
32
O terceiro exemplo utiliza uma estrutura de seleção composta:
programa entre20e90;
inicio
variaveis
real: n;
escreva(“digite um número”);
leia(n);
se (n>20 e n<90) entao
escreva(“número entre 20 e 90”);
senao
escreva(“número não está entre 20 e 90”);
fim.
O quarto exemplo utiliza uma estrutura de seleção:
programa escolhacaso;
inicio
variaveis
real: preco;
inteiro: codigo;
escreva(“informe o preço e o código”);
leia(preco);
leia(codigo);
escolha codigo
inicio
caso 1 : escreva(preco, “- sul”);
caso 2 : escreva(preco, “- norte”);
caso 3 : escreva(preco, “- leste”);
caso 4 : escreva(preco, “- oeste”);
caso 5,6 : escreva(preco, “- nordeste”);
caso 7,8,9 : escreva(preco, “- sudeste”);
caso 10..20 : escreva(preco, “- centro oeste”);
casocontrario : escreva(preco, “- importado”);
fim;
fim.
O quinto exemplo utiliza uma estrutura de decisão com teste no
início:
programa enquantofaca;
inicio
variaveis
inteiro: n, i;
escreva(“digite um número”);
i := 1;
enquanto (i<=n) faca
inicio
escreva(i);
i = i + 1;
fim;
fim.
33
O sexto exemplo utiliza uma estrutura de repetição com variável
de controle:
programa tabuada;
inicio
variaveis
inteiro: n, nn, cont;
escreva(“digite o número”);
leia(n);
para cont de 1 ate 10 passo 1 faca
inicio
nn := cont * n;
escreva(n, “x”, cont, “=”, nn);
fim;
fim.
O sétimo exemplo utiliza a função pot:
programa potenciacao;
inicio
variaveis
inteiro: n, p, pp;
escreva(“digite 2 números inteiros”);
leia(n, p);
pp := pot(n,p);
escreva(pp);
fim.
O oitavo exemplo utiliza a declaração e manipulação de vetor:
programa quantidadealunosaprovados;
inicio
tpv = vetor(20) de real;
variaveis
tpv: nota;
real: soma, mediag;
inteiro: cont, qtdalunos, alunosap;
soma := 0;
qtdalunos := 0;
cont := 0;
faca
inicio
soma = soma + nota[cont];
qtdalunos = qtdalunos + 1;
cont = cont + 1;
fim;
enquanto (cont<=19);
mediag := soma/ qtdalunos;
para cont de 0 ate 19 passo 1 faca
inicio
se (nota[cont] > mediag) entao
alunosap := alunosap + 1;
fim;
escreva(alunosap);
fim.
34
O nono exemplo utiliza a declaração e manipulação de matriz:
programa cxmatriz;
inicio
mat = matriz(10,3) de real;
variaveis
mat : n;
inteiro : cont, contar
real: mediaalunos, somamedia;
para cont de 0 ate 9 passo 1 faca
inicio
para contar de 0 ate 2 passo 1 faca
inicio
leia(n[cont][contar]);
fim;
fim;
para cont de 0 ate 9 passo 1 faca
inicio
para contar de 0 ate 2 passo 1 faca
inicio
mediaalunos := mediaalunos + n[cont][contar];
fim;
fim;
fim.
35
4 IMPLEMENTAÇÃO (CLASSES)
Este Capítulo trata da descrição das classes usadas no projeto. As
classes
estão
separadas
pelos
seguintes
pacotes:
Compilador,
Compilador.Analises, Fluxograma, Desenho, Ico e Util.
As classes utilizadas no projeto foram implementadas na
linguagem orientada a objetos Java (pacote JDK 1.6) e modeladas em UML
(Unified Modeling Language).
4.1 Modelagem das classes em UML
O Pacote Compilador possui as seguintes classes e pacote: classe
Executaprograma.java (que recebe por parâmetro o código já traduzido
para JavaScript e cria um arquivo no disco para ser visualizado no navegador),
classe Main (que chama a classe Principal para inicialização do projeto),
classe Principal.java (que contém o Editor de texto) e o pacote Analises
(que contém as análises do compilador).
O Pacote Analises possui as seguintes classes: Lexico (que
analisa a entrada de caracteres e produz uma seqüencia de símbolos
chamados tokens), Token (que permite adicionar e navegar entre os símbolos
usados no código), Sintatico (que recebe uma seqüência de tokens e
verifica se esta seqüência pode ser gerada pela gramática da linguagem).
O pacote Fluxograma possui as seguintes classes: Formas (que
monta a imagem para ser usado no fluxograma), Ligacao (que monta a
ligação entre um desenho e outro), Principal (que contém o ambiente para
ser desenvolvido o fluxograma).
O pacote desenho e Ico possuem imagens que são usadas nos
botões e nos desenhos do fluxograma.
O pacote Util possui as seguintes classes: Localizar (que
localiza a palavra no editor de texto) e substituir (que substitui todas as palavras
do editor de texto por outra).
36
4.2 Classe ExecutaPrograma
A classe ExecutaPrograma (Figura 12) tem função de receber
por parâmetro o código já traduzido em JavaScript e criar um arquivo com
mesmo no disco chamado “RAF_programa_resutante.html”. Por medidas de
segurança se houver um arquivo com o mesmo nome, será apagado e criado
novamente com o novo código e finalmente ser aberto pelo navegador Mozilla
Firefox. A Figura 12 apresenta a classe ExecutaPrograma.
Figura 12 – Classe ExecutaPrograma.
4.3 Classe Main
A Classe Main (Figura 13) é responsável pela a inicialização do
sistema, ela contém o método main que chama a classe Principal (ambiente
de desenvolvimento do usuário) e o método finalize() que contém o
Garbage Collector (Coletor de lixo) que é chamado na finalização do sistema. A
Figura 13 apresenta a classe Main.
Figura 13 – Classe Main
37
4.4 Classe Principal
A Classe Principal é o ambiente do usuário para edição de
Texto, nela é permitido digitar, salvar, selecionar, imprimir, desfazer, refazer,
recortar, colar, localizar e substituir texto.
A organização e ações dos componentes são de acordo com letra
inicial, sendo “m” para Menu ou itens do menu, “b” para Botões, “j” para caixa
de texto e barras de ferramenta e “d” para o botão direito do mouse (menu popup). Os métodos que possui ActionPerformed e MouseClicked
são
chamados ao efetuar um clique em um determinado componente e os que
possui KeyReleased são chamados ao soltar a tecla durante a digitação.
Lista de métodos da classe Principal:
• IniComponents(): método que contém toda a inicialização
dos componentes para a montagem do layout do editor de
texto;
• InfoRodape(): método que contém o cálculo para obter a
linha atual e o total de linhas digitadas pelo usuário;
• BRecortarActionPerformed(...),
mRecortarActionPerformed(...)
e
dRecortarActionPerformed(...) : métodos que permite
ao usuário recortar o texto selecionado;
• BCopiarActionPerformed(...),
mCopiarActionPerformed(...)
e
dCopiarActionPerformed(...) : métodos que permitem
ao usuário copiar o texto selecionado;
• bColarActionPerformed,
dColarActionPerformed:
mColaActionPerformed e
métodos
que
permitem
ao
usuário colar o texto;
• mImprimirActionPerformed(...): método que permite ao
usuário imprimir o texto (portugol) ;
• mLocalizarActionPerformed(...): método que permite
localizar um determinado texto;
• mSubstituirActionPerformed(...): método que permite
substituir um texto por outro;
38
• formWindowClosing(...): método que é chamado ao
fechar o sistema, nele é verificado se o usuário digitou ou não
algum texto, caso tenha digitado verifica se já foi salvo ou não,
permitindo “Salvar como” ou salvar alterações.
• MFluxoActionPerformed(...):
método que chama a
classe Fluxograma e obtém o código do mesmo;
• JComandoKeyReleased(...)
e
jComandoMouseClicked(...): métodos que chamam o
método infoRodape;
• initComponents2: método que aumenta o tamanho da
janela de acordo com a resolução do micro do usuário e
associa os componentes (menus e botões) com ações de
“Abrir”, “Novo”, “Salvar”, “Salvar como” e “executar”;
• NovoArquivo(): método que permite ao usuário criar um
novo arquivo;
• SalvarComo(): método que permite ao usuário Salvar pela
primeira vez o arquivo atual em um determinado local;
• Salvar(): método que permite salvar as alterações do
arquivo atual;
• initUndoRede(): método que associa os componentes
(Menus e botões) as ações desfazer e refazer;
39
Figura 14 – Classe Principal.
As
classes
RedoAction
e
UndoAction
são
classes
disponibilizadas pela Sun Microsystens que tem a função de desfazer e refazer
um estado anterior que estava o texto.
4.4.1 Classe RedoAction
A Classe RedoAction permite ao usuário refazer um estado
anterior (desfeito) que estava o seu texto. Caso chegue ao limite de refazer a
ação é desabilitada automaticamente. A Figura 15 apresenta a classe
RedoAction.
40
1 public class RedoAction extends AbstractAction
2 {
3
public void actionPerformed(ActionEvent e)
4
{
5
…
6
}
7
8
protected void updateRedoState()
9
{
10
…
11
}
12
13
final Principal this$0;
14
15
public RedoAction()
16
{
17
…
18
}
19 }
Figura 15 – Classe RedoAction.
4.4.2 Classe UndoAction
A Classe UndoAction permite ao usuário desfazer um estado
anterior que estava o seu texto. Caso chegue ao limite de desfazer a ação é
desabilitada automaticamente. A Figura 16 apresenta a classe UndoAction.
1 class UndoAction extends AbstractAction
2 {
3
public void actionPerformed(ActionEvent e)
4
{
5
…
6
}
7
8
protected void updateUndoState()
9
{
10
…
11
}
12
13
final Principal this$0;
14
15
public UndoAction()
16
{
17
…
18
}
19 }
Figura 16 – Classe UndoAction.
41
4.5 Classe CodigoGerado
A Classe estática CodigoGerado auxilia na tradução do portugol
para JavaScript com algumas funções chamadas matriz(),
leia(),
pot(), rad() e lógico(). Cada método retorna um trecho código traduzido
com o mesmo nome, exemplo o método matriz() que retorna um trecho de
código (função) em JavaScript chamada matriz(m,n).
A função matriz(m,n)
auxilia na tradução para o código
JavaScript no tratamento de matrizes. Como a linguagem JavaScript só possui
vetores, a função cria um vetor com n posições e dentro de cada elemento
coloca outro vetor com n posições.
A função leia() auxilia na tradução para o código JavaScript na
leitura do valor da variável e identifica qual é seu tipo. Os tipos são: caracter,
inteiro, real e lógico.
A função pot(n,n) recebe dois valores numéricos por parâmetro
e auxilia na tradução para o código JavaScript no que se refere a potenciação.
A função rad(n) recebe um valor numérico por parâmetro e
auxilia o código JavaScript no que se refere a raiz quadrada. A Figura 17
apresenta a classe CodigoGerado.
Figura 17 – Classe CodigoGerado.
A Figura 18 mostra o código-fonte dos métodos matriz(m,n), leia(),
pot(m,n), rad(n), assim como as variáveis verdadeiro e falso.
42
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function matriz(v,m){
var linha = new Array(v);
for(i=0;i<m;i++){
linha[i] = new Array(m);
}
return linha;
}
function leia(){
var num = '1234567890.-';
var encontrou = false;
var saida;
var v = prompt('Valor','');
if (v=='verdadeiro' || v=='falso'){//tipo lógico
encontrou = true;
saida=v;
}
for(i=0;i<v.length && encontrou == false;i++){//tipo Caracter
var car = v.charAt(i);
if(num.indexOf(car)==-1){
encontrou = true; saida=v;
}
}
if(encontrou==false){
saida = parseFloat(v);
}
return saida;
}
function pot(n,p){
var t;
t = Math.pow(n,p);
return t;
}
function rad(n){
var t;
t = Math.sqrt(n);
return t;
}
var verdadeiro = 'verdadeiro'; var falso = 'falso';
Figura 18 – Funções adicionais.
4.6 Classe Token
A Classe Token permite que sejam adicionados elementos do
código digitado pelo usuário para verificar se esta seqüência pode ser gerada
pela gramática da linguagem.
Métodos da Classe Token:
43
• proxValor(): método que navega para o próximo elemento
já adicionado. Exemplo: após todos os token terem sido
encontrados, a gramática chega ao token “programa”, e verifica
se a escrita esta correta. Após a verificação, o próximo token é
chamado pelo método proxValor() que faz a busca do mesmo
na da lista de tokens, retornando o “Nome_programa”.
Elementos
Programa
Chamada de
proxValor
Nome_programa
;
método
Posição
0 (Posição atua)
1
2
• ValorAnt(): método que navega para o elemento anterior;
Elementos
Programa
Nome_programa
;
Chamada
de método
ValorAnt
Posição
0 (Posição atua)
• addItem(String
1
2
valor):
método que adicionar um
indice):
método
elemento;
• getItemAt(int
que
recebe
por
parâmetro um número e retorna a posição do elemento desta
posição;
• Posicao(): método que retorna um valor numérico da
posição atual do elemento;
• getItemCount(): método que retorna a quantidade de
elementos adicionados;
A Figura 19 mostra o diagrama da Classe Token.
44
Figura 19 – Classe Token.
4.7 Classe Lexico
A Classe Lexico recebe por parâmetro o código digitado pelo
usuário e separa os elementos que tem ou não importância, caso tenha, é
retornado um objeto do tipo token com todos os elementos para serem usados
na Classe Sintatico.
Lista de Métodos da classe Lexico:
• palavrareservada(String valor): recebe por parâmetro
uma palavra e retorna um valor booleano dizendo se existe ou
não;
• setPalavra(String valor): recebe por parâmetro uma
palavra para ser adicionado na lista de palavras que poderá ser
usada na compilação, exemplo variáveis e números.
• getToken(): retorna a seqüência de elementos que serão
usados na classe Sintatico;
getPosLinha(): retorna a seqüência de elementos (linha dos
tokens) que serão usados na classe Sintatico;
Elementos
getToken
getPosLinha
0
1
2
3
4
programa
Nome_progra
ma
1
;
inicio
fim.
1
2
3
1
45
A Figura 20 mostra o diagrama da Classe Lexico.
Figura 20 – Classe Lexico.
4.8 Classe Sintatico
A Classe Sintatico recebe por parâmetro dois objetos do tipo
Token: um que contém todos os elementos (código do usuário) e que contém
as posições da linha de cada elemento. Nessa Classe é verificado se a
seqüência de tokens pode ser gerada pela gramática da linguagem.
Lista de Métodos da classe Sintatico:
• saida(): Método que recebe por parâmetro a tradução do
portugol para JavaScript durante a verificação da sintaxe;
• getsaida(): Método que retorna o código completo traduzido
para JavaScript;
Os próximos métodos são usados para verificação do código do
usuário, caso ocorra um erro, a verificação é cancelada retornando um aviso
(tipo de erro) e a posição da linha, senão a compilação será com sucesso.
• comeco():
método que verifica a sintaxe do inicio do
programa;
Código esperado
Programa Nome_programa ;
Código traduzido
<title>Nome_programa</title>
46
• bloco_princ(): Método que verifica a sintaxe do bloco
principal do programa;
Código esperado
Inicio fim.
Código traduzido
<script language=”javascript”></script>
• tipo(): Método que verifica a existência da declaração de
matriz ou vetor;
• tipo_cons(): Método que verifica a sintaxe da matriz ou
vetor;
Código esperado
tipoVet = vetor(n) de tipo
Vetor
Código traduzido
tipoVet = new Array(n);
Código esperado
tipoMat = matriz(n,n) de tipo
Matriz
Código traduzido
tipoVet = Matriz(n,n);
• tipo_bas: Método que verifica a sintaxe dos tipos básicos
(primitivos) : inteiro, caracter, real e lógico;
• decl(): Método que verifica a existência da declaração de
variável;
Código esperado
variaveis
Código traduzido
Var
• lista_id(), varios_id() e cont_lista(): Métodos
que verificam a sintaxe da declaração de variáveis;
Código esperado
tipo: a,b;
tipo: q;
Código traduzido
a = ‘’;
b = ‘’;
q = ‘’;
• tipox(): Método que verifica a sintaxe dos tipo básicos ou
tipo constante: inteiro, caracter, real, lógico e os tipos de vetores
ou matrizes declarados anteriormente.
• varios_cmds()
e
cmd():
Método que verifica qual
comando após a declaração de variáveis serão usados.
• cmd_if():
Método que verifica o início da sintaxe do
comando se;
Código esperado
se(
Código traduzido
if(
47
• exp_logica(): Método que verifica a expressão lógica;
Código esperado
A<>0 e (b=1) ou c>=3
Código traduzido
A!=0 && (b!=1) || c>=3
• varios_if(): Método que verifica a existência do senao;
Código esperado
senao
Código traduzido
else
• cmd_enquando(): Método que verifica a sintaxe do comando
enquanto;
Código esperado
enquanto( ... )faca
inicio
....
fim;
Código traduzido
while(...){
...
}
• cmd_faca(): Método que verifica a sintaxe do comando
faca;
Código esperado
Faca
Inicio
....
fim
enquanto(...);
Código traduzido
do{
...
}while(..);
• exp_nao(): Método que verifica a sintaxe do comando nao
(negação);
Código esperado
nao
Código traduzido
!
• cont_exp():
Método
que
verifica
a
existência
dos
operadores lógicos na expressão lógica;
Código esperado
(a>2) e (a<10) ou (a=20)
Código traduzido
(a>2) && (a<10) || (a=20)
• val5(): Método que verifica a sintaxe do valor lógico e literal;
48
• cmd_atrib(): Método que verifica a sintaxe da atribuição de
variável;
Código esperado
a:=
Código traduzido
a=
• exp_arit(): Método que verifica a sintaxe da expressão
aritmética
Código esperado
(a+2)/9 mod 8
Código traduzido
(a+2)/9 % 8
• exp_arit() e y(): Métodos que verificam a sintaxe da
expressão aritmética
Código esperado
(a+2)/9 mod 8
Código traduzido
(a+2)/9 % 8
• oper(): Método que verificam a sintaxe dos operadores
aritméticos;
Código esperado
+ - / * mod div
Código traduzido
+ - / * % parseint(n/n)
• operx(): Método que verificam a sintaxe dos operadores
relacionais (= e <>);
Código esperado
= <>
Código traduzido
== !=
• oper_logicos():
Método que verifica a sintaxe dos
operadores lógicos;
Código esperado
e ou
Código traduzido
&& ||
• oper_relacional(): Método que verifica a sintaxe dos
operadores relacionais;
Código esperado
>
=>
<
<=
<> =
Código traduzido
>
=>
<
<=
!= ==
• getID(): Método que verifica a sintaxe e existência das
variáveis;
Código esperado
a[0][1]
Código traduzido
a[0][1]
49
• func_mat(): Método que verifica a sintaxe e existência das
funções matemáticas (potência e raiz quadrada);
Código esperado
pot(n,n)
...
rad(n);
Código traduzido
Math.pow(n,p);
...
Math.sqrt(n);
• cmd_escolha(): Método que verifica a sintaxe do comando
escolha;
Código esperado
escolha a
• bloco_escolha(): Método que verifica o bloco do comando
escolha (Inicio e fim);
Código esperado
Inicio ... fim;
• cmd_casos(): Método que a verifica sintaxe do comando
caso.
• val_caso()
e
val_caso2():
Método que verifica a
sintaxe dos valores usados no comando caso.
• val4(): Métodos que verifica a sintaxe dos valores lógicos
(verdadeiro e falso) e literal;
Código esperado
caso 1,5,6: escreva(“Números”);
Código traduzido
if(a==1|| a== 5 ||a==6){document.write(“Números”);} else
Código esperado
caso 11..14: escreva(“outros Números”);
Código traduzido
if(a==11 || a== 12 || a==13 || a==14){
document.write(“Números”);
} else
• casow(): Método que verifica a existência de um próximo
comando caso;
• cmd_casocontrario(): Método que verifica a sintaxe do
comando casocontrario;
Código esperado
casocontrario: escreva(“outros Números”);
Código traduzido
{
document.write(“outros números”);
}
• val(): Método que verifica a sintaxe das variáveis e valores
numéricos (inteiro e real), tendo possibilidade de colocar
parênteses;
50
• cmd_escrever(): Método que verifica a sintaxe do comando
escreva;
Código esperado
escreva(“Bom dia!”);
Código traduzido
document.write(“Bom dia”);
• varios_escrever(): Método que verifica a existência da
expressão aritmética no comando escreva;
Código esperado
escreva(“Valor é”,a+b);
Código traduzido
document.write(“Valor é”,a+b);
• varios_escrever2(): Método que verifica a existência de
um próximo elemento no comando escreva
Código esperado
escreva(“Valor é”,a+b);
Código traduzido
document.write(“Valor é ”,a+b, “Total”, c );
• cmd_ler(): Método que verifica a existência e a sintaxe do
comando leia;
Código esperado
leia(a);
Código traduzido
a=leia();
• cmdler_id():
Método que verifica a existência de um
próximo elemento no comando leia;
Código esperado
leia(a,b,c,d);
Código traduzido
a=leia();
b=leia();
c=leia();
• cmd_para: Método que verifica a sintaxe do comando para;
Código esperado
Para a de 10 ate 1 passo -1 faca
Código traduzido
for(a=+10;a>=+1;a=a-1)
• bloco(): Método que verifica a sintaxe do bloco que contém
comandos;
Código esperado
inicio .... fim;
Código traduzido
{ ... }
• val2(): Método que verifica a sintaxe das variáveis e valores
numéricos (inteiro e real);
• val3(): Método que verifica a sintaxe das variáveis e valores
numéricos (inteiro);
51
• val_logico() e val_logico(String v): Método que
verifica a sintaxe dos valores lógicos;
• literal(): Método que verifica a sintaxe dos valores literais;
• getID2(String v): Método que verifica existência de uma
determinada variável;
• addID(String v): Método que adiciona variáveis usadas
no algoritmo;
• num_it(int
n):
Método que valida valores numéricos
(inteiro);
• num_real(int n): Método que valida valores numéricos
(real);
• limpar_literal(String v): Método que limpa valores
literal;
• setErro(String
v):
Método
que
adiciona
erros
encontrados na análise sintática;
• getErro(): Método que retorna erros encontrados na análise
sintática.
A Figura 21 mostra o diagrama da Classe Sintatico.
52
Figura 21 – Classe Sintatico
53
4.9 Classe Forma
A Classe Forma é um componente de desenho que recebe dois
parâmetro (tipo e id da forma), nela é carregado um desenho e uma tabela com
propriedades de uma forma especifica.
As propriedades são espécie de referência, como:
• ID da forma;
• Próxima forma do fluxograma;
• Texto a ser exibido no seu conteúdo.
Lista de métodos da classe Forma:
• setText(String v): Método que permite mostrar um texto
em HTML (HyperText Markup Language) no conteúdo da forma
• getValue(): método que retorna o texto exibido no conteúdo
da forma;
• setValue(String v): Método que permite mostrar o texto
no conteúdo da forma;
• setID(String
v):
Método que permite atribuir uma
identificação a forma;
• getID(): Método que retorna a identificação da forma;
• tipo(int cor, int tipo, int espaco): Método que
configura a cor do texto a ser mostrado no conteúdo da forma
(0 para preto e 1 para branco), carrega a imagem e configura o
espaço entre o desenho e o texto a ser exibido;
• setPropriedades(String
v):
Método
que
permite
carregar a tabela com propriedades da forma especifica;
• setProximo(String v): Método que permite identificar a
próxima forma;
• getProximo(): Método que retorna o nome da próxima
forma;
• getVerdadeiro(): Método que retorna o nome da próxima
forma (caso seja verdadeiro). Este método somente é usado no
caso de condições;
• setVerdadeiro(String v): Método que é usado para
identificar a próxima forma (caso seja verdadeira);
54
• getFalso(): método que retorna o nome da próxima forma
(caso seja falso). Este Método somente é usado no caso de
condições;
• setFalso(String v): Método que é usado para identificar
a próxima forma (caso seja falso);
• getFimse(): método que retorna o nome da próxima forma
identificando o fim da condição verdadeira;
• setFimse(String v): Método que é usado para identificar
a próxima forma e o fim da condição verdadeira;
• getFimsenao(): método que retorna o nome da próxima
forma identificando o fim da condição falsa;
• setFimsenao(String
v):
Método que é udado para
identificar a próxima forma e o fim da condição falsa;
• setEnquantoInicio(String
v):
Método que é usado
para identifica a primeira forma usada no bloco enquanto;
• getEnquantoInicio(): Método que retorna o nome da
primeira forma usada no bloco enquanto;
• setIniciofaca(String
v):
Método que identifica a
primeira forma usada no bloco faça;
• getIniciofaca(): Método que retorna o nome da primeira
forma usada no bloco faça;
• getTipo(): Método que retorna o tipo da tomada de decisão
(se, enquanto ou para);
• tipoRepeticao(): Método que retorna o tipo de repetição
(enquanto ou para);
• addPropriedades(): método que permite montar os itens
da tabela de propriedades;
• PropriedadesBasicas(): método que permite montar as
propriedades básicas da tabela básica (ID, Próximo, texto ...)
• getPropriedades(): método que retorna as propriedades
montada na tabela de propriedades;
• PropriedadesFins():
método que permite montar a
propriedade fim da tabela (fimse e fimsenao);
55
• PropriedadesCondicao(): método que permite montar as
propriedades usada na tomada de decisão (verdadeiro, falso,
inicioFaça ...);
A Figura 22 mostra o diagrama da classe Forma.
Figura 22 – Classe Forma.
4.10 Classe Ligacao
A Classe Ligacao é um componente de desenho que permite
ligar duas formas à tabela de propriedades. Recebe por parâmetro o tipo de
ligação.
A Figura 23 ilustra os tipos de ligações utilizadas no desenho de
um (Fluxograma).
56
Figura 23 – Ligações usadas no desenho de um fluxograma.
Lista de métodos:
• getLigacao(): Método que retorna o tipo de ligação para
ser desenhado no fluxograma.
A Figura 23 mostra o diagrama da classe Ligacao.
Figura 24 – Classe Ligacao.
57
5 CONCLUSÕES
Conforme resultados obtidos com testes e pesquisas no
desenvolvimento do compilador, foi possível destacar alguns aspectos
importantes. No início a ferramenta teria uma versão applet para funcionar nos
navegadores de internet. Mas, como a ferramenta gera um arquivo em HTML
no disco local para execução do sistema (o código traduzido para linguagem
JavaScript), e o applet por questão de segurança não permite este tipo de
acesso, então, o sistema teve somente uma versão desktop.
O compilador RAF foi concluído com os seguintes módulos: Editor
de texto; Compilador para pseudolinguagem e fluxograma; Tradutor de portugol
para JavaScritp; Módulo de desenho de Fluxogramas; e Tradutor de
Fluxograma para pseudolinguagem.
Por fim, acredita-se que a ferramenta irá facilitar a compreensão
dos alunos de Superior em Tecnologia em desenvolvimento Web no
aprendizado de algoritmos.
58
REFERÊNCIAS BIBLIOGRÁFICAS
AHO. A. V.: SETHI, R. & ULLMAN, J. D. Compiladores: Princípios, Técnicas e
Ferramentas. Guanaban Koogan 1986.
Diogo Branquinho Ramos. Coral: protótipo de uma linguagem orientada a
objetos usando geradores de compiladores java. Universidade do Oeste
Paulista, 2005
DELAMARO, Márcio Eduardo. Como construir um compilador, utilizando
ferramentas Java. Novatec. 2004.
FELIPE ZSCHORNACK. Um Ambiente de execução para a Linguagem RS.
Universidade Federal de Pelotas Instituto de Física d Matemática Curso de
Ciência da Computação. Acesso em 2 out. de 2007. Acesso em 2 out. de 2007.
Disponível
em:
<www.ufpel.tche.br/prg/sisbi/bibct/acervo/info/2003/
mono_felipe.pdf>.
G-Portugol - A Linguagem de Programação. Acesso em 2 out. de 2007.
Disponível em: <http://gpt.berlios.de/site/>
LOUDEN, KENNETH. Compiladores, Princípios e Práticas. São Paulo: Pioneira
Thomson Learning, 2004.
Portugol IDE. Acesso em 2
<http://orion.ipt.pt/~manso/Portugol/>.
out.
de
2007.
Disponível
em:
RAMOS, Diogo Branquinho. Coral: protótipo de uma linguagem orientada a
objetos usando geradores de compiladores Java. 68p. Trabalho de Conclusão
de Curso (Graduação em Ciência da Computação) – Universidade do Oeste
Paulista – UNOESTE: Presidente Prudente - SP, 2005.
SANTIAGO, Rafael de. Compilador CIFluxProg . Universidade do Vale do Itajaí,
2004. Disponível em: <www.inf.furb.br/seminco/2004/artigos/96-vf.pdf>
ZSCHORNACK, Felipe. Um Ambiente de execução para a Linguagem RS.
Universidade Federal de Pelotas Instituto de Física e Matemática Curso de
Ciência da Computação.
Download

DESENVOLVIMENTO DE UM COMPILADOR PARA