Appels de fonctions dans une fonction

Pour discuter de l'assembleur
Heis Spiter
Messages : 1092
Inscription : mer. 28/janv./2004 16:22
Localisation : 76
Contact :

Appels de fonctions dans une fonction

Message par Heis Spiter »

Bonsoir à tous :).

Ca faisait longtemps que j'étais passé ;). Mais ça n'est pas pour autant que j'ai arrêté de programmer, bien au contraire. Mais là, je coince et je vais avoir besoin de votre aide. Le but étant d'appeler une fonction dont le contenu est en assembleur, par une autre fonction en PureBasic. Au détail près que cela ne fonctionne pas...
Voici l'exemple parfait de ce que je veux faire (en simplifé bien sûr, mais ça reproduit le pépin) :

Code : Tout sélectionner

Procedure.s ASM(str.s)
  ! mov eax, dword [p.v_str]
  ProcedureReturn 
EndProcedure

Procedure Test()
  Debug ASM("pouet")
EndProcedure
Merci par avance pour vos éclaircissements.
Heis Spiter, webmaster du site http://www.heisspiter.net
Développeur principal et administrateur du projet Bird Chat
Parti courir au bonheur du dév. public et GPL :D
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Code : Tout sélectionner

!EXTRN _SYS_CopyString@0

Procedure.s ASM(str.s)
	!MOV    Edx,dword [p.v_str]
	!CALL    _SYS_CopyString@0
	!PUSH    Eax
	!PUSH    dword [p.v_str]
	!CALL    _SYS_FreeString@4
	!POP    Eax
	!ADD    Esp,4 
	!RET    4
EndProcedure

Procedure Test()
  Debug ASM("pouet")
EndProcedure

Test()
KarLKoX
Messages : 1191
Inscription : jeu. 26/févr./2004 15:36
Localisation : France
Contact :

Message par KarLKoX »

erix14 a écrit :

Code : Tout sélectionner

!EXTRN _SYS_CopyString@0
Procedure Test()
  Debug ASM("pouet")
EndProcedure

Test()
Tient un poto du pouet test ^_^
"Qui baise trop bouffe un poil." P. Desproges
Heis Spiter
Messages : 1092
Inscription : mer. 28/janv./2004 16:22
Localisation : 76
Contact :

Message par Heis Spiter »

Merci pour ta réponse erix14. Mais malheureusement, j'ai à la fois des difficultés pour comprendre ton exemple, et des difficultés à l'adapter sur ton code source...
Voici ma fonction (pas encore optimisée ni débuggée) :

Code : Tout sélectionner

Procedure.s split(Chaine.s, Delimiteur.s)
  
  Static previous
  Lendel.l
  del.l
  Toreturn.s
  ! push dword [p.v_Delimiteur]
  ! call _PB_Len@4
  ! mov dword [p.v_Lendel], eax
  ! mov ecx, dword [p.v_Lendel]
  ! add ecx, dword [s_split.v_previous]
  ! push ecx
  ! push dword [p.v_Delimiteur]
  ! push dword [p.v_Chaine]
  ! call _PB_FindString@12
  ! mov dword [p.v_del], eax
  ! cmp dword [p.v_del], 0
  ! je _jumpcmp
    ! mov ecx, dword [p.v_del]
    ! sub ecx, dword [s_split.v_previous]
    ! sub ecx, dword [p.v_Lendel]
    ! mov ebx, dword [s_split.v_previous]
    ! add ebx, dword [p.v_Lendel]
    ! push ecx
    ! push ebx
    ! push dword [p.v_Chaine]
    ! call _PB_Mid@16
    ! mov dword [p.v_Toreturn], eax
    ! mov edx, dword [p.v_del]
    ! mov dword [s_split.v_previous], edx
    ! jmp _result
    ! _jumpcmp :
    ! cmp dword [s_split.v_previous], 0
    ! jne _eos
      ! mov eax, dword [p.v_Chaine]
      ProcedureReturn
    ! _eos :
      ! push dword [p.v_Chaine]
      ! call _PB_Len@4
      ! add eax, 1
      ! sub eax, [s_split.v_previous]
      ! push eax
      ! push dword [p.v_Chaine]
      ! call _PB_Right@12
      ! mov dword [p.v_Toreturn], eax
      ! mov dword [s_split.v_previous], 0
  ! _result :
  ! mov eax, dword [p.v_Toreturn]
  ProcedureReturn
  
EndProcedure

Procedure Test()

  STR.s = "  Premier découpage / Deuxième découpage / Troisième découpage"
  Debug split(STR.s, " / ")
  Debug split(STR.s, " / ")
  Debug split(STR.s, " / ")
 
EndProcedure

