Page 1 sur 1

Simuler un gosub avec une macro ?

Publié : mer. 03/mai/2006 11:28
par Ulix
Est-il possible de simuler un Gosub avec une macro ?

Pourquoi cette question ?
D'abord je m'attendais a ce que la nouvelle version de PB (Fred tu peut encore la rajouté) permette de geré des gosubs interne a une procedure avec un accés aux variables locale. Hélas...:mad: je suis déçu que ce ne soit pas le cas !

Ensuite un exemple etant plus parlant, voici ce que désirais faire :

Code : Tout sélectionner



;Procedure affichage() 		; Si décommentaire, marche pas
;Protected a, b, c, d
;Static f, g, h, i

a=100:b=50:c=25:d=10

For nombre = 1 To 4
Select nombre
Case 1 : Gosub colonne1
Case 2 : Gosub colonne2
Case 3 : Gosub colonne1_3
Case 4 : Gosub colonne1_5:Gosub colonne2
EndSelect
Next
End


Colonne1:
f+1
Debug "Utilisation de Colonne1 = "+Str(f)
Debug a=a+c
Return

Colonne2:
g+1
Debug "Utilisation de Colonne2 = "+Str(g)
Debug b=d+c
Return

Colonne1_3:
h+1
Debug "Utilisation de Colonne1_3 = "+Str(h)
Debug a=a-b
Return

Colonne1_5:
i+1
Gosub colonne1
Gosub colonne1_3
Debug "Utilisation de Colonne1_5 = "+Str(g)
Return
;EndProcedure

;affichage()




Quelques réflexions (vous les savez !)

On notera que les sous-programmes (labels) peut être appele de plusieurs endroits différents, qu'il peut être utilisé plusieurs fois, enfin qu'un sous-programme peut appeler un autre sous-programme.
Une fois le sous-programme fini, le programme reprend a l'instruction qui suit celle qui l'avait appelé.
Utilisation des gosub/return simplifie le code et le rend plus compacte.
Enfin l'accées aux variables locales permet de ne pas muiltiplié les procedures a l'excés et d'avoir une ribanbelle de données a passés comme arguments.
Bref, je leurs trouve que des avantages ! :lol:

Puisque le "Gosub nouvelle version" n'est pas au rendez-vous, ma question est :

Est-il possible de simuler un Gosub avec une macro ?


Est-il possible lorsque l'on appelle un sous-programme :
- de mémorisé la position mémoire de l'instruction qui appele le sous-programme (j'espére que vous comprenez),
- d'aller au sous-programme (le label:)
- d'executer le sous-programme et une fois finie (donc le return)
- de se repositionné sur l'instruction suivant (position mémoire + 1 instruction).


Je suppose que l'on doit faire appelle a du code assembleur, mais est-il possible d'intégré cela dans une macro ?


Est-il possible de "lorsque l'on appelle un sous-programme, de mémorisé la position mémoire de l'instruction qui appele le sous-programme" ?
Il y a bien la posibilité de connaitre l'adresse d'une variable, la position mémoire : Pointeur = ?Variable, peut-on connaitre l'instruction courante ?

Y a t-il des exemples ? :oops:


Merci de votre patience et de m'avoir lu ! :wink:

Publié : mer. 03/mai/2006 21:03
par Guimauve
Il suffit simplement d'essayer ...

Enfin je ne sais pas si ça va répondre à ta question, à toi de voir.

Code : Tout sélectionner

Macro SubRoutineColone1()
   f+1
   Debug "Utilisation de Colonne1 = "+Str(f)
   Debug a=a+c
EndMacro 
   
Macro SubRoutineColonne2()
   g+1
   Debug "Utilisation de Colonne2 = "+Str(g)
   Debug b=d+c
EndMacro 
   
Macro SubRoutineColonne1_3()
   h+1
   Debug "Utilisation de Colonne1_3 = "+Str(h)
   Debug a=a-b
EndMacro
   
Macro SubRoutineCcolonne1_5()
   i+1
   SubRoutineColone1()
   SubRoutineColonne1_3()
   Debug "Utilisation de Colonne1_5 = "+Str(g)
EndMacro 


Procedure affichage()       ; Si décommentaire, marche pas
   Protected a, b, c, d
   Static f, g, h, i
   
   a=100
   b=50
   c=25
   d=10
   
   For nombre = 1 To 4
      Select nombre
         Case 1
            SubRoutineColone1()

         Case 2 
            SubRoutineColonne2()

         Case 3 
            SubRoutineColonne1_3()
 
         Case 4 
            SubRoutineCcolonne1_5()
            SubRoutineColonne2()

      EndSelect
   Next
   
   End

EndProcedure

affichage()
Attention très important.

