Curso de ScriptVox Intermediário - Aula 15 - Prof. Oswaldo Vernet - iNCE/UFRJ

Esta aula encerra o curso intermediário. Baixem a nova versão do interpretador.

Os comandos SE e ENQUANTO possuem em comum o fato de avaliarem a expressão que
os segue; dependendo do valor obtido nesta avaliação, o fluxo de execução pode
sofrer um desvio para uma linha do script distinta da linha seguinte àquela 
que contém o comando.

A diferença entre estes dois comandos está no aspecto iterativo. O comando
SE em sua versão não compacta fará a avaliação da expressão apenas uma vez, 
tomando a decisão de continuar na linha seguinte se a expressão for verdadeira 
(isto é, diferente de zero) ou de desviar para a linha onde se encontra a 
cláusula SENÃO correspondente, caso ela exista, ou para a linha onde se 
encontra o comando FIM SE correspondente. 

Já o comando ENQUANTO age diferentemente: se a expressão for falsa (isto é, 
igual a zero), o fluxo é desviado para o comando FIM ENQUANTO correspondente; 
se for verdadeira, o fluxo direciona-se para a linha seguinte à do comando 
ENQUANTO, dando início à execução do BLOCO do comando, e prossegue até que o 
comando FIM ENQUANTO correspondente seja atingido; neste momento, ocorre um 
desvio implícito de volta à linha do comando ENQUANTO, causando nova avaliação 
da expressão. Este processo se repetirá até que a expressão seja avaliada como 
falsa (isto é, igual a zero).

A ideia desta aula é examinar atentamente as espécies de expressões que podemos
utilizar nestes dois comandos. Em princípio, elas devem produzir um resultado do tipo
inteiro quando avaliadas, que será considerado falso se for zero ou verdadeiro se
for diferente de zero. É comum encontrar nestas expressões certos operadores ditos
RELACIONAIS, que estabelecem comparações entre valores. São eles: o operador de
igualdade "=", o operador de não igualdade "<>", o operador maior ">", o operador
maior ou igual ">=", o operador menor "<" e o operador menor ou igual "<=".
Todos estes operadores, quando aplicados a valores para os quais a comparação
faça sentido, produzem como resultado o inteiro um (se a comparação for verdadeira)
ou o inteiro zero (se a comparação for falsa).

Além destes seis, existem os operadores ditos de INCLUSÃO, aplicáveis a cadeias ou
a listas, que foram objeto de exame na aula anterior. São eles: o operador "começa por", 
simbolizado por "=*", o operador "termina por", simbolizado por "*=" e o operador "contém",
simbolizado por "*=*". Estes também produzem como resultado os valores zero ou um,
significando falso e verdadeiro, respectivamente.

Para introduzirmos os três operadores que faltam, vamos resolver o seguinte exercício:
construir a função faz_pergunta, que recebe como parâmetro uma cadeia contendo uma pergunta
a ser feita ao usuário. A função deverá escrever na tela a cadeia e, sem mudar de linha,
esperar que o usuário digite sim ou não como resposta. A resposta poderá ser em português
ou em inglês, isto é: se o usuário digitar "S", "SIM", "Y" ou "YES", a função deverá
retornar o inteiro um, significando verdadeiro; se o usuário digitar "N", "NÃO" ou "NO",
a função deverá retornar zero, significando falso. Se o usuário não digitar nenhuma
dessas palavras, o usuário deve ser insultado e a pergunta, repetida. Maiúsculas e 
minúsculas devem ser igualmente tratadas.

Segue-se um primeiro esboço da função faz_pergunta:

* início da função faz_pergunta
função faz_pergunta (pergunta) : resposta
@início
	escreve pergunta &
	lê MAIUSC resposta
	se resposta = "S"   retorna 1
	se resposta = "SIM" retorna 1
	se resposta = "Y"   retorna 1
	se resposta = "YES" retorna 1
	se resposta = "N"   retorna 0
	se resposta = "NÃO" retorna 0
	se resposta = "NO"  retorna 0
	escreve "Imbecil, responde direito!"
	desvia @início
