Page 1 sur 1

Boucle FORD NEXTD imbriquée pas variable et réel

Publié : sam. 07/mars/2015 14:18
par PAPIPP
Bonjour à tous

Voici deux macros (-FORD(...) et NEXTD(.) pour simuler une ou plusieurs boucles imbriquées ou pas
avec un pas passé en variable en nombre réel ou entier positif ou négatif.

La seule restriction pour l'utilisation de 2 macros est d'avoir une variable différente à chacune des boucles.
syntaxe :

FORD(variable,début,fin,pas)
NEXtD(variable)

la variable suit la syntaxe des variables de PB si elle doit être en float double précision il faut la définir avant l'appel de FORD(...)
Voir les exemples ci-dessous.

Code : Tout sélectionner

Macro _q_t_
"
EndMacro
Macro _n (__n)
_q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro

  Structure ADR
    ADR_var.s
    ADR_pas.l
    ADR_macexpc.l
    ADR_deb.l
    ADR_fin.l
  EndStructure
  Macro Nextd(NEXTD_variable)
  NEXTD_variable+ADR_ford(_q_t_#NEXTD_variable#_q_t_)\ADR_pas
  NEXTDlabdeb=ADR_ford(_q_t_#NEXTD_variable#_q_t_)\ADR_deb
  If ADR_ford(_q_t_#NEXTD_variable#_q_t_)\ADR_fin=0
    ADR_ford(_q_t_#NEXTD_variable#_q_t_)\ADR_fin=?nextd#NEXTD_variable
  EndIf
  !mov eax,[v_NEXTDlabdeb]
  !jmp eax
  Nextd#NEXTD_variable:
EndMacro
Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  If FORD_flag=0
    NewMap ADR_ford.ADR()
    FORD_flag=1
  EndIf
  If flag_#FORD_variable=0
    FORD_macexpc=MacroExpandedCount
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_var=_q_t_#FORD_variable#_q_t_
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_deb=?DEBlab_#FORD_variable
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin=?nextd#FORD_variable
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_macexpc=FORD_macexpc
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_pas=FORD_pas
    flag_#FORD_variable=1
  EndIf
  FORD_variable=FORD_debut
  ;********* debut boucle *********
  DEBlab_#FORD_variable: ; début de la boucle
  If FORD_pas>0
    ;********  	While émulation  FORD_variable <=fin  test pas >0  ************
    If FORD_variable<=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      FORDlabfin=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas<0
    ;********  	While émulation  FORD_variable >=fin  test pas <0  ************
    If FORD_variable>=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      Goto Nextd#FORD_variable
    EndIf
  ElseIf FORD_pas=0
    MessageRequester("Erreur ","le pas ne peut être égal à 0")
    End
  EndIf
  FINlab_#FORD_variable:
EndMacro

PASd=2
ford(a,1,6,pasd)
Debug a
nextd(a)
Debug "------ on ne peut garder la même variable a ----------------"
ford(a10,0,6,pasd)
Debug a10
nextd(a10)

Debug "-------- possibilité d'avoir des boucles imbriquées -------------------"

pas.d=4
Ford(a1,10.0,50.0,pas)
pasb=5
FORD(a2,5.0,15.0,pasb)
ford(a3,2,8,2)
Debug _n(a1)+_n(a2)+_n(a3)
Nextd(a3)
Nextd(a2)
nextd(a1)
; 
Debug "---------------------------"

pas.d=4
e=0
Ford(e,10.0,50.0,pas)
Debug e
Nextd(e)

Debug "---------------------------"
;
pas=-10.0
b1.d=0
Ford(b1,200.0,10.0,pas)
Debug b1
Nextd(b1)
; 
Debug "-------- possibilité d'avoir un pas en nombre réel -------------------"

pas=-3.4
c.d=0
ford(C,#PI,-30*#PI,pas)
Debug c
nextd(C)

Debug "------- Pour chaque boucle il faut changer le nom de la variable --------------------"

pas.d=4
Ford(f,10.0,100.0,pas)
Debug f
Nextd(f)

End

A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : mar. 10/mars/2015 13:03
par PAPIPP
Bonjour à tous

Voici une amélioration du prg précédent pour se rapprocher de la structure de l’instruction FOR de PB

For <variable> = <expression1> To <expression2> [Step <constante>]
...
Next [<variable>]

La syntaxe des instructions de ce PRG est

FORD(variable, debut , fin, pas)

NEXTD

La seule restriction est de ne pouvoir utiliser la même variable dans plus d’ une boucle
Il faudra utiliser une variable différente pour chaque boucle.
En cas d’utilisation d’une même variable L’erreur signalée sera ‘’ligne xxx label déjà déclare’’

NEXTD est sans variable pour éviter les boucles imbriquées particulières comme avec le prg précédent

FORD(A1,10,50,pasx)
FORD(A2,50,10,-10)
NEXRD(A1)
NEXTD(A2)

Ces deux boucles sont imbriquées d’une manière très particulière.
Cela donne des résultats surprenant !!!

C’est pour éviter cet inconvénient que ce PRG a été créé

Il utilise les instructions PUSH POP (voir la source) pour récupérer la variable de la boucle.
Il serait plus fiable de gérer une pile avec PB ce sera le prochain PRG.
L’incrémentation et la décrémentation de la variable nbpushpop est une info qui pourra servir plus tard.. Elle sert ici à vérifier que le nombre de PUSH est identique au nombre de POP à la fin de chaque boucle (nbpushpop=0 dans ce cas).

Code : Tout sélectionner

Macro _q_t_
"
EndMacro
Macro _n (__n)
_q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
Dim varpushpop.s(32)
Structure ADR
  ADR_valvar.d
  ADR_valdeb.d
  ADR_valfin.d
	ADR_valpas.d
	ADR_deb.l
	ADR_fin.l
	; ********  les informations suivantes ne sont pas indispensables au bon fonctionnement elles  permettent de faire évoluer le PRG 
	; ******        par exemple gérer le principe  push pop   par programme classique 
	ADR_var.s
  ADR_macexpc.l
  ADR_nbpushpop.l
EndStructure
nbpushpop=0
Define NEXTDPOP


Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  ;************ initialisation générale une seule fois pour ce PRG **********************
  If FORDflag_=0
    NewMap ADR_ford.ADR()
    Dim varpushpop.s(128) ; ici limitation à 128 variables  vous pouvez augmenter cette valeur
    FORDflag_=1
  EndIf
  
  ;*************  initialisation pour chaque variable une seule fois par variable *************
  
  If flagford_#FORD_variable=0
    fordvxx#FORD_variable=MacroExpandedCount
    varpushpop(fordvxx#FORD_variable)=_q_t_#FORD_variable#_q_t_
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_var=_q_t_#FORD_variable#_q_t_
    ADR_ford()\ADR_valvar=FORD_variable
    ADR_ford()\ADR_deb=?DEBlab_#FORD_variable
    ADR_ford()\ADR_macexpc=fordvxx#FORD_variable
    ADR_ford()\ADR_valpas=FORD_pas
    ADR_ford()\ADR_valdeb=FORD_debut
    ADR_ford()\ADR_valfin=FORD_fin
    flagford_#FORD_variable=1
  EndIf
  
  ;*************  Initialisation de la boucle pour une variable *************************
  
  FORD_variable=FORD_debut
  ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_valvar=FORD_variable
  
  ;********************************** debut boucle **************************************
  
  DEBlab_#FORD_variable: ; début de la boucle
  
  EnableASM  ;mémorise  l'indice correspondant à chaque variable x. C'est l'indice de la table varpushpop pour une variable x=FORD_variable  
  push fordvxx#FORD_variable
  nbpushpop+1
  DisableASM
  
  FORD_variable=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_valvar
  If FORD_pas>0
    ;******** While émulation FORD_variable <=fin test pas >0 ************
    If FORD_variable<=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      FORDlabfin=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas<0
    ;******** While émulation FORD_variable >=fin test pas <0 ************
    If FORD_variable>=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      FORDlabfin=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas=0
    MessageRequester("Erreur ","le pas ne peut être égal à 0")
    End
  EndIf
  FINlab_#FORD_variable:
  
EndMacro
Macro Nextd  ;(NEXTD_variable)
  
  EnableASM  ; récupére l'indice  de chaque variable x. C'est l'indice de la table varpushpop pour la variable x =NEXTDPOP
  pop NEXTDPOP
  nbpushpop-1
  DisableASM
  
  NEXTD_variable$=varpushpop(NEXTDPOP)
  NEXTDlabdeb=ADR_ford(NEXTD_variable$)\ADR_deb
  NEXTD_fin=ADR_ford()\ADR_fin
  NEXTD_valfin=ADR_ford()\ADR_valfin
  ; *******************  incrémentation de la variable par le pas *************************
  
  ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas
  NEXTDlabdeb=ADR_ford()\ADR_deb
  If NEXTD_fin=0
    ADR_ford()\ADR_fin=?nextd_#Macroexpandedcount
  EndIf
  !mov eax,[v_NEXTDlabdeb]
  !jmp eax
  Nextd_#Macroexpandedcount:
  EnableASM
  pop NEXTDPOP
  nbpushpop-1
  DisableASM
  
EndMacro


PASd=2
ford(a1,1,6,pasd)
Debug _nl+_n(a1)+_n(nbpuslpop)
nextd
Debug _nl+_n(nbpushpop)
Debug "------ on ne peut garder la même variable a ----------------"
ford(a2,0,6,pasd)
Debug _nl+_n(a2)+_n(nbpuslpop)
nextd
Debug _nl+_n(nbpushpop)
Debug "-------- possibilité d'avoir des boucles imbriquées 2 variables pas inversé-------------------"
; 
pas.d=10
Ford(a3,10.0,50.0,pas)  ;
pasb=-10
FORD(a4,50.0,-10.0,pasb)
Debug _n(a3)+_n(a4)     ;
Nextd
; 	Debug _n(a1)+_n(a2)
nextd
; 	;
Debug _nl+_n(nbpushpop)
Debug "-------- possibilité d'avoir des boucles imbriquées  3 variables -------------------"

pas.d=4
Ford(a5,10.0,50.0,pas)
pasb=5
FORD(a6,5.0,15.0,pasb)
FORD(a7,2,8,2)
Debug _NL+_n(a5)+_n(a6)+_n(a7)+_n(nbpushpop)
Nextd
Nextd
nextd
Debug _n(nbpuhpop) ;
Debug _nl+_n(nbpushpop)
Debug "---------------------------"
; 
pas.d=4
A8=0
Ford(A8,10.0,50.0,pas)
Debug A8
Nextd
Debug _nl+_n(nbpushpop)

Debug "---------------------------"
;
pas=-10.0
A9.d=0
Ford(A9,200.0,10.0,pas)
Debug A9
Nextd
;
Debug _n(nbpushpop)

Debug "-------- possibilité d'avoir un pas en nombre réel -------------------"

pas=-3.4
A10.d=0
ford(A10,#PI,-30*#PI,pas)
Debug A10
nextd
Debug _n(nbpushpop)

Debug "------- Pour chaque boucle il faut changer le nom de la variable --------------------"

pas.d=4
Ford(A11,10.0,100.0,pas)
Debug A11
Nextd
Debug _n(nbpushpop)

End

A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : mer. 11/mars/2015 20:45
par nico
Merci pour le code, en espérant qu'on aura jamais à le rectifier; c'est le néant total, la compréhension de ce code, impressionnant.

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : mer. 11/mars/2015 23:08
par PAPIPP
Bonjour Nico et merci

Comme je l'avais prévu voici un prg avec gestion de la pile sans PUSH ni POP ce qui rend le prg plus fiable.
PRG modifié avec la macro _NL

Code : Tout sélectionner

Macro _q_t_
  "
EndMacro
Macro _n(__n)
  _q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
Macro _NL
"N°L=" + Str(#PB_Compiler_Line) + " ** "
EndMacro
Dim varpushpop.s(32)
Structure ADR
  ADR_valvar.d
  ADR_valdeb.d
  ADR_valfin.d
	ADR_valpas.d
	ADR_deb.l
	ADR_fin.l
	; ********  les informations suivantes ne sont pas indispensables au bon fonctionnement elles  permettent de faire évoluer le PRG
	; ******        par exemple gérer le principe  push pop   par programme classique
  ADR_nbpushpop.l
EndStructure
_nbpushpop_=0
Define NEXTDPOP

Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  ;************ initialisation générale une seule fois pour ce PRG **********************
  If FORDflag_=0
    NewMap ADR_ford.ADR()
    Dim varpushpop.s(256) ; ici limitation à 256 variables  vous pouvez augmenter cette valeur
    Dim tabpushpop.l(128)  ; ici limitation à 128 boucles imbriquées *************************
    FORDflag_=1
  EndIf
  
  ;*************  initialisation pour chaque variable une seule fois par variable *************
  
  If flagford_#FORD_variable=0
    fordvxx#FORD_variable=MacroExpandedCount
    varpushpop(fordvxx#FORD_variable)=_q_t_#FORD_variable#_q_t_
    ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_valvar=FORD_variable
    ADR_ford()\ADR_deb=?DEBlab_#FORD_variable
    ADR_ford()\ADR_valpas=FORD_pas
    ADR_ford()\ADR_valdeb=FORD_debut
    ADR_ford()\ADR_valfin=FORD_fin
    flagford_#FORD_variable=1
  EndIf
  
  ;*************  Initialisation de la boucle pour une variable *************************
  
  FORD_variable=FORD_debut
  ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_valvar=FORD_variable
  
  ;********************************** debut boucle **************************************
  
  DEBlab_#FORD_variable: ; début de la boucle
  
  ;**************************  gestion PUSH POP  n'inverser pas les 2 instructions suivantes *******************************
  tabpushpop(_nbpushpop_)=fordvxx#FORD_variable
  _nbpushpop_+1
  
  FORD_variable=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_valvar
  If FORD_pas>0
    ;******** While émulation FORD_variable <=fin test pas >0 ************
    If FORD_variable<=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      FORDlabfin=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas<0
    ;******** While émulation FORD_variable >=fin test pas <0 ************
    If FORD_variable>=FORD_fin
      Goto FINlab_#FORD_variable
    Else
      FORDlabfin=ADR_ford(_q_t_#FORD_variable#_q_t_)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas=0
    MessageRequester("Erreur ","le pas ne peut être égal à 0")
    End
  EndIf
  FINlab_#FORD_variable:
  
EndMacro
Macro Nextd  ;(NEXTD_variable)
  
   ;**************************  gestion PUSH POP  n'inverser pas les 2 instructions suivantes *******************************
  _nbpushpop_-1
  NEXTDPOP= tabpushpop(_nbpushpop_)
  
  NEXTD_variable$=varpushpop(NEXTDPOP)
  NEXTDlabdeb=ADR_ford(NEXTD_variable$)\ADR_deb
  NEXTD_fin=ADR_ford()\ADR_fin
  NEXTD_valfin=ADR_ford()\ADR_valfin
  ; *******************  incrémentation de la variable par le pas *************************
  
  ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas
  NEXTDlabdeb=ADR_ford()\ADR_deb
  If NEXTD_fin=0
    ADR_ford()\ADR_fin=?nextd_#Macroexpandedcount
  EndIf
  !mov eax,[v_NEXTDlabdeb]
  !jmp eax
  Nextd_#Macroexpandedcount:
  
   ;*************************************  gestion PUSH POP  ****************************************
  _nbpushpop_-1
EndMacro


PASd=2
ford(a1,1,6,pasd)
Debug _nl+_n(a1)
nextd

Debug "------ on ne peut garder la même variable a ----------------"
ford(a2,0,6,pasd)
Debug _nl+_n(a2)
nextd

Debug "-------- possibilité d'avoir des boucles imbriquées 2 variables pas inversé-------------------"
;
pas.d=10
Ford(a3,10.0,50.0,pas)  ;
pasb=-10
FORD(a4,50.0,-10.0,pasb)
Debug _n(a3)+_n(a4)     ;
Nextd
nextd
; 	;
Debug "-------- possibilité d'avoir des boucles imbriquées  3 variables ou plus   -------------------"

pas.d=4
Ford(a5,10.0,50.0,pas)
pasb=5
FORD(a6,5.0,15.0,pasb)
FORD(a7,2,8,2)
Debug _NL+_n(a5)+_n(a6)+_n(a7); +_n(_nbpushpop_)
Nextd
Nextd
nextd

Debug "---------------------------"
;
pas.d=4
A8=0
Ford(A8,10.0,50.0,pas)
Debug A8
Nextd

Debug "---------------------------"
;
pas=-10.0
A9.d=0
Ford(A9,200.0,10.0,pas)
Debug A9
Nextd
;

Debug "-------- possibilité d'avoir un pas en nombre réel -------------------"

pas=-3.4
A10.d=0
ford(A10,#PI,-30*#PI,pas)
Debug A10
nextd

Debug "------- Pour chaque boucle il faut changer le nom de la variable --------------------"

pas.d=4
Ford(A11,10.0,100.0,pas)
Debug A11
Nextd

End

Je pense pouvoir réutiliser une variable déjà utilisée dans une boucle précédente hors des boucles imbriquées comme le fait l'instruction FOR ..... next

A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : jeu. 12/mars/2015 8:49
par Mesa
J'ai une erreur de macro ligne 111, on dirait qu'il manque la macro _nl.

M.

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : jeu. 12/mars/2015 12:32
par PAPIPP
Bonjour Mesa et merci
J'ai encore oublier cette macro qui ne me sert que pour débuguer le PRG
Toutes les macros qui me servent pour mettre au point le PRG sont placées en RESIDENT

Elle peut être retirée sans problème.
voici cette macro :

Code : Tout sélectionner

Macro _NL
"N°L=" + Str(#PB_Compiler_Line) + " ** "
EndMacro
A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : ven. 13/mars/2015 0:24
par PAPIPP
Bonjour à tous

Voici un prg de simulation très proche des boucles FORT NEXT avec pas réel ou entier positif ou négatif.

Ou l’on peut utiliser la même variable dans des boucles indépendantes donc non imbriquées.
Par contre dans les boucles imbriquées il faut des variables différentes.

Ce programme est plus simple à comprendre que les précédents car il n’utilise qu’une seule table gérée en pile comme PUSH POP. La gestion en pile ne sert que pour les boucles imbriquées.
On n'utilise qu'un seul poste de la table lorsque la boucle est indépendante.

J’ai placé des commentaires pour une meilleure compréhension.

Code : Tout sélectionner

Macro _q_t_
  "
EndMacro
Macro _n(__n)
  _q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro

Structure ADR
  ADR_VAR.s
  ADR_valvar.d
  ADR_valdeb.d
  ADR_valfin.d
  ADR_valpas.d
  ADR_deb.l
  ADR_fin.l
EndStructure

Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  ;************ initialisation générale une seule fois pour ce PRG **********************
  If FORDflag_=0
     Define  _nbpushpop_=0
    Dim tab_var.ADR(128)  ;  ; ici limitation à 128 boucles imbriquées (on peut augmenter cette valeur seule limite) *************************
    FORDflag_=1
  EndIf
  
  ;*************  initialisation pour chaque variable une seule fois par variable *************
  
  If flagford_#FORD_variable#MacroExpandedCount=0
    ; **********   chargement de la table TAB_VAR   *********************
    tab_var(_nbpushpop_)\ADR_var=_q_t_#FORD_variable#_q_t_
    tab_var(_nbpushpop_)\ADR_valvar=FORD_variable
    tab_var(_nbpushpop_)\ADR_fin=0  ;; pour réinitialiser l'adresse de fin
    tab_var(_nbpushpop_)\ADR_deb=?DEBlab_#MacroExpandedCount
    tab_var(_nbpushpop_)\ADR_valpas=FORD_pas
    tab_var(_nbpushpop_)\ADR_valdeb=FORD_debut
    tab_var(_nbpushpop_)\ADR_valfin=FORD_fin

    flagford_#FORD_variable#MacroExpandedCount=1
  EndIf
  
  ;*************  Initialisation de la boucle pour une variable *************************
  
  FORD_variable=FORD_debut
  tab_var(_nbpushpop_)\ADR_valvar=FORD_variable
  
  ;********************************** debut boucle **************************************
  
  DEBlab_#MacroExpandedCount: ; début de la boucle
  ;**************************  gestion PUSH POP *******************************
  _nbpushpop_p=_nbpushpop_
  _nbpushpop_+1
  
    FORD_variable=tab_var(_nbpushpop_p)\ADR_valvar
  If FORD_pas>0
    ;******** While émulation FORD_variable <=fin test pas >0 ************
    If FORD_variable<=FORD_fin
      Goto FINlab_#Macroexpandedcount
    Else
      FORDlabfin=tab_var(_nbpushpop_p)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas<0
    ;******** While émulation FORD_variable >=fin test pas <0 ************
    If FORD_variable>=FORD_fin
      Goto FINlab_#Macroexpandedcount
    Else
      FORDlabfin=tab_var(_nbpushpop_p)\ADR_fin

      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas=0
    MessageRequester("Erreur ","le pas ne peut être égal à 0")
    End
  EndIf
  FINlab_#Macroexpandedcount:
  
EndMacro
Macro Nextd  ;(NEXTD_variable)
  
  ;**************************  gestion PUSH POP *******************************
  _nbpushpop_-1
  
  NEXTDlabdeb=tab_var(_nbpushpop_)\ADR_deb
  NEXTD_fin=tab_var(_nbpushpop_)\ADR_fin
  NEXTD_valfin=tab_var(_nbpushpop_)\ADR_valfin
 
  
  ; *******************  incrémentation de la variable par le pas *************************
  
  tab_var(_nbpushpop_)\ADR_valvar+tab_var(_nbpushpop_)\ADR_valpas
  NEXTDlabdeb=tab_var(_nbpushpop_)\ADR_deb
  If NEXTD_fin=0
    tab_var(_nbpushpop_)\ADR_fin=?nextd_#Macroexpandedcount
  EndIf
  !mov eax,[v_NEXTDlabdeb]
  !jmp eax
  Nextd_#Macroexpandedcount:
  
  ;**************************  gestion PUSH POP *******************************
  _nbpushpop_-1
EndMacro


PASd=2
ford(a1,1,6,pasd)
Debug _n(a1)
nextd

Debug "------ on peut garder la même variable a ----------------"
ford(a1,0,8,pasd)
Debug _n(a2)+_n(A1)
nextd

Debug "-------- possibilité d'avoir des boucles imbriquées 2 variables pas inversé-------------------"
;
pas.d=10
Ford(a3,10.0,50.0,pas)  ;
pasb=-10
FORD(a4,50.0,-10.0,pasb)
Debug _n(a3)+_n(a4)     ;
Nextd
nextd
; 	;
Debug "-------- possibilité d'avoir des boucles imbriquées  3 variables ou plus   -------------------"

pas.d=4
Ford(a5,10.0,50.0,pas)
pasb=5
FORD(a6,5.0,15.0,pasb)
FORD(a7,2,8,2)
Debug _n(a5)+_n(a6)+_n(a7); +_n(_nbpushpop_)
Nextd
Nextd
nextd

Debug "---------------------------"
;
pas.d=4
A8=0
Ford(A8,10.0,50.0,pas)
Debug A8
Nextd

Debug "---------------------------"
;
pas=-10.0
A9.d=0
Ford(A9,200.0,10.0,pas)
Debug A9
Nextd
;

Debug "-------- possibilité d'avoir un pas en nombre réel -------------------"

pas=-3.4
A10.d=0
ford(a10,#PI,-30*#PI,pas) ;;même variable que la première boucle 
Debug A10
nextd

Debug "------- Pour chaque boucle on peut garder le même nom de la variable --------------------"

pas.d=4
Ford(A1,10.0,100.0,pas) ;;même variable que la première boucle 
Debug A1
Nextd

ford(a1,1,20,5)
Debug _n(a1)
nextd



End


A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : sam. 14/mars/2015 15:57
par PAPIPP
Bonjour à tous

Le PRG précédent qui se voulait plus simple car il n’utilisait pour la gestion de la pile que d’une table
Dim tab_var.ADR(128) avec la structure
Structure ADR
ADR_VAR.s
ADR_valvar.d
ADR_valdeb.d
ADR_valfin.d
ADR_valpas.d
ADR_deb.l
ADR_fin.l
EndStructure
Et _nbpushpop_ comme index de pile

Ce PRG est vraiment trop simple car il ne répond correctement que dans 2 cas
1) Dans les boucles indépendantes du type :
FORD(A1,deb1,fin1,pas1)
NEXTD
..
..
FORD(A1,deb2,fin2,pas2) ; ici boucle avec même variable que la précédente
NEXTD
..
..
FORD(A2,deb3,fin3,pas3) ; ici tout est différend
NEXTD


2) Dans les boucles imbriquées simples ou insérées les unes dans les autres :
FORD(A1,deb1,fin1,pas1)
FORD(A2,deb2,fin2,pas2) ; ici impossible d’avoir le même nom de variable
FORD(A2,deb3,fin3,pas3) ; ici tout est différend
NEXTD
NEXTD
NEXTD

Par contre si vous voulez insérer ou imbriquer 2 boucles indépendantes dans une autre boucle simple ou elle-même imbriquée ou pas vous obtenez de mauvais résultats
Exemple :

Code : Tout sélectionner

pas1=2
pas2=3
pas3=5

ford(A1,0,8,pas1)

    A3=0 ; remise à zero de A3 qui ne sert pas dans la boucle suivante
    Debug "__ debut boucle imbriquée A1 avec A2  les valeurs de A3 ne sont pas utiles puisque A3 peut être initialise avant la boucle qui ne concerne que A1 et A2 _________________"

    ford(A2,0,9,pas2)
    Debug _n(A1)+_n(A2)+_n(A3)
    nexTd

    A2=0 ; remise à zero de A2 qui ne sert pas dans la boucle suivante
    Debug "___debut boucle imbriquée A1 avec A3 les valeurs de A2 ne sont pas utiles puisque A2 peut être initialise avant la boucle qui ne concerne que A1 et A3 _________________"
    
    ford(A3,0,15,pas3)
    Debug _n(A1)+_n(A2)+_n(A3)
    nextd

nextd
Vous pouvez tester sur le PRG précédent pour obtenir de mauvais résultats
Par contre cela fonctionne sur le dernier PRG avec MAP.

Pour obtenir les mêmes caractéristiques que les boucles FOR … next

Voici le dernier PRG avec MAP corrigé et un peu moins complexe que celui décrit par nico. (Une table en moins)
Il permet d’utiliser les mêmes variables dans 2 boucles indépendantes et de même niveau
d’imbrication (vor les exemples) .
Par contre la complexité relevé par nico est toujours présente je vais dans un prochain article essayé
d’expliquer le fonctionnement de ces 2 macros.
J’ai laissé 2 infos en tête dans la structure qui m’ont servi à le mettre au point.
Elles ne sont pas nécessaires au bon fonctionnement mais sont indispensables pour la compréhension.

Code : Tout sélectionner

Macro _q_t_
  "
EndMacro
Macro _n(__n)
  _q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
Structure ADR
	ADR_VAR.s ; nom de la variable qui ne sert pas à l"exploition mais qui permet lors de la mise au point de savoir à qui appartiennent les information de cet index
	ADR_macexpc.s{4} ; Numéro d"identification du nombre d'appel de la macro  ne sert que pour l'dentification dans la MAP
	ADR_valvar.d
	ADR_valdeb.d
	ADR_valfin.d
	ADR_valpas.d
	ADR_deb.l
	ADR_fin.l
EndStructure
Macro Nextd  ;(NEXTD_variable)
  
  ;**************************  gestion PUSH POP *******************************
  _nbpushpop_-1
  NEXTDlabdeb=ADR_ford(varpushpop(_nbpushpop_))\ADR_deb
  NEXTD_fin=ADR_ford()\ADR_fin
;   NEXTD_valfin=ADR_ford()\ADR_valfin
  ; *******************  incrémentation de la variable par le pas *************************
  
  ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas
  NEXTDlabdeb=ADR_ford()\ADR_deb
  If NEXTD_fin<>?nextd_#Macroexpandedcount
    ADR_ford()\ADR_fin=?nextd_#Macroexpandedcount
  EndIf
  !mov eax,[v_NEXTDlabdeb]
  !jmp eax
  
  Nextd_#Macroexpandedcount:
  ;**************************  gestion PUSH POP *******************************
  _nbpushpop_-1
  If _nbpushpop_=0
    ; ******** on peut ici nettoyer  la MAP  ADR_ford et les tables  varpushpop avec varpushpopB si elles  deviennent trop petites *******
    ;     ClearMap(ADR_ford.ADR())
    ;     varpushpop=varpushpopB
  EndIf
EndMacro

Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  
  ;************************* initialisation générale une seule fois pour ce PRG **********************
  If FORDflag_=0
    Define NEXTDPOP,_nbpushpop_=0
    NewMap ADR_ford.ADR()
    Dim varpushpop.s(256) ; ici limitation à 256  (variables+ MacroExpandedCount) vous pouvez augmenter cette valeur
    Dim varpushpopB.s(256)
    FORDflag_=1
  EndIf
  
  ;********************* initialisation pour chaque boucle une seule fois par boucle *************
  
  If flagford_#MacroExpandedCount#FORD_variable=0
    FORD_identification$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
    varpushpop(_nbpushpop_)=FORD_identification$
    ADR_ford(FORD_identification$)\ADR_var=_q_t_#FORD_variable#_q_t_
    ADR_ford()\ADR_macexpc=Str(MacroExpandedCount)
    ADR_ford()\ADR_valvar=FORD_variable
    ADR_ford()\ADR_deb=?DEBlab_#MacroExpandedCount
    ADR_ford()\ADR_fin=?Nextd_#Macroexpandedcount
    ADR_ford()\ADR_valpas=FORD_pas
    ADR_ford()\ADR_valdeb=FORD_debut
    ADR_ford()\ADR_valfin=FORD_fin
    flagford_#MacroExpandedCount#FORD_variable=1
  EndIf
  
  ;**************************  Initialisation de la boucle pour une variable *************************
  
  FORD_variable=FORD_debut
  ADR_ford(Str(MacroExpandedCount))\ADR_valvar=FORD_variable
 
  ;********************************************* debut boucle *****************************************
  
  DEBlab_#MacroExpandedCount: ; *****************   début de la boucle
  ;**************************  gestion PUSH POP *******************************
  _FORD_identification_$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
  varpushpop(_nbpushpop_)=_FORD_identification_$
 
  _nbpushpop_+1
  
  FORD_variable=ADR_ford(_FORD_identification_$)\ADR_valvar
  If FORD_pas>0
    ;******** While émulation FORD_variable <=fin test pas >0 ************
    If FORD_variable<=FORD_fin
      Goto FINlab_#Macroexpandedcount
    Else
      FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas<0
    ;******** While émulation FORD_variable >=fin test pas <0 ************
    If FORD_variable>=FORD_fin
      Goto FINlab_#Macroexpandedcount
    Else
      FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
      !mov eax,[v_FORDlabfin]
      !jmp eax
    EndIf
  ElseIf FORD_pas=0
    MessageRequester("Erreur ","le pas ne peut être égal à 0")
    End
  EndIf
  FINlab_#Macroexpandedcount:
EndMacro

;**************  Pour toutes les boucles imbriquées on ne peut utiliser les mêmes variables ******************
pas1=2
pas2=3
pas3=5

ford(A1,0,8,pas1)

A3=0 ; remise à zero de A3 qui ne sert pas dans la boucle suivante
Debug "__ debut boucle imbriquée A1 avec A2  les valeurs de A3 ne sont pas utiles puisque A3 peut être initialise avant la boucle qui ne concerne que A1 et A2 _________________"

ford(A2,0,9,pas2)
Debug _n(A1)+_n(A2)+_n(A3)
nexTd

A2=0 ; remise à zero de A2 qui ne sert pas dans la boucle suivante
Debug "___debut boucle imbriquée A1 avec A3 les valeurs de A2 ne sont pas utiles puisque A2 peut être initialise avant la boucle qui ne concerne que A1 et A3 _________________"

ford(A3,0,15,pas3)
Debug _n(A1)+_n(A2)+_n(A3)
nextd

nextd

Debug "------boucle indépendante  on  peut garder la même variable a1 ----------------"


PASd=2
ford(a1,1,6,pasd)
Debug _n(a1)
nextd

Debug "------ on  peut garder la même variable a1 ----------------"
ford(a1,0,6,pasd)
Debug _n(a1)
nextd

Debug "-------- possibilité d'avoir des boucles imbriquées 2 variables pas inversé-------------------"
;
pas.d=10
Ford(a3,10.0,50.0,pas)  ;
pasb=-10
FORD(a4,50.0,-10.0,pasb)
Debug _n(a3)+_n(a4)     ;
Nextd
nextd
; 	;
Debug "-------- possibilité d'avoir des boucles imbriquées  3 variables ou plus   -------------------"

pas.d=4
Ford(a5,10.0,50.0,pas)
pasb=5
FORD(a6,5.0,15.0,pasb)
FORD(a7,2,8,2)
Debug _n(a5)+_n(a6)+_n(a7); +_n(_nbpushpop_)
Nextd
Nextd
nextd

Debug "---------------------------"
;
pas.d=4
A8=0
Ford(A8,10.0,50.0,pas)
Debug A8
Nextd

Debug "---------------------------"
;
pas=-10.0
A9.d=0
Ford(A9,200.0,10.0,pas)
Debug A9
Nextd
;

Debug "-------- possibilité d'avoir un pas en nombre réel -------------------"

pas=-3.4
A10.d=0
ford(A10,#PI,-30*#PI,pas)
Debug A10
nextd

Debug "------- Pour chaque boucle il faut changer le nom de la variable --------------------"

pas.d=4
Ford(A10,10.0,100.0,pas)
Debug A10
Nextd

End

Si vous détectez des erreurs dans des structures d'appel veuillez me les signaler.

A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : mer. 18/mars/2015 11:56
par PAPIPP
Bonjour à tous.
Tentative d'explication des 2 macros FORD et NEXTD.
Pour essayer de comprendre les 2 macros FORD et NEXTD commençons par un prototype simple et qui fonctionne au moins sur une seule boucle

Si l’on veut émuler le code ASM en PB (plus concis que ASM) dans une Macro on pourra créer une macro FORD …. NEXTD avec les paramètres suivants.

Comme l’instruction for la macro devra avoir comme paramètres :
1) une variable
2) un début
3) une fin
4) et un pas ou step
On doit tenir compte du pas négatif ou positif

Code : Tout sélectionner

Macro FORD(variable,debut,fin,pas)
; initialisation de la boucle FORD
Variable=debut
Label_boucle_debut:
If pas>0 ;  pas positif
  If variable<=fin 
       Goto label_finford
   Else
       Goto label_finnextd
  EndIf
ElseIf pas <0;  pas négatif 
  If variable>=fin 
       Goto label_finford
   Else
       Goto label_finnextd
  EndIf
ElseIf  pas=0 ; ici pas négatif peut être traité de tout autre manière
MessageRequester("erreur","pas égal à zero")
EndIf

label_finford:
EndMacro

; Le principe de la Macro FORD ne pose pas de pb
; 
; et  NEXTD est assez facile si l’on passe la variable et le pas.

Macro NEXTD(variable,pas)
variable+pas
Goto Label_boucle_debut 
label_finnextd:
EndMacro
;********************************************************************
; ; avec pas positif
VA=0
debut=1
fin=10
pas=2
FORD(VA,debut,fin,pas)

Debug va

NEXTD(va,pas)
;*********************************************************************
; ; avec pas négatif

; VA=0
; debut=10
; fin=1
; pas=-2
; FORD(VA,debut,fin,pas)
; 
; Debug va
; 
; NEXTD(va,pas)
Si l’on dé-commente les instructions du pas négatif et si l’on commente les instructions du pas positf.

Les deux options fonctionnent bien.

Par contre si l’on dé-commente les deux pas, l’on obtient une erreur ( ligne xx label déjà déclaré)

Essayons de résoudre le pb des muti-appels avec cet exemple.

Code : Tout sélectionner

; Macro _q_t_
;   "
; EndMacro
; Macro _n(__n)
;   _q_t_#__n#=_q_t_+Str(__n)+" "
; EndMacro

Macro essai(var)
;   _macexpc=MacroExpandedCount
  
  Debug _n(var)+_n(MacroExpandedCount)
  label#var:
  label#MacroExpandedCount:
  label#var#MacroExpandedCount: 
  
EndMacro
VA=30
VA2=32
va3=33
For jj=0 To 3
essai(va)    ; premier appel
essai(va2)   ; deuxième appel
essai(vA3)   ; troisième appel
va4=34
For i=0 To 5
  essai(va4)   ; quatrième appel
Next
va5=35
essai(va5)     ; cinquième appel
Next
; par contre si l'on appel avec une variable déjà utilisée on a une erreur. Supprimer le commentaire de l'appel essai suivant pour avoir une erreur de label déjà déclaré 
; pour faire un essai sans erreur vous devez mettre en commentaire le label label#var de la macro commentez dans la macro label#var: et dé-commentez l'appel essai(va) ci-dessous.
; essai(va) ;; sixième appel
; le nombre défini par MacroExpandedCount est le nombre d'appel physique et non logique. C'est le nombre de fois que l'on voit l'appel de la macro.

Passons aux macros FORD et NEXTD

Code : Tout sélectionner

Macro _q_t_
	"
EndMacro
Macro _n(__n)
	_q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
  
Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
  ; initialisation de la boucle FORD
  FORD_variable=FORD_debut
  Label_boucle_FORD_debut#macroexpandedcount:
  If FORD_pas>0 ;  FORD_pas positif
    If FORD_variable<=FORD_fin
      Goto label_finford#macroexpandedcount
		Else
      Goto label_finnextd#macroexpandedcount
    EndIf
  ElseIf FORD_pas<0;  FORD_pas négatif
    If FORD_variable>=FORD_fin
      Goto label_finford#macroexpandedcount
		Else
      Goto label_finnextd#macroexpandedcount
    EndIf
  ElseIf FORD_pas=0 ; ici FORD_pas négatif peut être traité de tout autre manière
    MessageRequester("erreur","pas égal à zero")
  EndIf
  ; MacroExpandedCount
  label_finford#macroexpandedcount:
  macroexpandedcount1=MacroExpandedCount
EndMacro

; Le principe de la Macro FORD ne pose pas de pb
;
; Par contre le principe de la Macro NEXTDO en pose un si l’on ne veut pas passer ni  la variable ni le pas (ce problème sera résolu plus tard).
; Si dans la macro NEXTDO on passe la variable et le pas, c’est assez facile

Macro NEXTDO(NEXTD_variable,NEXTD_pas)
  NEXTD_variable+NEXTD_pas
  Goto Label_boucle_FORD_debut#macroexpandedcount
  label_finnextd#macroexpandedcount:
EndMacro
;********************************************************************
; ; ; avec pas positif
VA=0
debut=1
fin=10
pas=2
FORD(VA,debut,fin,pas)

Debug _N(va)+_N(MacroExpandedCount1)

nextdo(va,pas)
; ;*********************************************************************
; ; ; avec pas négatif
Debug "********* Changement de pas mais avec la même variable (2  boucles indépendantes)"
VA=0
debut=10
fin=1
pas=-2
FORD(VA,debut,fin,pas)

Debug _N(va)+_N(MacroExpandedCount1)

nextdo(va,pas)
 
;;**************************
On a résolu le pb des multi-appels de la même macro et en plus on peu garder la même variable dans plusieurs boucles indépendantes.

Pour les boucles imbriquées nous allons avoir un nouveau petit bp à résoudre.
Car en numérotant les macros dans l’ordre physique qui se présente nous avons.

Vous pouvez essayer les instructions suivantes avec les Macros précédentes

Code : Tout sélectionner

VA=0
debut=1
fin=10
pas=2
VA2=0
debut2=8
fin2=0
pas2=-2
FORD(VA,debut,fin,pas) ;;;;;   macroexpandedcount=1
FORD(VA2,debut2,fin2,pas2) ;;;;;   macroexpandedcount=2
Debug _n(va2)+_n(va)
nextdO(va2,pas2)  ;;;;; Goto Label_boucle_debut#macroexpandedcount
;;   MacroExpandedCount=1 Or il faut se brancher après incrémentation avec une valeur de 2 et non de 1
nextdo(va,pas) ;;;;; Goto Label_boucle_debut#macroexpandedcount
;;  MacroExpandedCount=2 et ici il faut il faut se brancher après incrémentation avec une valeur de 1 et non de 2

; Le programme va bouclé à l’infini puisque le FORD niveau 1  et NEXRDO niveau 1 ne sont pas associés.
 
Le programme va bouclé à l’infini puisque le FORD niveau 1 et NEXTD niveau 1 ne sont pas associés.
On ne peut résoudre ce pb qu’avec une pile push pop ou une gestion de pile car si ici il n’y a que 2 boucles , il peut y avoir 4 ,5 ou plusieurs boucles imbriquées.

Lorsque nous aurons résolu le pb de la pile il faudra s’attaquer au passage des 2 paramètres (variable et pas) en les supprimant dans la Macro NEXTD et en les passant par MAP ou table.
Il y a un effet pervers à garder les variables car on peut obtenir la structure d’appel suivante.
VA=0
debut=1
fin=10
pas=2
VA2=0
debut2=8
fin2=0
pas2=-2
FORD(VA,debut,fin,pas)
FORD(VA2,debut2,fin2,pas2)
Debug _n(va2)+_n(va)
NEXTD(va,pas)
NEXTD(va2,pas2) ;; inversion des NEXTD donne des résultats surprenants
alors que
FORD(VA,debut,fin,pas)
FORD(VA2,debut2,fin2,pas2)
Debug _n(va2)+_n(va)
NEXTD
NEXTD)
Lève immédiatement l’ambigüité car le NEXTD le plus prés de l’instruction FORD lui est associée.et le le dernier NEXTD est associé à l’instruction FORD la plus éloignée.

Comment résoudre le pb des boucles imbriquées et en même temps celui de la suppression des paramètres (variable et pas) de la macro NEXTD
Ici le pb devient plus délicat à résoudre en effet :
Comme il va falloir stocker certaines infos de chaque boucle physique on doit pouvoir supprimer les paramètres (variable et pas) dans la micro NEXTD
Pour garder une présentation à peu près correcte le texte suivant est entre code et /code.

Code : Tout sélectionner

1)	stocker le N° de macroexpandedcount dans une table en incrémentant un index
         la table sera  varpushpop() et l’index _nbpushpop_ on devra aussi mémoriser toutes les informations relative à la boucle  
              (valeur de la variable,valeur du pas,valeur max de fin, adresse de branchement du commencement de boucle dans FORD,
         l’adresse de débranchement de boucle dans NEXTD)
         la table de la pile ne devra gérer que les boucles imbriquées (nombre d’imbrications) les infos de chaque boucle doivent être stockées or ces deux
        ensembles n’ont pas les mêmes dimensions.
2)	Nous aurons donc 1 table servant à la gestion de pile et une table ou une MAp pour toutes les infos de chacune des boucles. 
          Mais comme nous ne connaissons pas le nb de boucle nous utiliserons une MAP avec comme identifiant le N° de macroexpandedcount 
          comme celui-ci est numérique nous prendrons str(macroexpandedcount)
3)	Nos aurons donc 3 niveaux d’initialisation
       31)  Un niveau général et unique pour le prg ou nous définirons la table varpushpop() la MAP
              et l’index _nbpushpop_ 
       32) un niveau de chaque définition d’une  boucle physique définie par FORD(var1,deb1,fin1,pas1)
              pour mémoriser dans la MAP :
               les infos va1,deb1,fin1,pas1 mêmes si ses infos ne sont pas nécessaires  ainsi que les adresses :
              l’adresse du label de la fin de NEXTD  label_finnextd#macroexpandedcount  pour chaque boucle
              l’adresse du label de début de FORD  Label_boucle_debut#macroexpandedcount 
       33) Au niveau de chaque boucle logique :
                La gestion de la pile par incrémentation de l’index
                La mémorisation dans la table varpushpop(_nbpushpop_) du N° de la boucle en train d’être exécuté ce N° est le  N° de macroexpandedcount
                La gestion de la pile se fera avec l'index _nbpushpop_ associée à la table varpushpop() 
                  qui contient les N° MacroExpandedCount propre à chaque boucle.
               _nbpushpop_ sera indexé en prévision de rencontrer un autre FORD avant de le décrémenter dans NEXTD (gestion classique d'une pile).

Lorsque _nbpushpop_ est à zero nous ne sommes pas dans une boucle imbriquée la valeur contenu dans varpushpop(0)  est le dernier N° MacroExpandedCount initialiser dans FORD au début de cette boucle dons il ne peut y avoir de confusion dans les infos recherchées à partir de cette valeur dans la MAP puisqu'au début de chaque boucle il y a une initialisation dans FORD.
FORD(A1,D1,F1,PAS1) ;;; _nbpushpop_ =0 pour exploitation et +1 donc 1 en prévision du prochain FORD
FORD(A2,D2,F2,pas2) ;;; _nbpushpop_ =1 pour exploitation et +1 donc 2 en prévision du prochain FORD
FORD(A3,D3,F3,pas3) ;;; _nbpushpop_ =2 pour exploitation et +1 donc 3 en prévision du prochain FORD

Ici instructions avec A1 A2, A3

NEXTD ;;; _nbpushpop_=3 et -1 donc 2 pour l’exploitation correspond parfaitement à FORD(A3.)
NEXTD;;; _nbpushpop_=2 et -1 donc 1 pour l’exploitation correspond parfaitement à FORD(A2..)
NEXTD;;; _nbpushpop_=1 et -1 donc 0 pour l’exploitation correspond parfaitement à FORD(A1.)
On peut vérifier sur toute autre structure d’appel on aura une correspondance parfaite entre FORD et NEXTD
Exemple soit les boucles suivantes 2 boucles indépendantes suivi d’une structure de boucle complexe (2 boucles indépendantes imbriquées dans une boucle)
FORD(A1,DEB1,FIN1,PAS1) _nbpushpop_=0 pour stoker str( MacroExpandedCount) dans varpushpop(0) puis incrémentation en prévision d’un nouveau FORD
.........
NEXTD ;;_nbpushpop_-1 décrémentation donc =0 extraction de l’identificateur du varpushpop(_nbpushpop_) donc de varpushpop(0) Sortie de la boucle avec _nbpushpop_=0

FORD(A2,DEB2,FIN2,PAS2) _nbpushpop_=0 pour stoker str( MacroExpandedCount) dans varpushpop(0) puis incrémentation en prévision d’un nouveau FORD
….
NEXTD ;;_nbpushpop_-1 décrémentation donc =0 extraction de l’identificateur du varpushpop(_nbpushpop_) donc de varpushpop(0)

FORD(B1,D1,F1,P1) ;; _nbpushpop_=0 pour stoker str( MacroExpandedCount) dans varpushpop(0) puis incrémentation en prévision d’un nouveau FORD
;; Maintenant 2 boucles indépendantes imbriquées dans une autre boucle
FORD(C2,D2,F2,P2) ;; _nbpushpop_=1 pour stoker str( MacroExpandedCount) dans varpushpop(1) puis incrémentation en prévision d’un nouveau FORD

NEXTD;;_nbpushpop_-1 décrémentation donc =1 extraction de l’identificateur du varpushpop(_nbpushpop_) donc de varpushpop(1) Sortie de la boucle avec _nbpushpop_=1
FORD(C3,D3,F3,P3) ;; _nbpushpop_=1 pour stoker str( MacroExpandedCount) dans varpushpop(1) puis incrémentation en prévision d’un nouveau FORD

NEXTD;;_nbpushpop_-1 décrémentation donc =1 extraction de l’identificateur du varpushpop(_nbpushpop_) donc de varpushpop(1) Sortie de la boucle avec _nbpushpop_=1
NEXTD;;_nbpushpop_-1 décrémentation donc =0 extraction de l’identificateur du varpushpop(_nbpushpop_) donc de varpushpop(0) Sortie de la boucle avec _nbpushpop_=0
A la fin des boucles imbriquées _nbpushpop_ doit être =0 ce qui est le cas ici

Ainsi avec la MAP associée à la table varpushpop() laquelle est indexée par _nbpushpop_ on résout le pb des boucles imbriquées et la suppression des paramètres (variable et pas) dans NEXTD.

Pour éviter l'erreur Ligne xx le label est déjà déclaré.
Nous pouvons donc prendre comme type de label :
soit la forme label#variable#MacroExpandedCount: (ceinture bretelle)
soit la forme label#MacroExpandedCount: (plus simple et unique)


Maintenant il ne doit plus rester de pb important pour comprendre les 2 macros.

Voici quelques précisions sur les infos utilisées.


La macro FORD commence par 2 zones d’initialisation
La première pour initialiser une seule fois le programme

Code : Tout sélectionner

  ;************************* initialisation générale une seule fois pour ce PRG **********************
	If FORDflag_=0
		Define NEXTDPOP,_nbpushpop_=0
		NewMap ADR_ford.ADR()
		Dim varpushpop.s(256) ; ici limitation à 256  (boucles avec str(MacroExpandedCount)) vous pouvez augmenter cette valeur
		Dim varpushpopB.s(256)
		FORDflag_=1
	EndIff
la deuxième pour initialiser chaque boucle physique.

Code : Tout sélectionner

;******** initialisation pour le début de chaque boucle  une seule fois par le N° d’appel physique de la macro  associée au n° de macroexpandedcount  *************

	;********************* initialisation pour chaque boucle une seule fois par boucle *************
	
	If flagford_#MacroExpandedCount#FORD_variable=0
		FORD_identification$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
		varpushpop(_nbpushpop_)=FORD_identification$
		ADR_ford(FORD_identification$)\ADR_var=_q_t_#FORD_variable#_q_t_
		ADR_ford()\ADR_macexpc=Str(MacroExpandedCount)
		ADR_ford()\ADR_valvar=FORD_variable
		ADR_ford()\ADR_deb=?Label_boucle_FORD_debut#macroexpandedcount
		ADR_ford()\ADR_fin=?label_finnextd#macroexpandedcount
		ADR_ford()\ADR_valpas=FORD_pas
		ADR_ford()\ADR_valdeb=FORD_debut
		ADR_ford()\ADR_valfin=FORD_fin
		flagford_#MacroExpandedCount#FORD_variable=1
	EndIf
	
	;**************************  Initialisation de la boucle pour chaque appel  *************************
 ;******** initialisation pour le début de chaque boucle de la variable par la valeur début *************
	FORD_variable=FORD_debut
	ADR_ford(Str(MacroExpandedCount))\ADR_valvar=FORD_variable 
et ensuite le début de boucle proprement dite

Code : Tout sélectionner

;********************************************* debut boucle *****************************************
	
	DEBlab_#MacroExpandedCount: ; *****************   début de la boucle
	;**************************  gestion PUSH POP *******************************
	_FORD_identification_$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
	varpushpop(_nbpushpop_)=_FORD_identification_$

	_nbpushpop_+1  ;; incrémentation de l’index de pile placé ici avant les multiples branches
                          ;;;  on incrémente en prévision de rencontrer une nouvelle boucle FORD avant la décrémentation dans NEXTD
                          ;;; avec FORD on incrémente _nbpushpop_
                        ;;; avec NEXTD on décrémente _nbpushpop_ 
	
	FORD_variable=ADR_ford(_FORD_identification_$)\ADR_valvar
	If FORD_pas>0   ;;; avec pas positif 
		;******** While émulation FORD_variable <=fin test pas >0 ************
		If FORD_variable<=FORD_fin 
			Goto FINlab_#Macroexpandedcount
		Else
			FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
			!mov eax,[v_FORDlabfin]
			!jmp eax;;; Branchement à la fin de macro NEXTD
		EndIf
	ElseIf FORD_pas<0   ;;; avec pas négatif
		;******** While émulation FORD_variable >=fin test pas <0 ************
		If FORD_variable>=FORD_fin
			Goto FINlab_#Macroexpandedcount
		Else
			FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
			!mov eax,[v_FORDlabfin]
			!jmp eax;;; Branchement à la fin de macro NEXTD 
		EndIf
	ElseIf FORD_pas=0 ;;; Ici pas =0 risque s’il reste à cette valeur de créer une boucle infinie
		MessageRequester("Erreur ","le pas ne peut être égal à 0")
		End
	EndIf
	FINlab_#Macroexpandedcount:
EndMacro
L’analyse de la macro FORD est terminée

Passons à l’analyse de la macro NEXTD

Code : Tout sélectionner

Macro Nextd  ;(NEXTD_variable)
	
	;**************************  gestion PUSH POP *******************************
	_nbpushpop_-1  ;;; index de la pile  qui permet dans des boucles imbriquées de retrouver la bonne boucle associée à la bonne variable 
                              ;; la décrémentation nous amène dans la boucle de niveau inférieure voire à zero   au niveau des boucles indépendantes de base.
	NEXTDlabdeb=ADR_ford(varpushpop(_nbpushpop_))\ADR_deb ; recherché en function de l’index de la pile de retrouver la valeur de MacroExpandedCount donc de la boucle consernée dans MAP 
	NEXTD_fin=ADR_ford()\ADR_fin ; recherché de l’adresse de fin 
;   NEXTD_valfin=ADR_ford()\ADR_valfin
	; *******************  incrémentation de la variable par le pas *************************
	
	ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas  ;; incrémentation par son pas  de la variable liée à la boucle.
	NEXTDlabdeb=ADR_ford()\ADR_deb ;; recherche de l’adresse début de la boucle qui se trouve dans FORD 
	If NEXTD_fin<>?nextd_#Macroexpandedcount ; ; un petit pb d’initialisation de (FORD) est résolu ici 
		ADR_ford()\ADR_fin=?nextd_#Macroexpandedcount
	EndIf
	!mov eax,[v_NEXTDlabdeb];;; branchement au début de la boucle dans le FORD correspondant
	!jmp eax  ;;;; branchement au début de la boucle qui se trouve dans FORD
	
	Nextd_#Macroexpandedcount:
	;**************************  gestion PUSH POP *******************************
	_nbpushpop_-1
	If _nbpushpop_=0
		; ******** on peut ici nettoyer  la MAP  ADR_ford et les tables  varpushpop avec varpushpopB si elles  deviennent trop petites *******
		;     ClearMap(ADR_ford.ADR())
		;     varpushpop=varpushpopB
	EndIf
EndMacro
Les éléments annexes.

Code : Tout sélectionner

; Macro _q_t_ ;; elle sert pour la macro suivante
; 	"
; EndMacro
; Macro _n(__n) ;; elle sert à débuguer le prg _N(var)=> donne ( VAR=valeur de Var)
; 	_q_t_#__n#=_q_t_+Str(__n)+" "
; EndMacro
Structure ADR
		ADR_VAR.s ; nom de la variable qui ne sert pas à l"exploition mais qui permet lors de la mise au point de savoir à qui appartiennent les information de cet index
		ADR_macexpc.s{4} ; Numéro d"identification du nombre d'appel de la macro  ne sert que pour l'dentification dans la MAP
		ADR_valvar.d
		ADR_valdeb.d
		ADR_valfin.d
		ADR_valpas.d
		ADR_deb.l
		ADR_fin.l
EndStructure
L’analyse des macros FORD et NEXTD est terminée

L’incrémentation de _nbpushpop_ dans FORD et sa décrémentation dans NEXTD associés à varpushpop(_nbpushpop_) est une entité de la gestion de la pile qu’il faudra manipuler avec précaution.
Par exemple ne pas inverser les 2 instructions et ne les déplacer pas n’importe où.

Voici les 2 macros FORD et NEXTD que nous venons de construire

Code : Tout sélectionner


Macro _q_t_
	"
EndMacro
Macro _n(__n)
	_q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
Structure ADR
		ADR_VAR.s ; nom de la variable qui ne sert pas à l"exploition mais qui permet lors de la mise au point de savoir à qui appartiennent les information de cet index
		ADR_macexpc.s{4} ; Numéro d"identification du nombre d'appel de la macro  ne sert que pour l'dentification dans la MAP
		ADR_valvar.d
		ADR_valdeb.d
		ADR_valfin.d
		ADR_valpas.d
		ADR_deb.l
		ADR_fin.l
EndStructure
Macro Nextd  
	
	;**************************  gestion PUSH POP *******************************
	_nbpushpop_-1
	NEXTDlabdeb=ADR_ford(varpushpop(_nbpushpop_))\ADR_deb
	NEXTD_fin=ADR_ford()\ADR_fin
;   NEXTD_valfin=ADR_ford()\ADR_valfin
	; *******************  incrémentation de la variable par le pas *************************
	
	ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas
	NEXTDlabdeb=ADR_ford()\ADR_deb
	If NEXTD_fin<>?label_finnextd#macroexpandedcount
		ADR_ford()\ADR_fin=?label_finnextd#macroexpandedcount
	EndIf
	!mov eax,[v_NEXTDlabdeb]
	!jmp eax
	label_finnextd#macroexpandedcount:
	;**************************  gestion PUSH POP *******************************
	_nbpushpop_-1
	If _nbpushpop_=0
		; ******** on peut ici nettoyer  la MAP  ADR_ford et les tables  varpushpop avec varpushpopB si elles  deviennent trop petites *******
		;     ClearMap(ADR_ford.ADR())
		;     varpushpop=varpushpopB
	EndIf
EndMacro

Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
	
	;************************* initialisation générale une seule fois pour ce PRG **********************
	If FORDflag_=0
		Define NEXTDPOP,_nbpushpop_=0
		NewMap ADR_ford.ADR()
		Dim varpushpop.s(256) ; ici limitation à 256  (variables+ MacroExpandedCount) vous pouvez augmenter cette valeur
		Dim varpushpopB.s(256)
		FORDflag_=1
	EndIf
	
	;********************* initialisation pour chaque boucle une seule fois par boucle *************
	
	If flagford_#MacroExpandedCount#FORD_variable=0
		FORD_identification$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
		varpushpop(_nbpushpop_)=FORD_identification$
		ADR_ford(FORD_identification$)\ADR_var=_q_t_#FORD_variable#_q_t_
		ADR_ford()\ADR_macexpc=Str(MacroExpandedCount)
		ADR_ford()\ADR_valvar=FORD_variable
		ADR_ford()\ADR_deb=?Label_boucle_FORD_debut#macroexpandedcount
		ADR_ford()\ADR_fin=?label_finnextd#macroexpandedcount
		ADR_ford()\ADR_valpas=FORD_pas
		ADR_ford()\ADR_valdeb=FORD_debut
		ADR_ford()\ADR_valfin=FORD_fin
		flagford_#MacroExpandedCount#FORD_variable=1
	EndIf
	
	;**************************  Initialisation de la boucle pour une variable *************************
	
	FORD_variable=FORD_debut
	ADR_ford(Str(MacroExpandedCount))\ADR_valvar=FORD_variable

	;********************************************* debut boucle *****************************************
	Label_boucle_FORD_debut#macroexpandedcount: ; *****************   début de la boucle
	;**************************  gestion PUSH POP *******************************
	_FORD_identification_$=Str(MacroExpandedCount);+_q_t_#FORD_variable#_q_t_
	varpushpop(_nbpushpop_)=_FORD_identification_$

	_nbpushpop_+1
	
	FORD_variable=ADR_ford(_FORD_identification_$)\ADR_valvar
	If FORD_pas>0
		;******** While émulation FORD_variable <=fin test pas >0 ************
		If FORD_variable<=FORD_fin
			Goto label_finford#macroexpandedcount
		Else
			FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
			!mov eax,[v_FORDlabfin]
			!jmp eax
		EndIf
	ElseIf FORD_pas<0
		;******** While émulation FORD_variable >=fin test pas <0 ************
		If FORD_variable>=FORD_fin
			Goto label_finford#macroexpandedcount
		Else
			FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
			!mov eax,[v_FORDlabfin]
			!jmp eax
		EndIf
	ElseIf FORD_pas=0
		MessageRequester("Erreur ","le pas ne peut être égal à 0")
		End
	EndIf
	label_finford#macroexpandedcount:
EndMacro

Vous pouvez supprimer dans la structure et dans les MACROS les informations et les instructions qui ne sont pas strictement nécessaires au bon fonctionnement.

Si vous avez des questions n'hésitez pas.
A+

Re: Boucle FORD NEXTD imbriquée pas variable et réel

Publié : jeu. 19/mars/2015 23:02
par PAPIPP
Bonjour à tous

Comme l’instruction for …. Next de PB permet de modifier le paramètre début et fin de l’instruction.

L’exemple suivant le montre avec l’instruction for next de PB

Code : Tout sélectionner

       A1=0
	fin=50
	pas=20
	For deb=0 To 30 Step 10
	  Debug "** debut ** ="+Str(deb)
	  For A1=deb To  fin Step 5
	  Debug _n(deb)+_n(fin)+_n(pas)+_n(A1)
	  Next
	Next  
Pour réaliser la même chose avec FORD … NEXTD il faut initialiser et mémoriser :
FORD_deb FORD_fin et FORD_pas non pas au début de la boucle physique mais au début de la boucle logique.
Par contre FORD … NEXTD avec cette possibilité permet de modifier le pas à chaque boucle logique.

Code : Tout sélectionner

 Macro _q_t_
		"
EndMacro
Macro _n(__n)
		_q_t_#__n#=_q_t_+Str(__n)+" "
EndMacro
Structure ADR
				ADR_VAR.s ; nom de la variable qui ne sert pas à l"exploition mais qui permet lors de la mise au point de savoir à qui appartiennent les information de cet index
				ADR_macexpc.s{4} ; Numéro d"identification du nombre d'appel de la macro  ne sert que pour l'dentification dans la MAP
				ADR_valvar.d
				ADR_valdeb.d
				ADR_valfin.d
				ADR_valpas.d
				ADR_deb.l
				ADR_fin.l
EndStructure
Macro Nextd  
		
		;**************************  gestion PUSH POP *******************************
		_nbpushpop_-1
		NEXTDlabdeb=ADR_ford(varpushpop(_nbpushpop_))\ADR_deb
		NEXTD_fin=ADR_ford()\ADR_fin
		; *******************  incrémentation de la variable par le pas *************************
		
		ADR_ford()\ADR_valvar+ADR_ford()\ADR_valpas
		NEXTDlabdeb=ADR_ford()\ADR_deb
		If NEXTD_fin<>?label_finnextd#macroexpandedcount
				ADR_ford()\ADR_fin=?label_finnextd#macroexpandedcount
		EndIf
		!mov eax,[v_NEXTDlabdeb]
		!jmp eax
		label_finnextd#macroexpandedcount:
		;**************************  gestion PUSH POP *******************************
		_nbpushpop_-1
		If _nbpushpop_=0
				; ******** on peut ici nettoyer  la MAP  ADR_ford et les tables  varpushpop avec varpushpopB si elles  deviennent trop petites *******
				;     ClearMap(ADR_ford.ADR())
				;     varpushpop=varpushpopB
		EndIf
EndMacro

Macro ford(FORD_variable,FORD_debut,FORD_fin,FORD_pas)
		
		;************************* initialisation générale une seule fois pour ce PRG **********************
		If FORDflag_=0
				Define NEXTDPOP,_nbpushpop_=0
				NewMap ADR_ford.ADR()
				Dim varpushpop.s(256) ; ici limitation à 256  (variables+ MacroExpandedCount) vous pouvez augmenter cette valeur
				Dim varpushpopB.s(256)
				FORDflag_=1
		EndIf
		
		;********************* initialisation pour chaque boucle une seule fois par boucle *************
		
		If flagford_#MacroExpandedCount#FORD_variable=0
				FORD_identification$=Str(MacroExpandedCount)
				varpushpop(_nbpushpop_)=FORD_identification$
				ADR_ford(FORD_identification$)\ADR_var=_q_t_#FORD_variable#_q_t_
				ADR_ford()\ADR_macexpc=Str(MacroExpandedCount)
				ADR_ford()\ADR_valvar=FORD_variable
				ADR_ford()\ADR_deb=?Label_boucle_FORD_debut#macroexpandedcount
				ADR_ford()\ADR_fin=?label_finnextd#macroexpandedcount
; 				ADR_ford()\ADR_valpas=FORD_pas   ; ******* initialisation et mémorisation debut boucle physique
; 				ADR_ford()\ADR_valdeb=FORD_debut ; ******* initialisation et mémorisation debut boucle physique
; 				ADR_ford()\ADR_valfin=FORD_fin   ; ******* initialisation et mémorisation debut boucle physique
				flagford_#MacroExpandedCount#FORD_variable=1
		EndIf
		
		;**************************  Initialisation de la boucle pour une variable *************************
		
		FORD_variable=FORD_debut
		ADR_ford(Str(MacroExpandedCount))\ADR_valvar=FORD_variable
		;*************** si l'on veut que tous les paramétre puissent être modifier à chaque début d'une boucle logique les 3 instruction suivantes sont nécessaires 
		ADR_ford()\ADR_valpas=FORD_pas   ; ****** pour avoir un pas variable  initialisation et mémorisation debut boucle logique
    ADR_ford()\ADR_valdeb=FORD_debut ; ****** pour avoir un début variable initialisation et mémorisation debut boucle logique
    ADR_ford()\ADR_valfin=FORD_fin  ; ****** pour avoir une fin variable initialisation et mémorisation debut boucle logique

		
		;********************************************* debut boucle *****************************************
		Label_boucle_FORD_debut#macroexpandedcount: ; *****************   début de la boucle
		;**************************  gestion PUSH POP *******************************
		_FORD_identification_$=Str(MacroExpandedCount)
		varpushpop(_nbpushpop_)=_FORD_identification_$

		_nbpushpop_+1
		
		FORD_variable=ADR_ford(_FORD_identification_$)\ADR_valvar
		If FORD_pas>0
				;******** While émulation FORD_variable <=fin test pas >0 ************
				If FORD_variable<=FORD_fin
						Goto label_finford#macroexpandedcount
				Else
						FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
						!mov eax,[v_FORDlabfin]
						!jmp eax
				EndIf
		ElseIf FORD_pas<0
				;******** While émulation FORD_variable >=fin test pas <0 ************
				If FORD_variable>=FORD_fin
						Goto label_finford#macroexpandedcount
				Else
						FORDlabfin=ADR_ford(_FORD_identification_$)\ADR_fin
						!mov eax,[v_FORDlabfin]
						!jmp eax
				EndIf
		ElseIf FORD_pas=0
				MessageRequester("Erreur ","le pas ne peut être égal à 0")
				End
		EndIf
		label_finford#macroexpandedcount:
	EndMacro
	Debug " **** comparaison entre for next de PB  et FORD NEXTD avec un début variable à chaque boucle logique "
		A1=0
	fin=50
	For deb=0 To 30 Step 10
	  Debug "** debut ** ="+Str(deb)
	  For A1=deb To  fin Step 5
	  Debug _n(deb)+_n(fin)+_n(pas)+_n(A1)
	  Next
	Next  

	Debug " ************** les 3 paramètres début fin et pas peuvent être modifiés à chaque début de boucle logique *************"
	Debug " ************** ci_dessous le début varie à chaque début de boucle logique comme l'instruction for  ci dessus le permet *************"
	A1=0
	fin=50
	pas=5
	For deb=0 To 30 Step 10
	  Debug "** debut ** ="+Str(deb)
	  FORD (A1,deb, fin,pas)
	  Debug _n(deb)+_n(fin)+_n(pas)+_n(A1)
	  NEXTD
	Next  
	Debug " *************** comme pas ou step peut êtr une varaible voici ce que for... next de PB  ne peut pas faire (pas variable à chaque boucle logique) ****************** " 
		Debug " ************** ci_dessous le pas varie à chaque début de boucle logique *************"
	A1=0
	fin=200
	pas=20
	For pas=5 To 30 Step 5
	  Debug "** PAS ** ="+Str(pas)
	  FORD (A1,deb, fin,pas)
	  Debug _n(deb)+_n(fin)+_n(pas)+_n(A1)
	  NEXTD
	Next  
A+