Discussion:
Transformer un String en Character pour un case
(trop ancien pour répondre)
k***@gmail.com
2017-05-26 18:47:43 UTC
Permalink
Bonjour,

Par avance je m'excuse de mon ignorance mais Ada est un langage somme toute compliqué, mes connaissances en programmation se limitent aux concepts simples (condition, variable et constante, un tout petit peu de POO...) que j'ai appris en faisant un peu de Python ou de PHP (deux langages que je ne maîtrise pas du tout soit dit en passant).

OS: Debian 8 64 bits
Compilateur: GNAT 4.9 (dépôts Debian)
Éditeur: vim 2.7.4

Comme premier projet je m'amuse à coder une calculatrice. J'ai obtenu une version fonctionnelle, mais qui ne gère que des entiers, les opérateurs "+", "-", "/", "*", et à priori des nombres de petites tailles. Elle est mal écrite et a des failles évidentes de conceptions.

Avant de passer à la suite, aka améliorer mon code (float, grand nombre, plus d'opérateurs, usage de meilleurs pratique etc) j'aimerai changer ma condition if (voir code ici: https://paste.debian.net/hidden/4e60928d/, notez que j'ai renommé mes variables) par un case.

Or, case ne gère pas de String (obtenu par Ada.Text_IO.Get_Line) mais des types discret (si je ne m'abuse, du genre Character). Donc j'ai voulu modifier mon code, dont voici la version (non fonctionnelle) actuelle:

with Ada.Text_IO;

procedure Main is

type Math_Operators is ('+', '-', 'x', '/');

-- Operator : Math_Operators;
Operator : String (1 .. 1);
First_Number, Second_Number, Result : Integer;

-- Check if the user input (for mathematical operator) is
-- a one length value
function Checking_Operator_And_Change_Type return Math_Operators is
begin
if Operator'Length = 1 then
return Math_Operators (Math_Operators'First);
else
raise Constraint_Error;
end if;
end Checking_Operator_And_Change_Type;

begin
-- Ask the user to assign an integer to variable A
Ada.Text_IO.Put_Line ("ENTER AN Integer:");
First_Number := Integer'Value (Ada.Text_IO.Get_Line);
Ada.Text_IO.New_Line;

-- Ask the user to assign a mathematical Operator (string) to mathOperator
Ada.Text_IO.Put_Line ("CHOOSE A MATHEMATICAL OPERATOR: '+', '-', '/', '*'");
Operator := Ada.Text_IO.Get_Line;
-- I HAVE TO MAKE SOMETHING WITH THE RETURNED VALUE
-- A FUNCTION RETURN A VALUE
-- I CAN'T IGNORE THIS RETURNED VALUE!

Ada.Text_IO.New_Line;

-- Ask the user to assign an integer to variable Bet
Ada.Text_IO.Put_Line ("ENTER ANOTHER INTEGER:");
Second_Number := Integer'Value (Ada.Text_IO.Get_Line);
Ada.Text_IO.New_Line;

-- Calculate the result
case Operator is
when "+" =>
Result := First_Number + Second_Number;
when "-" =>
Result := First_Number - Second_Number;
when "*" =>
Result := First_Number * Second_Number;
when "/" =>
Result := First_Number / Second_Number;
end case;

-- Calculate the result
-- if Operator = "+" then
-- Result := First_Number + Second_Number;
-- elsif Operator = "-" then
-- Result := First_Number - Second_Number;
-- elsif Operator = "*" then
-- Result := First_Number * Second_Number;
-- elsif Operator = "/" then
-- Result := First_Number / Second_Number;
-- end if;

-- Display the result
Ada.Text_IO.Put_Line("RESULT:");
Ada.Text_IO.Put_Line (">" & Integer'Image (First_Number) & " " & Operator & Integer'Image (Second_Number) & " =" & Integer'Image (Result));
end Main;

Ce code produit à la compilation cette erreur:

$ gnat make main.adb
gcc-4.9 -c main.adb
main.adb:43:14: expected a discrete type
main.adb:43:14: found type "Standard.String"
gnatmake: "main.adb" compilation error

De ce que j'en comprend, case attend bel et bien un type discret (ou Character, de ce que j'ai retenu d'une discussion sur #***@irc.freenode.org).

On m'a donc indiqué que l'idéal serait de créer un type, comme Math_Operators auquel j'attribue mes opérateurs mathématique ("+", "-", "x", "/"), je récupère via Ada.text_IO.Get_Line (qui donne un String) l'opérateur du choix de l'utilisateur (en testant sa longueur, d'où la fonction Checking_Operator_And_Change_Type, dont je n'arrive pas à me servir et qui au delà de checker la longueur est censé me sortir un Character avec le return) et le rend utilisable pour le case en le rendant du type Math_Operator (qui est, je crois, un sous-type de Character, et est donc compatible avec case).

Sans nécessairement me donner la réponse ou éditer mon code, auriez-vous une indication qui m'aiderait à avancer? J'ai beau lire de la documentation sur wikibooks.org, des manuels de référence ainsi que googler, j'arrive pas à trouver mon bonheur.

Si vous avez besoin de plus d'informations, n'hésitez pas.

PS: Je sais qu'une énorme part de l'apprentissage de l'Ada concerne le Typage, j'y travail, mais j'ai besoin de cas concret plus que de lecture pour comprendre. Cependant si vous avez un bon lien... Je suis preneur ;).


Cordialement,
Kévin GASPARD
Pascal Obry
2017-05-27 10:10:54 UTC
Permalink
Salut Kévin,
Post by k***@gmail.com
with Ada.Text_IO;
procedure Main is
   type Math_Operators is ('+', '-', 'x', '/');
   -- Operator : Math_Operators;
   Operator : String (1 .. 1);
First_Number, Second_Number, Result : Integer;
Operator est une chaîne de charactère, de longueur 1 mais une chaîne.
Post by k***@gmail.com
-- Check if the user input (for mathematical operator) is
-- a one length value
function Checking_Operator_And_Change_Type return
Math_Operators is
begin 
if Operator'Length = 1 then
return Math_Operators (Math_Operators'First);
else
raise Constraint_Error;
end if;
end Checking_Operator_And_Change_Type;
begin
   -- Ask the user to assign an integer to variable A
   Ada.Text_IO.Put_Line ("ENTER AN Integer:");
   First_Number := Integer'Value (Ada.Text_IO.Get_Line);
   Ada.Text_IO.New_Line;
   -- Ask the user to assign a mathematical Operator (string) to
mathOperator
   Ada.Text_IO.Put_Line ("CHOOSE A MATHEMATICAL OPERATOR: '+', '-',
'/', '*'");
Operator := Ada.Text_IO.Get_Line;
-- I HAVE TO MAKE SOMETHING WITH THE RETURNED VALUE
-- A FUNCTION RETURN A VALUE
-- I CAN'T IGNORE THIS RETURNED VALUE!
   
   Ada.Text_IO.New_Line;
   -- Ask the user to assign an integer to variable Bet
   Ada.Text_IO.Put_Line ("ENTER ANOTHER INTEGER:");
   Second_Number := Integer'Value (Ada.Text_IO.Get_Line);
   Ada.Text_IO.New_Line;
-- Calculate the result
case Operator is
Une chaîne de caractère, donc pas supporté par case. Une solution:

case Operator (1) is
Post by k***@gmail.com
when "+" =>
et (simple quote).

when '+' =>

...

Mais pourquoi ne pas déclarer Operator:

Operator : Character;

Cordialement,
--
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://www.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B
GASPARD Kévin
2017-05-27 18:44:17 UTC
Permalink
Bonjour Pascal et merci pour la réponse.
Post by Pascal Obry
Operator est une chaîne de charactère, de longueur 1 mais une chaîne.
case Operator (1) is
Post by k***@gmail.com
when "+" =>
et (simple quote).
when '+' =>
...
En lisant cela l'idée me paraissait bonne et je me demandais pourquoi je n'y avais pas pensé tout seul, puisque si je ne m'abuse un array contient différents types de valeur (dont même un array en fonction des langages). Cependant:

gcc-4.9 -c main.adb
main.adb:26:09: missing case values: character'val(0) .. '@'
main.adb:26:09: missing case values: 'B' .. character'val(255)
main.adb:26:14: subtype of expression is not static, alternatives must cover base type
main.adb:27:22: expected type "Standard.Character"
main.adb:27:22: found a string type
main.adb:29:22: expected type "Standard.Character"
main.adb:29:22: found a string type
main.adb:29:22: duplication of choice value: 'A' at line 27
main.adb:31:22: expected type "Standard.Character"
main.adb:31:22: found a string type
main.adb:31:22: duplication of choice value: 'A' at line 29
main.adb:33:22: expected type "Standard.Character"
main.adb:33:22: found a string type
main.adb:33:22: duplication of choice value: 'A' at line 29
gnatmake: "main.adb" compilation error

Au passage j'ai modifié mon code pour l'épurer un peu, il devenait illisible avec le surplus de commentaire et les notes que je conservais, voici la version actuelle:

with Ada.Text_IO;

procedure Main is

Operator : String (1 .. 1);
First_Number, Second_Number, Result : Integer;

begin
-- Ask the user to assign an integer to variable A
Ada.Text_IO.Put_Line ("ENTER AN INTEGER:");
First_Number := Integer'Value (Ada.Text_IO.Get_Line);
Ada.Text_IO.New_Line;

-- Ask the user to assign a mathematical Operator (string) to mathOperator
Ada.Text_IO.Put_Line ("CHOOSE A MATHEMATICAL OPERATOR: '+', '-', '/', '*'");
Operator := Ada.Text_IO.Get_Line;

Ada.Text_IO.New_Line;

-- Ask the user to assign an integer to variable B
Ada.Text_IO.Put_Line ("ENTER ANOTHER Integer:");
Second_Number := Integer'Value (Ada.Text_IO.Get_Line);
Ada.Text_IO.New_Line;

-- Calculate the result
case Operator(1) is
when "+" =>
Result := First_Number + Second_Number;
when "-" =>
Result := First_Number - Second_Number;
when "*" =>
Result := First_Number * Second_Number;
when "/" =>
Result := First_Number / Second_Number;
end case;

-- Display the result
Ada.Text_IO.Put_Line("RESULT:");
Ada.Text_IO.Put_Line (">" & Integer'Image (First_Number) & " " & Operator & Integer'Image (Second_Number) & " =" & Integer'Image (Result));
end Main;

On peut donc constater que GNAT a un problème avec Operator(1).
Post by Pascal Obry
Operator : Character;
C'est l'idée que j'ai sans doute essayé à la base, mais encore une fois ça ne fonctionne pas (en l'état):

procedure Main is

-- Operator : String (1 .. 1);
Operator : Character;
First_Number, Second_Number, Result : Integer;

begin
(...)

J'obtiens en compilant:

gcc-4.9 -c main.adb
main.adb:17:32: expected type "Standard.Character"
main.adb:17:32: found type "Standard.String"
main.adb:27:14: array type required in indexed component
gnatmake: "main.adb" compilation error

Et c'est certainement se résultat qui m'a conduit à déclarer Operator comme un String dont le range est de (1 .. 1).

Sur #***@irc.freenode.org il me semble bien que l'on m'avait conseillé de changer le type d'Operator *après* avoir récupérer son contenu via Ada.Text_IO.Get_Line en faisant une fonction, sûrement mal foutu elle aussi d'ailleurs (voir le code de mon poste original).

Cordialement,
GASPARD Kévin
J-P. Rosen
2017-05-28 04:03:19 UTC
Permalink
Post by GASPARD Kévin
Bonjour Pascal et merci pour la réponse.
Post by Pascal Obry
Operator est une chaîne de charactère, de longueur 1 mais une chaîne.
case Operator (1) is
Post by k***@gmail.com
when "+" =>
gcc-4.9 -c main.adb
main.adb:26:09: missing case values: 'B' .. character'val(255)
Ada demande que toutes les valeurs possibles soient fournies pour un
case (et c'est même une fonction très appréciée du langage, qui évite
bien des bugs). Donc, le compilateur te demande: "qu'est-ce que je dois
faire, si jamais le caractère n'est pas '+', '-', '*' ou '/' ?

Si tu veux l'ignorer, il faut le dire explicitement avec un
when others => null;

(mais il vaudrait mieux vraisemblablement faire une erreur)
Post by GASPARD Kévin
main.adb:27:22: expected type "Standard.Character"
main.adb:27:22: found a string type
"+" est une chaine de caractère à un seul élément, un caractère s'écrit
'+' (simple quote)
Post by GASPARD Kévin
Au passage j'ai modifié mon code pour l'épurer un peu, il devenait
illisible avec le surplus de commentaire et les notes que je
Post by Pascal Obry
Operator : Character;
[...]
Post by GASPARD Kévin
gcc-4.9 -c main.adb
main.adb:17:32: expected type "Standard.Character"
main.adb:17:32: found type "Standard.String"
main.adb:27:14: array type required in indexed component
case Operator (1) is
Si c'est un caractère, il n'y a plus besoin de l'indexer:
case Operator is
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
GASPARD Kévin
2017-05-28 09:21:35 UTC
Permalink
Bonjour J-P, merci pour ta réponse.
Post by J-P. Rosen
Post by k***@gmail.com
gcc-4.9 -c main.adb
main.adb:26:09: missing case values: 'B' .. character'val(255)
Ada demande que toutes les valeurs possibles soient fournies pour un
case (et c'est même une fonction très appréciée du langage, qui évite
bien des bugs). Donc, le compilateur te demande: "qu'est-ce que je dois
faire, si jamais le caractère n'est pas '+', '-', '*' ou '/' ?
Si tu veux l'ignorer, il faut le dire explicitement avec un
when others => null;
C'est logique, à la base quand ma calculatrice n'était qu'un fœtus je gérais les others mais je me suis rendu compte qu'Ada naturellement était mécontent si tu lui donnait autre chose que ces quatre valeurs là.
J'aurai du laisser mon others en me disant qu'il ne fallait pas que je laisse ne serais-ce qu'une possibilité de laisser passer une erreur sans la gérer explicitement. Je note.
Post by J-P. Rosen
(mais il vaudrait mieux vraisemblablement faire une erreur)
Selon wikibooks.org, j'ai quatre possibilités d'exceptions:
(https://en.wikibooks.org/wiki/Ada_Programming/Exceptions#Predefined_exceptions)

- Constraint_Error
- Program_Error
- Storage_Error
- Tasking_Error

Je suppose que c'est un Constraint_Error, en gros l'entrée de l'utilisateur est "out of range" de ce qui est attendu par le programme?

Mais le mieux, ne serait-il pas de dire à l'utilisateur que son entrée est incorrecte et le ré-inviter à taper un opérateur autorisé? Ça éviterai de fermer le programme en générant un abandon.

Je pars du principe que ce sujet précis est résolu, je vais ouvrir un autre sujet sur ces dernières questions si je ne trouve pas de réponse par moi-même (et penserait à amener la réponse ici si ça peut servir à quelqu'un d'autre), même si en fait je n'ai pas fais de conversion.

Je vous remercie tout les deux pour votre aide :-) !

Cordialement,
GASPARD Kévin
J-P. Rosen
2017-05-29 04:58:55 UTC
Permalink
Post by GASPARD Kévin
(https://en.wikibooks.org/wiki/Ada_Programming/Exceptions#Predefined_exceptions)
- Constraint_Error
- Program_Error
- Storage_Error
- Tasking_Error
Je suppose que c'est un Constraint_Error, en gros l'entrée de
l'utilisateur est "out of range" de ce qui est attendu par le
programme?Ca, ce sont les exceptions prédéfinies, mais tu peux en déclarer une à toi.
Mais le mieux, ne serait-il pas de dire à l'utilisateur que son
entrée est incorrecte et le ré-inviter à taper un opérateur autorisé?
Ça éviterai de fermer le programme en générant un abandon.Bien sûr, mais je disais "faire une erreur", pas nécessairement "lever
une exception". Dire "opérateur inconnu, recommencez" c'est une erreur
du point de vue de l'utilisateur.

Les exceptions sont un moyen (parmi d'autres) de gérer les erreurs...
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
Pascal Obry
2017-05-28 16:02:03 UTC
Permalink
   -- Calculate the result
   case Operator(1) is
      when "+" =>
         Result := First_Number + Second_Number;
Comme indiqué dans mon précédent message tu dois dans tous les cas
changer "+" en '+' (simple quote).
--
  Pascal Obry /  Magny Les Hameaux (78)

  The best way to travel is by means of imagination

  http://www.obry.net

  gpg --keyserver keys.gnupg.net --recv-key F949BD3B
GASPARD Kévin
2017-05-28 16:44:55 UTC
Permalink
Post by Pascal Obry
   -- Calculate the result
   case Operator(1) is
      when "+" =>
         Result := First_Number + Second_Number;
Comme indiqué dans mon précédent message tu dois dans tous les cas
changer "+" en '+' (simple quote).
Merci pour la précision, j'en ai pas parlé et j'ai effectivement eu une de compilation erreur jusqu'à ce que je le fasse:

expected type "Standard.Character"
found a string type

À partir de ça j'en conclu que le choix du guillemet et du guillemet double change le type que j'obtiens.

Le double guillemet me donne un String (donc un array), tandis que le simple me donne bien un Character "pur".

Désormais je m'attaque à un autre problème: gérer les nombres flottants (avec une certaine précision décimale) et de grandes tailles. Je continue un peu dessus et si je coince sur la méthode à adopter je reviendrai sûrement ici pour créer un autre sujet.

Je pense qu'on peut dire que ce sujet est clos et résolu à moins que vous ayez encore autre chose à m'indiquer :-).

Cordialement,
GASPARD Kévin
J-P. Rosen
2017-05-29 05:00:20 UTC
Permalink
Post by GASPARD Kévin
Désormais je m'attaque à un autre problème: gérer les nombres flottants (avec une certaine précision décimale) et de grandes tailles. Je continue un peu dessus et si je coince sur la méthode à adopter je reviendrai sûrement ici pour créer un autre sujet.
Hint: Float_IO ...
--
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr
Continuer la lecture sur narkive:
Loading...