linkakro le 11/07/2011 à 17:59
(edit global 15/3/2013)
(edit mineur 31/12/2013)
La mauvaise utilisation des Goto ou des Menu dans des boucles/alternatives peut provoquer des bugs ou un ralentissement.
D'une manière générale, la moindre manipulation perturbant des End peut poser problème.
Mais le grand classique demeure l'excès de Goto.
Toutefois les bugs peuvent être exploités volontairement à condition de savoir ce qu'on fait !
Par exemple, le tuto suivant du sdz explique comment se servir volontairement de certains bugs.
http://www.siteduzero.com/tuto[...]ec-les-end.html
edit --- ce n'est plus site du zero mais OpenClassrooms
Mon objectif ici est d'exposer les Bugs et d'expliquer le phénomène
D'ailleurs ce phénomène
devrait se produire dans tous les languages interprétés (=sans compilation) possédant le Goto sans le surveiller.
EDIT : 23/5/2013 : autre sujet dans un cas typique, et explication par quelqu'un d'autre que moi.
http://tout82.free.fr/forum/sujet.php?sujet=3788
===== Principe
La calculatrice semble garder en mémoire chaque boucle/alternative ouverte dans un programme jusqu'à l'arrêt du programme.
Quand la calculatrice rencontre un End, elle ferme la dernière boucle/alternative ouverte.
(lors de l'arrêt elle ferme tout)
Or les Goto empêchent la calculatrice de lire toutes les instructions du code.
Donc il arrive que des boucles ne soient pas fermées.
Ou encore qu'on en ouvre une plusieurs fois.
De plus End est la seule instruction qui permette de fermer les boucles/alternatives, donc il peut y avoir des confusions.
===== Remarque
Une alternative utilise un Then.
Un If seul ne se comporte pas comme une alternative.
En effet le If ne stocke pas d'information dans la pile.
Il faut le combiner à Then et [ End ou Else ] pour obtenir une alternative.
Cela permet de modifier le comportement sans avoir besoin de End plus tard.
===== Conséquence 1 : ralenti
Si on ne ferme pas les boucles/alternatives, la calculatrice ralentit jusqu'à saturation mémoire.
C'est le problème classique des jeux snake ratés.
Code
Lbl A
If B
Then // cette alternative ne sera pas fermée après execution
Goto A
End // non lu si B est vrai
Bonus : Remarquez que le End de cet exemple est
facultatif s'il est à la fin. Sinon TOUTE la fin du programme est ignorée pour B faux.
===== Conséquence 2 : confusion
Quand le Goto envoie hors d'une boucle/alternative :
Le prochain End rencontré (quel qu'il soit) sera interprété comme fin de la précédente boucle/alternative quittée même s'il n'a aucun rapport.
Si le Goto envoie hors d'un Then (alternative) :
SOIT : Le prochain End est sans effet
SOIT : Le prochain Else provoquera un saut jusqu'au prochain End (quel qu'il soit)
Code
If 1
Then
Goto A
End // sans importance
// ailleurs dans le programme ... voir même avant !!! //
For // boucle quelconque
Lbl A
... // rien ou des boucles refermées
End // ne fait rien (comme une fin de If), alors qu'il devrait renvoyer au For
Code
For(W,1,2
If 1
Then
Goto 1
End
Lbl 1
... // rien ou des boucles refermées
End // ce End ferme le If , alors qu'il devrait renvoyer au For
Si le Goto envoie hors d'une boucle :
SOIT :
le prochain End provoquera un retour au début de la boucle
SOIT : il ne se passe rien
Consulter la section "usage volontaire" qui utilise cela.
===== Usage volontaire (routines et boucles)
(voir
tuto sdz indiqué en lien et
conséquence 2 (confusion))
Code
Goto 0
Lbl 1
End //ramène au while 1
Lbl 0
While 1
Goto 1
Remarque (edit 3/3/12) :
On peut perturber des boucles sans Goto comme dans cet exemple suivant.
Code
While 1
If A
End //ramène au début si la condition A est vraie
If B
End // idem, condition B
Ne pas exploiter ce bug n'importe quand... surtout pas dans une autre boucle si on ne referme pas.
Code
If
Then
For(
...
If
End // Ce End est soumis au If, comme précédemment
End // TANTOT MARCHE, TANTOT CONFONDU AVEC LE PRECEDENT
Tiré du tutoriel d'OpenClassrooms >>> ROUTINE FACILE
Code
...
For(A,1,2 // execution routine
If A-2
Goto 0
End
...// fin programme
Stop
Lbl 0
... // routine
End // retour
Remarque ajoutée 31/12/2013 :
Si vous voulez créer des routines de cette manière et que cela soit rapide, vous avez intérêt à placer le Label le plus tôt possible dans le programme, ou bien que cela soit à l'intérieur d'un programme court.
CONTOURNER DES BUGS :
(n'hésitez pas à me proposer de nouveaux exemples)
(edit 24/6/12)
Pour pouvoir quitter une boucle sans provoquer de bug, il suffit parfois d'appeler un programme dans un autre et de quitter avec la commande Return.
En effet l'arrêt d'un programme (même appelé) libère la mémoire vive de ses boucles.
Code
Code
// programme BOUCLE
While 1
Return // quitte le programme donc la boucle, sans bug
End
Return // sous-entendu car à la fin
--- (edit 15/02/12)
Répartir différemment les instructions pour extraire le(s) Goto(s)
Code
If A
Then
...
Goto 0 // supprimmer
Else
...
Goto 0 // supprimmer
End
Goto 0 // ajouter
Utiliser le fait qu'un If seul ne se comporte pas comme un alternative pour extraire le Goto.
Code
Code
If A
Then
... // algo ne modifiant pas les données du test A
Goto 0
End
devient
Code
If A
Then
... // algo ne modifiant pas les données du test A
End
If A // même test que juste au dessus
Goto 0
Fonctionne aussi avec un Else dans la structure tant que les instructions contenues n'influencent pas le test.
linkakro le 11/07/2011 à 18:18
Ton observation des For est correcte.
Cependant la cause du bug n'est pas toujours la définition de la boucle.
La calculatrice garde en mémoire chaque boucle ouverte.
Quand elle lit un End, elle ferme la dernière boucle qu'elle se souvient avoir ouverte.
Si la dernière boucle ouverte est Then, alors le End ferme le Then au lieu de sa boucle.
Code
For(W,1,2
If 1
Then
Goto 1
End
Lbl 1
End // ce End n'est pas reconnu
PS: c'est le bug que j'ai combattu dans mon STOECHIO
linkakro le 09/06/2012 à 14:56
Pas exactement.
Lorsque la TI lit le goto, elle doit avoir en mémoire l'ouverture du If précédent, et seulement lui, car l'autre boucle avait déjà été refermée.
Lorsqu'elle atteind le Lbl 1 en sortant du goto, elle lit un End qu'elle interprête comme la fin du dernier If ouvert, c'est-à-dire le deuxième !
Code
If ...
Then // ouvert 1 fois
Lbl 1
End // ferme le premier then la première fois // ferme ensuite le deuxième
If ...
Then // ouvert
Goto 1
Dans cet exemple complémentaire, on voit que le End n'est pas reconnu car aucune boucle n'est en mémoire.
Code
If ...
Then // ouvert 1 fois
Lbl 1
End // provoque une erreur la deuxième fois !
Goto 1