Test()
Pourrais-tu (ou un autre d'ailleurs :P). M'expliquer comment adapter ton exemple ? Et aussi me dire pourquoi le ProcedureReturn, comme défini dans la doc ne fonctionne pas ?

Merci

PS : Oui, fanatique des pouet tests, et des "ceci est un test... ça marche ?"
PS2 : D'un point de vue optimisation qu'est-ce qui est le mieux ? Le "call" ou le "invoke" ?
Heis Spiter, webmaster du site http://www.heisspiter.net
Développeur principal et administrateur du projet Bird Chat
Parti courir au bonheur du dév. public et GPL :D
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Est-ce que ça t'intéresse une véritable fonction Split qui retourne un tableau de String :

Code : Tout sélectionner

Structure TString ; Pour définir des tableaux de pointeurs de chaînes.
	String.s[$7FFFFFFF] ; Avec ça on a de quoi faire, mais attention à utiliser uniquement avec des pointeurs !
EndStructure
Structure TChar ; Pour définir des tableaux de pointeurs de caractères.
	Char.c[$7FFFFFFF] ; Avec ça on a de quoi faire, mais attention à utiliser uniquement avec des pointeurs !
EndStructure

Macro split(Chaine, Delimiteur)
	split_(@Chaine, @Delimiteur)
EndMacro
Procedure split_(*Chaine.Character, *Delimiteur.Character)
	If *Chaine And *Delimiteur
		*Chaine2.Character = *Chaine
		TabSize = 0
		Dim TabTemp.Long(0)
		*ptr.Character = *Chaine2
		While *ptr\c
			If *ptr\c = *Delimiteur\c
				*ptr2.Character = *ptr + 1
				*dlt.Character = *Delimiteur + 1
				While *ptr2\c = *dlt\c
					*ptr2 + 1
					*dlt + 1
				Wend
				If *dlt\c = 0
					Longueur = *ptr - *Chaine2 + 1
					*UneChaine.TChar = AllocateMemory(Longueur)
					CopyMemory(*Chaine2, *UneChaine, Longueur-1)
					*UneChaine\Char[Longueur] = 0 ; 0 à la fin de la chaîne.
					TabSize + 1
					Redim TabTemp.Long(TabSize)
					TabTemp(TabSize-1)\l = *UneChaine
					TabTemp(TabSize)\l = 0
					*Chaine2 = *ptr2
					*ptr = *ptr2
				EndIf
			EndIf
			*ptr + 1
		Wend
		Longueur = *ptr - *Chaine2 + 1
		*UneChaine = AllocateMemory(Longueur)
		CopyMemory(*Chaine2, *UneChaine, Longueur)
		TabSize + 1
		Redim TabTemp.Long(TabSize)
		TabTemp(TabSize-1)\l = *UneChaine
		TabTemp(TabSize)\l = 0
		ptrTab = AllocateMemory(TabSize*4)
		CopyMemory(@TabTemp(), ptrTab, TabSize*4)
		ProcedureReturn ptrTab
	Else
		ProcedureReturn 0
	EndIf
EndProcedure

Procedure Test()
	STR.s = "  Premier découpage / Deuxième découpage / Troisième découpage"
	*TabStr.TString = split(STR, " / ")
	If *TabStr
		ind = 0
		While *TabStr\String[ind]
			Debug *TabStr\String[ind]
			ind + 1
		Wend
	EndIf
EndProcedure

Test()
Debug "-------------------"
STR.s = "Bonjour à tous les décodeurs PureBasic qui lit ce poste."
*TabStr.TString = split(STR, " ")
Debug *TabStr\String[0]
Debug *TabStr\String[5]
Debug *TabStr\String[9]
Debug "-------------------"
STR.s = "esttotocecitototesttotoun"
*TabStr.TString = split(STR, "toto")
Debug *TabStr\String[1] + " " + *TabStr\String[0] + " " + *TabStr\String[3] + " " + *TabStr\String[2]
Je pense que ce code est très rapide, mais il y a toujours moyen de l'améliorer. Si tu veux de la vitesse il ne faut pas travailler avec Split, mais avec des couples (DébutChaînes, LongueurChaîne) et cela directement avec la chaîne originale sans jamais faire de copies des sous chaîne trouvées.

Call : appelle une fonction directement avec son adresse
Invoke : appels indirects, récupère l'adresse de la fonction puis fait un Call
Heis Spiter
Messages : 1092
Inscription : mer. 28/janv./2004 16:22
Localisation : 76
Contact :

Message par Heis Spiter »

Génial comme code erix14 ! Je suis impressionné 8O. Voila qui est mieux et moins buggé que mon assembleur...
Heis Spiter, webmaster du site http://www.heisspiter.net
Développeur principal et administrateur du projet Bird Chat
Parti courir au bonheur du dév. public et GPL :D
erix14
Messages : 480
Inscription : sam. 27/mars/2004 16:44
Contact :

Message par erix14 »

Voici un code pour une utilisation spécifique de Split, j'utilise la chaîne d'origine comme mémoire pour les sous chaînes. Le test de rapidité contient le code SplitArray de Flype. (j'utilise ma classe ITest http://www.rx14.info/public/index.php?a=opti)

Code : Tout sélectionner

Structure TString ; Pour définir des tableaux de pointeurs de chaînes.
	String.s[$7FFFFFFF] ; Avec ça on a de quoi faire, mais attention à utiliser uniquement avec des pointeurs !
EndStructure
Structure TChar ; Pour définir des tableaux de caractères.
	Char.c[$7FFFFFFF] ; Avec ça on a de quoi faire, mais attention à utiliser uniquement avec des pointeurs !
EndStructure

Macro split(Chaine, Delimiteur)
	split_(@Chaine, @Delimiteur)
EndMacro
Procedure split_(*Chaine.Character, *Delimiteur.Character)
	Static TabOutput.l
	If *Chaine And *Delimiteur
		If TabOutput = 0 : TabOutput = AllocateMemory(404) : EndIf
		*Tab.Long = TabOutput
		*ptr.Character = *Chaine
		While *ptr\c
			If *ptr\c = *Delimiteur\c
				*ptr2.Character = *ptr + 1
				*dlt.Character = *Delimiteur + 1
				While *ptr2\c = *dlt\c
					*ptr2 + 1
					*dlt + 1
				Wend
				If *dlt\c = 0
					*ptr\c = 0
					*Tab\l = *Chaine
					*Tab + 4
					If *Tab = TabOutput+400 ; 100 sous chaînes maxi
						*Tab\l = 0
						ProcedureReturn TabOutput
					EndIf
					*Chaine = *ptr2
					*ptr = *ptr2
				EndIf
			EndIf
			*ptr + 1
		Wend
		*Tab\l = *Chaine
		*Tab + 4
		*Tab\l = 0
		ProcedureReturn TabOutput
	Else
		ProcedureReturn 0
	EndIf
EndProcedure
;/ Codé par Flype
Macro CountArray(array)
	(PeekL(@array-8))
EndMacro
Procedure.l SplitArray(array.s(1), text.s, separator.s = ",") ; String to Array
	Protected index.l, Size.l = CountString(text, separator)
	Redim array.s(Size)
	For index = 0 To Size
		array(index) = StringField(text, index + 1, separator)
	Next
	ProcedureReturn Size
EndProcedure 
;-
Global MonTest.ITest = New_Test(276)
For t=0 To #ITest
	MonTest\Start(1)
	STR.s = "Bonjour à tous les décodeurs PureBasic qui lit ce poste."
	*TabStr.TString = split(STR, " ")
	MonTest\Stop(1)
Next
MonTest\SetTitle(1, "Erix14 : "+*TabStr\String[5])
;/
Dim a.s(0)
For t=0 To #ITest
	MonTest\Start(2) 
	STR.s = "Bonjour à tous les décodeurs PureBasic qui lit ce poste."
	SizeArray = SplitArray(a(), STR, " ")
	MonTest\Stop(2)
Next
MonTest\SetTitle(2, "Flype : "+a(5))
;/
For t=0 To #ITest
   MonTest\Start(3)
   MonTest\Stop(3)
Next
MonTest\SetTitle(3, "A vide")

MonTest\Display(2)
Intel(R) Pentium(R) 4 CPU 2.40GHz
2.43 GHz, 768Mo de RAM
NVIDIA GeForce4 Ti 4800 SE - 128Mo
Microsoft Windows XP Professionnel Service Pack 2
-----------------------------------
Erix14 : PureBasic
1860 cycles CPU (minimum)
1966 cycles en moyenne
X 6.42
-----------------------------------
Flype : PureBasic
11944 cycles CPU (minimum)
12731 cycles en moyenne
X 1.00
-----------------------------------
A vide
0 cycles CPU (minimum)
22 cycles en moyenne
X ???
-----------------------------------
linkerstorm
Messages : 20
Inscription : lun. 29/janv./2007 7:13

Message par linkerstorm »

Heis Spiter a écrit :Merci pour ta réponse erix14. Mais malheureusement, j'ai à la fois des difficultés pour comprendre ton exemple, et des difficultés à l'adapter sur ton code source...

...

Pourrais-tu (ou un autre d'ailleurs :P). M'expliquer comment adapter ton exemple ? Et aussi me dire pourquoi le ProcedureReturn, comme défini dans la doc ne fonctionne pas ?

Merci
Salut Heis Spiter.

Voici l'explication du code de erix14 (je demande à ce dernier et à Tonton de me corriger si je me trompe et n'hésitez pas, c'est ma première intervention sur le forum ASM !).

En fait, en PB les paramètres des fonctions sont passés par valeur, c'est-à-dire qu'une copie de la valeur des paramètres est réalisée avant l'appel proprement dit, à l'exception des chaînes, qui sont passées par référence (seulement l'adresse de la chaîne est passée).

erix14 a pallié au problème en copiant la chaîne pour simuler une sorte de passage par valeur d'une chaîne.

En modifiant légèrement son code, on peut laisser d'ailleurs la tâche de copie à PB :

Code : Tout sélectionner

Procedure.s ASM(str.s)
	Copie.s = str
	! mov eax, dword [p.v_Copie]
	ProcedureReturn
EndProcedure

Procedure Test()
  Debug ASM("pouet")
EndProcedure

Test()
Ce qui revient grosso modo au code de erix14 ;)

Dis-moi si tu es satisfait de cette explication (si j'ai été assez clair en fait) ;)

linkerstorm
Répondre