fim função
* fim da função faz_pergunta

A variável "resposta" tem escopo local porque só precisa existir enquanto a função
faz_pergunta estiver sendo executada. Quem chamar a função estará interessado na resposta
zero ou um, e não no que o usuário digitou.

Bom, isto é o que escreveríamos até a versão 5.0 do ScriptVox. Na versão 6.0, introduzimos
os operadores LÓGICOS, que permitem reunir, em uma só expressão, diversos testes.
Vejamos o primeiro deles, que se aplica ao exemplo dado. 

O operador lógico "OU" aplica-se a operandos inteiros e realiza a DISJUNÇÃO LÓGICA entre
seus operandos: se os dois operandos são falsos (isto é, zero), o resultado será falso; 
do contrário, o resultado será verdadeiro. Utilizamos este operador quando desejamos saber se 
pelo menos uma das condições participantes da disjunção é verdadeira, já que ele só produz 
o valor falso se todas forem falsas. 

Portanto, podemos substituir a série de comandos SE no script por apenas dois comandos. 
A nova função faz_pergunta é mostrada a seguir:

* início da função faz_pergunta
função faz_pergunta (pergunta) : resposta
@início
	escreve pergunta &
	lê MAIUSC resposta
	se resposta = "S" ou resposta = "SIM" ou resposta = "Y" ou resposta = "YES" retorna 1
	se resposta = "N" ou resposta = "NÃO" ou resposta = "NO"  retorna 0
	escreve "Imbecil, responde direito!"
	desvia @início
fim função
* fim da função faz_pergunta

Para introduzirmos o segundo operador, vamos a um outro exemplo. Em um script, precisamos
testar se uma pessoa nasceu entre 1950 e 1970. A função testa_ano, detalhada a seguir,
cumpre esta tarefa, retornando verdadeiro caso o ano dado como parâmetro esteja na faixa
especificada ou falso caso contrário:

* início da função testa_ano
função testa_ano (ano)
	se ano < 1950 retorna 0
	se ano > 1970 retorna 0
	retorna 1
fim função
* fim da função testa_ano
  
O operador lógico "E" aplica-se a operandos inteiros e realiza a conjunção lógica entre os
seus operandos, isto é: se um dos operandos é falsos (isto é, zero), o resultado será falso; 
do contrário o resultado será verdadeiro. Utilizamos este operador quando desejamos saber se 
todas as condições participantes da conjunção são verdadeiras, já que ele só produz o valor 
falso se alguma for falsa. 

A função testa_ano pode ser assim reescrita:

* início da função testa_ano
função testa_ano (ano)
	se ano >= 1950 e ano <= 1970 retorna 1
	retorna 0
fim função
* fim da função testa_ano

Ou ainda, de forma mais compacta:

* início da função testa_ano
função testa_ano (ano)
	retorna ano >= 1950 e ano <= 1970
fim função
* fim da função testa_ano

A conjunção lógica tem precedência sobre a disjunção; ou seja, o operador "e" tem precedência 
sobre o operador "ou". Portanto, na expressão a seguir:

x > 0 ou y >= 0 e y <= 3

a disjunção não será entre as condições "x > 0" e "y >= 0", como aparenta, mas entre a condição
"x > 0" e o resultado da conjunção entre "y >= 0" e "y <= 3". Na dúvida, use parênteses para 
impor a ordem de avaliação que você desejar.

Um último exemplo nos levará a uma expressão mista em que os parênteses serão necessários para
impor uma ordem de avaliação distinta da que é imposta pela precedência natural entre os operadores 
"e" e "ou".

Devemos construir a função "bissexto", que recebe como parâmetro um inteiro e testa se ele 
correspnode a um ano bissexto; se for, a função deverá retornar um; se não for, deverá retornar
zero.

Sabemos que um ano bissexto é necessariamente múltiplo de 4. Porém, nem todos os anos múltiplos
de 4 são bissextos. Por exemplo: 1900 não foi bissexto, mas 2000 foi. A regra é a seguinte:
para que um ano seja bissexto ele deve ser múltiplo de 4; se, além disso, ele for também 
múltiplo de 100, a centena (isto é, o quociente do ano por 100) deve ser par.

