2016-07-31 3 views
4

Je dois implémenter une boucle idefinite avec plusieurs points de sortie. Malheureusement, la solution la plus évidente - REPEAT - JUSQU'à plusieurs WHILE ne fonctionne pas dans Gforth ni dans swapforth (Bien sûr, la boucle dans l'exemple ci-dessous peut être implémentée avec DO-LOOP, mais ce n'est qu'une démonstration. le vrai problème est lié au contrôle du matériel dans un système embarqué, de sorte que la boucle doit en effet être indéfinie):Forth: boucle indéfinie portable avec plusieurs points de sortie

: test1 (step -- step count) 
    0 
    begin 
     over + 
     dup . 
     dup 20 < while 
     dup 13 = while 
    repeat 
; 

3 test1 

dans « Penser Forth » il y a la déclaration de Moore cité:

Plusieurs fois conditionals sont utilisés pour sortir des boucles. Cette utilisation particulière peut être évitée en ayant des boucles avec plusieurs points de sortie. C'est un sujet en direct, en raison de la construction multiple WHILE qui est en poly-Forth mais n'a pas percolé jusqu'à Forth '83. C'est un moyen simple de définir plusieurs WHILEs dans le même REPEAT . Aussi Dean Sanderson [of Forth, Inc.] a inventé une nouvelle construction qui introduit deux points de sortie à une DO LOOP. Étant donné cette construction, vous aurez moins de tests.

Malheureusement, je n'ai pas réussi à trouver la solution de Dean. Existe-t-il un moyen portable d'implémenter plusieurs points de sortie dans la boucle indéfinie dans Forth?

+2

BTW, plusieurs 'WHILE' fonctionne dans n'importe quel ANS Forth - il doit simplement être résolu avec un autre' THEN', [un exemple] (https://forth-standard.org/standard/core/WHILE) est fourni même dans la norme. – ruvim

+0

Merci pour votre commentaire, en effet il y a une telle option. Je l'ai testé avec plus de deux WHILE et cela fonctionne. Cependant il semble qu'il soit plus difficile d'assigner des actions pour différentes raisons de quitter la boucle. J'ai créé la réponse montrant cette solution. – wzab

Répondre

2

Après quelques expériences, j'ai créé une solution basée sur DO + LOOP. Je ne sais pas si c'est le même que celui proposé par Dean Sanderson. Je l'ai testé avec succès à Gforth et en swapforth. Il semble qu'il est possible de créer le nombre arbitraire de points de sortie. La boucle indéfinie est créée via: 0 1 DO loop content ici 0 + LOOP. Les points de sortie sont créés par LEAVE placé dans IF THEN.

code Exemple:

: test1 (start step -- count step) 
    swap 
    1 0 do 
     over + 
     dup . 
     dup 20 > if 
     ." >20 " 
     leave 
     then 
     dup 13 = if 
     ." =13 " 
     leave 
     then 
     dup 17 = if 
     ." =17 " 
     leave 
     then 
    0 +loop 
; 

résultats des tests:

> 1 3 test1 
4 7 10 13 =13 ok 
> 2 3 test1 
5 8 11 14 17 =17 ok 
> 0 3 test1 
3 6 9 12 15 18 21 >20 ok 
+0

"Trouver une solution" pourrait signifier "J'ai trouvé une solution écrite par quelqu'un d'autre et l'ai copiée ici", ou "J'ai créé une solution". Précisez s'il vous plaît. – agc

+0

Eh bien, j'ai trouvé cette solution en expérimentant différentes syntaxes possibles de boucles indéfinies. Donc, en fait, je l'ai "créé" ou "inventé". Cependant, je ne suis pas sûr que personne ne l'ait inventé auparavant. Je pense en particulier que la solution de Sanderson mentionnée par Chuck Moore peut être similaire ou même la même. Malheureusement, je ne peux pas le trouver. – wzab

+1

Un seul point de sortie * gforth *, plusieurs tests: ': test2 (début d'étape - pas de comptage) cr swap début dup 20 < over 13 <> * plus de 17 <> * tant que terminé + dup. répétez swap; 'Pas aussi polyvalent que plusieurs points de sortie, car il ne peut pas retourner le test de sortie spécifique. – agc

2

EXIT de cours offre plusieurs sorties à une définition. Vous pouvez rendre le corps de la boucle une seule et même avec une définition soit en ayant un mot séparé ou, plus nettement, en utilisant des citations:

: test (start step -- count step) 
    swap [: begin 
    over + dup . 
    dup 20 > if ." >20" exit then 
    dup 13 = if ." =13" exit then 
    dup 17 = if ." =17" exit then 
    again ;] execute 
    (EXITs from loop continue here) ; 
1

Baser sur le commentaire donné par ruvim, je l'ai testé une solution sur la base de plusieurs WHILE résolu avec plus de THEN:

: test1 (step start -- step count) 
    cr 
    begin 
     over + 
     dup . cr 
     dup 30 < while 
     dup 13 <> while 
     dup 17 <> while 
    repeat 
     ." before 1st else" cr 
    else 
     ." after 1st else" cr 
    then 
     ." before 2nd else" cr 
    else 
     ." after 2nd else" cr 
    then 
; 

En effet cela fonctionne. Les tests ci-dessous montrent quelles sections du code sont exécutées pour différentes raisons de quitter la boucle.

boucle est sortie après le 1er temps:

5 1 test1 
6 
11 
16 
21 
26 
31 
after 2nd else 
ok 

boucle est sorti après le 2ème temps:

5 3 test1 
8 
13 
after 1st else 
before 2nd else 
ok 

boucle est sortie après le 3ème temps:

5 2 test1 
7 
12 
17 
before 1st else 
before 2nd else 
ok 

Donc, si quelqu'un veut pour affecter l'action à chaque WHILE, cela doit être fait comme suit:

: test1 (step start -- step count) 
    cr 
    begin 
     over + 
     dup . cr 
     dup 30 < while 
     dup 13 <> while 
     dup 17 <> while 
    repeat 
    ." exited after the 3rd while" cr 
    else 
    ." exited after the 2nd while" cr 
    then 
    else 
    ." exited after the 1st while" cr 
    then 
; 

La chose intéressante serait de savoir comment les échelles ci-dessus pour encore plus de temps. La syntaxe qui fonctionne pour 4 Whiles est illustré ci-dessous:

: test1 (step start -- step count) 
    cr 
    begin 
     over + 
     dup . cr 
     dup 30 < while 
     dup 13 <> while 
     dup 17 <> while 
     dup 19 <> while 
    repeat 
    ." exited after the 4th while" cr 
    else 
    ." exited after the 3nd while" cr 
    then 
    else 
    ." exited after the 2nd while" cr 
    then 
    else 
    ." exited after the 1st while" cr 
    then 
; 

Le code ci-dessus a été testé à la fois dans gforth et swapforth. La question intéressante est l'occupation de la pile de retour dans différentes solutions possibles. (Par exemple, dans la CPU J1B, la profondeur de la pile de retour n'est que de 32 niveaux).