Slang++
Pretende-se neste trabalho desenvolver uma folha de cálculo simples. O trabalho divide-se em duas fases, correspondendo a duas entregas de resoluções por parte dos alunos. A primeira fase é, naturalmente, menos ambiciosa nos seus objectivos que a segunda fase, servindo sobretudo como incentivo à dedicação dos alunos ao trabalho o mais cedo possível. Os objectivos de cada uma das fases serão descritos mais abaixo. Mas, globalmente, pretende-se que a folha de cálculo desenvolvida tenha as seguintes possibilidades:
double
).Slang++
.As diferenças principais entre as duas fases do trabalho prendem-se com a interface com o utilizador (ver Secções 2.1 e 2.2), que é simplificada na primeira fase, e com a utilização de hierarquias de classes como forma de evitar a análise sintáctica repetida das fórmulas presentes em cada célula da folha. Além disso, existem outros requisitos do trabalho na globalidade que não são exigidos na primeira fase.
Uma folha de cálculo consiste num conjunto de células dispostas conceptualmente em linhas e colunas, sendo as linhas e colunas identificadas por números inteiros arbitrários. A um par (l, c), em que l é o índice de uma linha e c é o índice de uma coluna, chama-se posição da célula na folha. As células existem sempre, independentemente de terem uma representação física no programa. As células têm uma fórmula que permite calcular o seu valor. Inicialmente todas as células estão vazias, i.e., não têm fórmula. As coordenadas têm índices arbitrários, inclusive negativos. Assim, a coordenada (-10, 30) é válida e corresponde à coluna 30 da linha -10.
Apenas as posições correspondentes a células não vazias são mostradas visualmente. As restantes são deixadas em branco.
Cada célula não-vazia da folha contém uma dada fórmula, que pode inclusive consistir apenas num valor numérico literal. As fórmulas são expressas usando uma sintaxe semelhante à do C++, embora muito mais simples, e com algumas diferenças no nome dos operadores.
Se uma célula contiver uma fórmula com um erro de sintaxe (lexical ou gramatical), tal deverá ser assinalado graficamente através da palavra
«sintaxe»
Para efeitos de cálculos de outras células, uma célula nessas
circunstâncias terá o valor nan
(not a number), que é o valor que obtém com a seguinte definição C++:
double const nan = 0.0 / 0.0;
Se o erro na fórmula for não de sintaxe mas de cálculo, e.g., invocação de uma função inexistente ou com um número errado de argumentos ou utilização de uma constante indefinida, tal deverá ser assinalado graficamente através da palavra
«cálculo»
Para efeitos de cálculos de outras células, uma célula nessas
circunstâncias terá o valor nan
.
A fórmula de uma célula pode conter referências a valores de outras células. Estas referências consistem sempre num par de coordenadas linha/coluna em que cada um dos valores é precedido do caractere '$'. Por exemplo,
$1$2
é uma referência ao valor da célula na posição (1,2) da folha de cálculo. As coordenadas numa referência são absolutas e fixas, i.e., referem-se à mesma célula independentemente da célula de cuja fórmula fazem parte, e não sofrem qualquer ajustamento quando as células são copiadas.
Quando a célula à
qual uma fórmula se refere não existir ou tiver um erro, deve-se assumir que o seu valor é nan
.
As fórmulas podem conter invocações de funções. Deverá ser suportado o seguinte conjunto de funções pré-definidas:
sen
(x) - seno de xcos
(x) - coseno de xtan
(x) - tangente de xasen
(x) - arco cujo seno é x (-pi / 2
a pi / 2)acos
(x) - arco cujo coseno é x (0 a pi)atan
(x) - arco cuja tangente é x (- pi /
2
a pi / 2)atan2
(y, x) - arco da tangente é y / x
(-pi a pi)senh
(x) - seno hiperbólico de xcosh
(x) - coseno hiperbólico de xtanh
(x) - tangente hiperbólico de xexp
(x) - exponencial de x, i.e., exlog
(x) - logaritmo natural de xlog2
(x) - logaritmo base 2 de xlog10
(x) - logaritmo base 10 de xpot
(x, y) - potência y de x,
i.e., o mesmo que xy, ou seja, x^
yraizq
(x) - raiz quadrada de xtecto
(x) - menor inteiro maior ou igual a xbase
(x) - maior inteiro menor ou igual a xabs
(x) - valor absoluto de x, i.e., |x|Estas funções não podem ser alteradas e estão já previstas no pacote fornecido (ver Secção 1.2.5).
Todas estas funções têm equivalente em C++ (usar #include <cmath>
).
As fórmulas podem conter constantes. Estas referem-se a valores
numéricos que não são alteráveis por via das fórmulas da folha. Numa fórmula as constantes são sempre introduzidas através da
construção %nome
, onde nome
é o nome
da constante.
Deverão existir apenas duas constantes pré-definidas:
%pi
- Valor "pi" (o perímetro de uma
circunferência de raio unitário é 2 × %pi
).%e
- Valor "e" (o logaritmo natural de %e
é 1).Estas constantes não podem ser alteradas e estão já previstas no pacote fornecido (ver Secção 1.2.5).
A gramática usada nas fórmulas é a que se define em seguida. Nesta gramática surgem primeiro as definições com menor precedência. A gramática é apresentada na forma de uma lista de regras de produção. As regras de produção consistem no formato:
categoria_sintáctica := sequência_de_símbolos
A sequência de símbolos define possíveis formas para sequências de
símbolos de acordo com a sintaxe da categoria sintáctica em definição.
Alguns símbolos pertencem à definição da gramática em si. É o caso
de |, que significa "ou", separando sequências de símbolos
possíveis alternativas. Os restantes símbolos ou são terminais (i.e.,
correspondem directamente a símbolos que se podem encontrar numa frase escrita
na gramática em definição), ou são não-terminais, caso em que corresponderão
a uma categoria sintáctica definida na gramática (nesse caso surgem em
itálico). Os símbolos terminais são colocados em tipo proporcional (assim
)
e assume-se que ocorrem tal e qual nas frase escritas usando a
gramática. Em alguns casos foge-se a uma definição formal, colocando
uma definição informal entre {}.
Gramática das fórmulas:
- expressão :=
- expressão_condicional
- expressão_condicional :=
- expressão_ou |
expressão_ou?
expressão_condicional:
expressão_condicional- expressão_ou :=
- expressão_e |
- expressão_e
|
expressão_ou- expressão_e :=
- expressão_igualdade |
- expressão_igualdade
&
expressão_e- expressão_igualdade :=
- expressão_relacional |
- expressão_relacional
==
expressão_igualdade |- expressão_relacional
!=
expressão_igualdade- expressão_relacional :=
- expressão_aditiva |
- expressão_aditiva
<
expressão_relacional |- expressão_aditiva
<=
expressão_relacional |- expressão_aditiva
>
expressão_relacional |- expressão_aditiva
>=
expressão_relacional- expressão_aditiva :=
- expressão_multiplicativa |
- expressão_multiplicativa
+
expressão_aditiva |- expressão_multiplicativa
-
expressão_aditiva- expressão_multiplicativa :=
- expressão_potencial |
expressão_potencial*
expressão_multiplicativa |
expressão_potencial/
expressão_multiplicativa- expressão_potencial :=
- expressão_unaria |
- expressão_unaria
^
expressão_potencial- expressão_unaria :=
- expressão_funcional |
-
expressão_unaria |+
expressão_unaria |!
expressão_unaria- expressão_funcional :=
- expressão_primaria |
- identificador
(
)
|- identificador
(
lista_de_expressoes)
- lista_de_expressoes :=
- expressão |
- expressão ',' lista_de_expressoes
- expressão_primaria :=
- número |
- constante |
- referência |
(
expressão)
- número :=
- {como os valores literais
double
do C++}- número_inteiro :=
-
{sequência de dígitos} |+
{sequência de dígitos} |- {sequência de dígitos}
- constante :=
%
identificador- identificador :=
- {sequência de letras, dígitos e
_
(sublinhado), começando por uma letra}- referência :=
$
inteiro$
inteiro
A análise sintáctica das fórmulas ocorre em duas fases: análise lexical e análise gramatical. Na primeira fase as fórmulas são lidas caractere a caractere e divididas em símbolos (usa-se um símbolo especial para marcar o final da sequência). Na segunda fase a sequência de símbolos é analisada verificando-se se corresponde à gramática acima (excepto as últimas regras produtivas, que dizem respeito à constituição de alguns tipos especiais de símbolos (número, constante, identificador e referência), e que são tratadas durante a análise lexical.
Por exemplo, a fórmula
5 * (1 + -3) ^ 2
pode ser gerada pelas regras de produção apresentadas na secção anterior. A divisão em símbolos, que ocorre durante a análise lexical, resulta em:
*
(
+
-
)
^
A análise sintáctica desta fórmula resulta em
Esta parte do trabalho não precisa de ser desenvolvida de raiz. Está
disponível um pequeno pacote de análise e cálculo de fórmulas (calculo
sem contexto.tar.gz
)
que contém as classes necessárias e um pequeno programa demonstrativo do
funcionamento do código (teste.C
). O código fornecido
deverá ser lido e compreendido, pois será certamente necessário alterá-lo,
pois não suporta referências, por exemplo.
Encontra também uma versão um pouco diferente do código (calculo
com contexto.tar.gz
) que faz uso de um contexto de cálculo das
fórmulas. A obtenção do valor das células referenciadas numa fórmula
obriga a que o cálculo seja realizado no contexto da respectiva folha de
cálculo. Pode-se inspirar neste pacote para perceber como isso pode ser
conseguido.
A interface do programa com o utilizador será muito simples. Na
primeira fase do trabalho recorrerá simplesmente a linhas de comandos,
usando-se para isso os canais cin
e cout
. Na
segunda fase será necessário equipar o programa com uma interface mais fácil
de usar, recorrendo à biblioteca Slang++
.
Atempadamente serão disponibilizados ficheiros executáveis oficiais para cada uma das fases de entrega do trabalho final, cuja interface com o utilizador deverá ser emulada pelos programas desenvolvidos pelos alunos.
Lista-se abaixo um exemplo simples de interacção do programa com o utilizador. A negrito apresentam-se as entradas do utilizador. Note-se que o programa mostra apenas as células das linhas 0 a 22 e colunas 0 a 7, e em baixo apenas se mostram as três primeiras colunas:
mms@mercurio ~> editor_de_folha_oficial /usr/local/bin/teste.flh 0 1 2 3... 0 31 0 0 1 «sintaxe» 0.314159 0.309017 2 «calculo» 0.628319 0.587785 3 31 0.942478 0.809017 4 nan 1.25664 0.951057 5 nan 1.5708 1 6 1.0472 1.88496 0.951057 7 0.866025 2.19911 0.809017 8 0.866025 2.51327 0.587785 9 3.14159 2.82743 0.309017 10 «calculo» 3.14159 1.22461e-16 11 1 3.45575 -0.309017 12 3.76991 -0.587785 13 4.08407 -0.809017 14 4.39823 -0.951057 15 4.71239 -1 16 nan 5.02655 -0.951057 17 nan 5.34071 -0.809017 18 «calculo» 5.65487 -0.587785 19 «calculo» 5.96903 -0.309017 20 «calculo» 21 22 <enter> para continuar. Menu: edita - ver/definir/apagar célula. copia - copia célula. guarda - guarda folha em disco. carrega - carrega folha do disco. sai - sai do editor. Opção: edita Qual a posição? [linha coluna] 5 2 Célula (5,2): Fórmula: sen($5$1) Valor: 1 Diagnóstico: Ok. Menu: nova - nova fórmula. apaga - apaga fórmula/célula. sai - volta ao menu anterior. Opção: nova Introduza a nova fórmula: sen($5$1) * 2 Célula (5,2): Fórmula: sen($5$1) * 2 Valor: 2 Diagnóstico: Ok. Menu: nova - nova fórmula. apaga - apaga fórmula/célula. sai - volta ao menu anterior. Opção: sai 0 1 2 3... 0 31 0 0 1 «sintaxe» 0.314159 0.309017 2 «calculo» 0.628319 0.587785 3 31 0.942478 0.809017 4 nan 1.25664 0.951057 5 nan 1.5708 2 6 1.0472 1.88496 0.951057 7 0.866025 2.19911 0.809017 8 0.866025 2.51327 0.587785 9 3.14159 2.82743 0.309017 10 «calculo» 3.14159 1.22461e-16 11 1 3.45575 -0.309017 12 3.76991 -0.587785 13 4.08407 -0.809017 14 4.39823 -0.951057 15 4.71239 -1 16 nan 5.02655 -0.951057 17 nan 5.34071 -0.809017 18 «calculo» 5.65487 -0.587785 19 «calculo» 5.96903 -0.309017 20 «calculo» 21 22 <enter> para continuar.
A interface é muito simples. Em vez de se descrever aqui, optou-se por disponibilizar uma versão oficial do ficheiro executável. Os alunos devem testá-lo e emular a sua interface.
Abaixo apresentam-se três exemplos de interacção do programa com o utilizador.
Edição de folha com cursor na célula (8,2) e com a célula (3,1) marcada para cópia.
Edição de folha depois de ter premido <enter>
sobre a célula (8,2).
Edição de folha depois de ter redimensionado a janela da respectiva consola. Note-se que as duas linhas de informação sobre a célula corrente não são mostradas.
Note-se que:
O trabalho divide-se em duas fases, correspondendo a final da primeira à entrega intermédia prevista no método de avaliação da disciplina. A segunda fase corresponde à entrega definitiva.
Corresponde a um programa que serve de folha de cálculo simplificada, com uma interface trivial. As únicas operações a suportar pela folha são:
Não é obrigatório evitar a análise gramatical antes do cálculo de cada fórmula. Fazê-lo apropriadamente requer noções de hierarquias de classes, necessárias apenas na segunda fase do trabalho.
Não é necessário garantir que, após uma alteração à folha de cálculo, nenhuma célula seja calculada mais do que uma vez, nem tão pouco verificar se existem dependências circulares entre as células. No entanto, recomenda-se que tal seja feito, por forma a adiantar trabalho para a entrega definitiva.
É obrigatória a utilização de uma interface com o programa exactamente
igual à fornecida pela resolução oficial (a única excepção é o
armazenamento da folha em disco, que deverá constar no menu mas não precisará
de ser implementada), disponível através do comando editor_de_folha_oficial
disponível na máquina mercurio
, no directório /usr/local/bin/
.
No mesmo directório encontrará o ficheiro teste.flh
, que contém
os dados de uma folha de cálculo simples (e com erros), que o seu programa
deverá ser capaz de ler. O formato dos ficheiros encontra-se descrito na Secção
4.
Corresponde a um programa que serve de folha de cálculo simplificada, com
uma interface baseada no Slang++
. Os requisitos são:
Termo
que
representa um termo de uma fórmula analisada.Slang++
.É obrigatória a utilização de uma interface com o programa exactamente
igual à fornecida pela resolução oficial, disponível através do comando editor_de_folha_final_oficial
disponível na máquina mercurio
, no directório /usr/local/bin/
.
No mesmo directório encontrará o ficheiro teste.flh
, que contém
os dados de uma folha de cálculo simples (e com erros), que o seu programa
deverá ser capaz de ler. O formato dos ficheiros encontra-se descrito na Secção
4.
O formato dos ficheiros de folhas de cálculo é simples. Na descrição abaixo considere todo o texto após e incluindo o símbolo '%' como sendo comentários, que não deverão surgir num ficheiro real.
3
% número de linhas da folha para as quais se especificam células (células não especificadas assumem-se vazias)
-2
% número da primeira linha para a qual se descrevem células
4
% número de células descritas nesta linha
-4
% número da coluna da primeira célula nesta linha (linha -2)
sin(%pi / 4)
% fórmula da célula na linha -2, coluna -4
0
% número da coluna da segunda célula nesta linha (linha -2)
$0$0 > 0 ? $0$1 : $0$2
% fórmula da célula na linha -2, coluna 0
1
% número da coluna da terceira célula nesta linha (linha -2)
1000.4
% fórmula da célula na linha -2, coluna 1
40
% número da coluna da quarta célula nesta linha (linha -2)
% fórmula (vazia!) da célula na linha -2, coluna 40
% Etc. Aqui surgiriam as descrições das duas linhas seguintes da folha de cálculo.
Ou seja, em primeiro lugar surge o número de linhas descritas. Depois segue-se informação sobre cada umas dessas linhas. A informação sobre uma linha consiste no número de células descritas nessa linha. Depois segue informação acerca das células. A informação acerca das células consiste na indicação da respectiva coluna e da sua fórmula. Todas estas informações são dadas em linhas separadas.
calculo
sem contexto.tar.gz
e inspire-se em calculo
com contexto.tar.gz
), alterando-o se necessário.Pacotes-0.3.tar.gz
.
Instale-as dando os seguintes comandos como administrador:
tar -zxf Pacotes-0.3.tar.gz
cd Pacotes
make
make install
Para poder executar estes programas tem de os copiar para o seu computador e dar o seguinte comando:
chmod +x editor_de_folha_*
il
, (#include <Utilitarios/Manipuladores/ignoradores.H>
e using namepace Utilitarios::Manipuladores
) para ignorar todos
os caracteres encontrados num canal de entrada até ao próximo fim-de-linha.map
da
biblioteca padrão, #include <map>
) para guardar as
células da folha de cálculo (ver referências
na bibliografia da disciplina). Está disponível uma breve
introdução aos mapas.Posicao
para representar posições de
células.Slang++
em
Slang++-0.3.tar.gz
.
Instale-a dando os seguintes comandos como administrador:
tar -zxf Slang++-0.3.tar.gz
cd Slang++
make
make install
Esta secção irá crescendo com outras dicas. Mantenha-se atento.
Folha
, Posicao
e EditorDeFolha
,
para além das já fornecidas (ver calculo
sem contexto.tar.gz
). (1ª e 2ª fases)carregaDe()
, que carrega nova
informação a partir de um canal de entrada (1ª fase), e guardaEm()
,
que
guarda num canal de saída toda a informação (2ª fase). Ver
Notas sobre leitura e escrita em ficheiros.O Trabalho Final será resolvido em grupo, devendo manter-se os mesmos grupos constituídos para o Problema.
Makefile
). Não é
necessário entregar qualquer relatório. Deve também enviar uma
mensagem de correio electrónico claramente identificada (número do grupo e
constituição) com os ficheiros fonte
(.H
, .C
e _impl.H
, caso existam) para Ana.Violante@iscte.pt
(grupos de IGE) ou para Ricardo.Ribeiro@iscte.pt
(grupos de ETI). Grupos mistos poderão enviar a mensagem para qualquer
dos dois endereços (mas apenas para um deles)..C
, ._impl.H
e .H
) e o respectivo ficheiro de
construção (Makefile
);Courier
) e, caso seja possível fazê-lo,
imprima em papel reciclado, frente-e-verso.As datas das orais e das inscrições nas orais serão anunciadas logo que possível.
A nota deste trabalho será dada apenas após uma discussão, individual, com cada um dos elementos do grupo. Nesta discussão qualquer elemento do grupo terá de demonstrar um total conhecimento do programa e ser capaz de operar as alterações que forem pedidas. Nessa oral poderão também ser feitas perguntas sobre a matéria em geral. A nota final poderá depender não só da qualidade do trabalho, mas também, e principalmente, da avaliação que os docentes façam da participação relativa dos alunos na feitura do trabalho.
Quaisquer funcionalidades extra que não tenham sido pedidas no enunciado, tais como menus mais sofisticados etc., não serão avaliadas.
Slang++
Slang++
apresenta
algumas complicações. Acontece que estas aplicações
não podem ser executadas dentro do depurador, pois fazem uso de
capacidades do terminal que este não disponibiliza. Assim,
é necessário executar o programa a depurar numa janela xterm
normal, fora do gdb
, e depois convencer o gdb
a "agarrar-se"
ao programa já em execução. Para isso:
gdb
dentro do Emacs
, como habitualmente, especificando
o ficheiro a depurar. Não dê o comando r[un]
!xterm
.ps -auxww | grep nome_do_programa | grep annnnn
nnnnn
é o seu número de aluno e nome_do_programa
é o nome do programa a depurar. Surgir-lhe-á uma lista
dos processos que são instâncias do seu programa e que lhe
pertencem. É conveniente que tenha apenas um programa em execução
de modo a identificar claramente qual o PID que lhe interessa.
gdb
coloque um ponto de paragem onde for conveniente.
Em seguida dê o comando:attach pid
pid
é o PID do processo identificado na alínea
anterior. Este comando faz com que o gdb
passe a controlar
o processo. Dê o comando:
c[ontinue]