Para testar se um número é múltiplo de outro, usamos o operador RESTO DA DIVISÃO, simbolizado
por "%". Assim, um número X será múltiplo de Y se, e somente se, o resto da divisão de X por
Y for zero. Portanto, se o resto for diferente de zero, é porque X não é múltiplo de Y.

Então, nosso raciocínio para construir a função é o seguinte: se o ano não for múltiplo de 4,
certamente ele não será bissexto e, neste caso, retornamos zero. Se ele for múltiplo de 4, 
ele poderá ou não ser bissexto. Temos que verificar se ele também é múltiplo de 100.  Se não
for, ele é um ano bissexto; se for, devemos verificar se o quociente do ano por cem é par,
ou seja, múltiplo de 2. Se for par, o ano é bissexto; se não for, o ano não é bissexto.

A função ficaria assim: 

* início da função bissexto
função bissexto (ano)
	se ano % 4 <> 0   retorna 0         ; se não é múltiplo de 4, não é bissexto
* a execução só chega aqui se o ano for múltiplo de 4
	se ano % 100 <> 0 retorna 1			; se é múltiplo de 4 mas não é de 100, é bissexto
* a execução só chega aqui se o ano for múltiplo 100 (e, portanto, também múltiplo de 4)
	se (ano / 100) % 2 = 0 retorna 1	; se é múltiplo de 4 e de 100 com centena par, é bissexto
* a execução só chega aqui se o ano for múltiplo de 100 (e também de 4, é claro) com centena ímpar
	retorna 0							; se é múltiplo de 4 e de 100 com centena ímpar, não é bissexto
fim função 
* início da função bissexto

Utilizando os operadores "e" e "ou", a função bissexto pode ser assim reescrita:

* início da função bissexto
função bissexto (ano)
	se ano % 4 = 0 e (ano % 100 <> 0 ou (ano / 100) % 2 = 0) retorna 1
	retorna 0
fim função 
* início da função bissexto

Observando mais atentamente esta última versão da função bissexto, podemos simplificá-la
ainda mais:

* início da função bissexto
função bissexto (ano)
	retorna  ano % 4 = 0 e (ano % 100 <> 0 ou (ano / 100) % 2 = 0)
fim função 
* início da função bissexto


EXERCÍCIOS

Exercícios de Estudo Dirigido

1. Utilizando o operador "contém", aplicado a listas, as expressões que aparecem nos comandos SE da
   versão melhorada da função faz_pergunta podem ser simplificadas. Mostre como.
				
2. Faça o mesmo para a função faz_pergunta.

3. O operador unário de negação lógica, simbolizado pelo identificador "NÃO", tem o seguinte
   efeito: se o operando que o segue for verdadeiro, o operador produz o resultado falso e
   vice-versa. O Teorema de De Morgan (o segundo De não está repetido, faz parte do nome do
   matemático), conhecido na lógica, permite converter uma conjunção lógica na negação de uma
   disjunção, e vice-versa. Por exemplo, a expressão

		x > 3 e x < 10

   equivale a

		não (x <= 3 ou x >= 10)

   Da mesma forma, a expressão

        x < 10 ou x > 20

   equivale a

        não (x >= 10 e x <= 20)

   Pesquise sobre o Teorema de De Morgan.


Exercício de avaliação (enviar para scriptvox@gmail.com até o meio-dia de 12 de março de 2012)

Escreva um script que lê do teclado duas datas, ambas no formato dd/mm/aaaa. O script deverá testar
se a primeira data é anterior à segunda e, em caso afirmativo, calcular o número de dias decorridos
entre as duas. Por exemplo, se as datas forem 01/03/1920 e 05/03/1920, a resposta deverá ser 4.
Se a primeira data for igual ou posterior à segunda, o script deverá apenas relatar este fato.

Cuidado com os anos bissextos!

Bom estudo! 

Oswaldo Vernet