Comme les procédures, si une macro en appelle une autre, le code de la macro appelée doit être placer avant celui de la macro appelante.

A+
Guimauve

Publié : jeu. 04/mai/2006 11:12
par Ulix
Désolé Guimauve !

C'est déja ce que je fais.
Au niveau code source, ça le rend plus lisible - Ok
Au niveau executable, il grossit très rapidement pour peu de chaque macro contiennent plusieurs lignes et que l'on appele plusieurs fois les macros. En effet les macros inserrent le code qu'elle contient a l'endroit d'où on les appelent.

Alors que les vrais "Gosub" permette d'utilisé plusieurs fois la même portion de code. Donc un code plus petit !

Je pensais plutôt a quelque chose comme çà :

Code : Tout sélectionner


Procedure.l go_sub(a, b, c)
  If a = 1
    !jmp near lbl_a1;<-a Gosub here write next address (rett) into  at compilation time and then just jumps.
    !rett:;                                                       |
  EndIf;                                                         |
  ;                                                              /
  Debug "a="+Str(a)+", b="+Str(b)+", c="+Str(c) ;               |
  ProcedureReturn ;                                           /
;                                                              /
!lbl_a1:;                                                     /
;                                                            /
  a = b+c;                                                  /
!jmp near rett;<-------------------------------------------/
EndProcedure

go_sub(1, 1, 1) 

Trouvé sur :

http://www.purebasic.fr/english/viewtop ... ight=gosub


Apparament on mémorise l'endroit d'où on part, on fait un saut jusqu'au label, on l'execute, puis on refait un saut a l'endroit d'où on vient.
Peut-on simule cela avec les macros, ou bien intégré cela dans une macro ?

Mon niveau en langage machine frise la 0, alors de la a comprendre toutes les subtilités ?? :mad:

Trouvé aussi cela :

Code : Tout sélectionner

Procedure.l go_sub(a,b,c)
  If a=1
   ;Gosub routine1
                      !mov dword[l_routine1_ret-4],ret1-l_routine1_ret
                      !jmp l_routine1
                      !ret1:
  EndIf
 
  If a=3
   ;Gosub routine1  ;again
                      !mov dword[l_routine1_ret-4],ret2-l_routine1_ret
                      !jmp l_routine1
                      !ret2:
  EndIf

  Debug "a="+Str(a)+", b="+Str(b)+", c="+Str(c)
  ProcedureReturn
; --------SubRoutines:
  routine1:
   ;Gosub NestedRoutine
                      !mov dword[l_routine2_ret-4],NestRet-l_routine2_ret
                      !jmp l_nestedroutine
                      !NestRet:
    a=b+c
 ;Return:
                      !db $E9,0,0,0,0;<-jmp OpCode and a dword space
                      routine1_ret:

  NestedRoutine:
    b+c
 ;Return:
                      !db $E9,0,0,0,0;<-jmp OpCode and a dword space
                      routine2_ret:
EndProcedure

#PAGE_READWRITE=4
VirtualProtect_(?routine1,?routine2_ret-?routine1,#PAGE_READWRITE,@OrigMode.l)
go_sub(1,1,1)
VirtualProtect_(?routine1,?routine2_ret-?routine1,OrigMode.l,@Mode)
FlushInstructionCache_(GetCurrentProcess_(),?routine1,?routine2_ret-?routine1)

Si quelqu'un sait comme intégrer cette façon de faire dans une Macro, je suis prenneur !
Merci d'avance pour aux idées et solutions. :idea:

Publié : jeu. 04/mai/2006 14:10
par Flype
Tu te compliques la vie à vouloir absolument tout gérer comme çà.
Imagine cette façon de faire dans un programme dépassant les 2 ou 3000 lignes : au secours ! Tu dis qu'il n'y a que des avantages à utiliser les gosub/goto, moi j'y vois surtout un gros manque de lisibilité du code source.

mon expérience perso me conduit à tout mettre en procédures, sinon je n'arrive pas à me dépatouiller dès lors qu'un projet grossit trop...

par contre si tu as un gros besoin de rapidité, je peux comprendre et encore...

Publié : jeu. 04/mai/2006 15:26
par Guimauve
Personnellement, moi je ferais des procédures avec les Sous routines si elles ont plusieurs instructions. Si non, des macros.
Oui mais les procédures c'est plus lent et les macros font grossir la taille de l'exe.
Ça va prendre quoi, 50 à 75 Nanosecondes de plus pour faire le travaille. Le fichier exe va faire 100 ko de plus.

Les disques durs les plus courants font 80 Go.

De plus, on ne fait pas d'omelette sans casser des oeufs.

Selon mon point de vue, les instructions GoSub/Goto c'est à banir de la programmation purement et simplement.

Voilà

Guimauve