CountChars function in assembler

Share your advanced PureBasic knowledge/code with the community.
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

I have already seen your tutorial.


Oh, you seem a patient analiser.

For me is not difficult to analise assembler code, it is impossible :!:

So i prefer to create than to analize.
However, i must have patient for to explain it.
An i will try it next time. :wink:


AL
LJ
Enthusiast
Enthusiast
Posts: 177
Joined: Wed Apr 30, 2003 4:00 pm

Hey

Post by LJ »

@Psychophanta,

You are doing just fine. Creating is very good. I'm a private education consultant and so explaining and analyzing is what I do best. You can leave the explaining up to me, no problem. We make a good team. If you did all the explaining, then you wouldn't need me :wink:

I like the assembly code you have created, it is truly beautiful. The last two tutorials would not have been possible without you. Thank you and if you want to work again on another tutorial for the Inline Assembly sticky, we will do it again.

Peace

Lj
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Peace & Anarchy hehehe :D


AL
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

I found a big bug in CountStrings()
I've corrected it:

Code: Select all

Procedure.l CountStrings(a.s,s.s)
  !cld          ;clear DF (Direction Flag)
  !mov edi,dword[esp]   ;load edi register with pointer to first string
  !mov esi,dword[esp+4] ;load esi register with pointer to second string (the string to search)
  !xor eax,eax    ;set eax register to NULL
  !mov bl,al      ;set bl register to NULL
  !mov edx,esi  ;save this value in edx to avoid, as much as possible, to have to read data from memory in the main loop.
  !;If any of two strings is empty then end program and matches found is 0:
  !cmp byte[esi],bl  ;test if second string is empty
  !jz fin           ;if so, then end
  !;Main loop:
  !mainloop:
  !cmp byte[edi],bl  ;check if end of first string is reached
  !jz fin   ;if not reached then end
  !mov esi,edx  ;restore this
  !cmpsb  ;what this instruction do is just compare byte[edi] with byte[esi] and increment edi and esi values by 1
  !jnz mainloop ;if byte[edi]=byte[esi] then goto match label, because a match byte was found...
  !;match: ;here we have got inside a second treatment: We are in a possible total match, lets see if it is a complete match or it is a fake:
  !mov ecx,edi ;save this position
  !@@:
  !cmp byte[edi],bl  ;check if end of first string is reached
  !jz fin   ;if not reached then end
  !cmp byte[esi],bl  ;check if end of second string is reached
  !jz @f   ;if so, here was a complete match
  !cmpsb   ;compare one more byte
  !jz @r   ;if equal, lets see if the deceit continues, or rather it could be a real complete match.
  !mov edi,ecx  ;ohhh! it was a deceit! Restore this
  !jmp mainloop ;What a patient! lets continue searching for another possible match and why not, a possible complete match...
  !;complete match was found:
  !@@:inc eax    ;increment complete matches counter
  !jmp mainloop   ;lets search for another possible complete match!
  !fin:
  ProcedureReturn
EndProcedure
;Grrr!: Z-80 had conditional CALL, Ix86 doesn't !?
a$="ureruPururePe ruPurePurPuPure uresdfhg ureeurPeruPuruee sPuuredil hPPPrtur eurePuree urePurePuure"

MessageRequester("",Str(CountStrings(a$,"Pure")),0)

;Can use function input parameters as normal pointers:
;Procedure.l CountStrings(*a,*s)
;but then you have to call function using pointers too:
;CountStrings(@a$,@"Pure")
In previous one, if you do something like:

Code: Select all

a$="ureruPururePe ruPurePurPuPure uresdfhg ureeurPeruPuruee sPuuredil hPPPrtur eurePuree urePurePuure"

MessageRequester("",Str(CountStrings(a$,"PPr")),0)
you got wrong result because i reset the 1st String pointer decrementing it by one, and the MUST is to save where we are when find a byte match, and restore it if entire string-to-find was not matched.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

are you sure you corrected it?

counting "abcdeaaa" , "a" returns 3?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

Sorry, sorry, this is more difficult than i thought. I am on it, and i will put it bug-free (promised to myself) in less than 2 hours.
And tomorrow you will have RFindString() too; (promised to myself too) :evil:
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

see? :-)

i ALWAYS run into bugs :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

like devils do :twisted:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Post by Psychophanta »

That's it :!:

Blueznl, you are fully invited to find a bug now.

Code: Select all

Procedure.l CountStrings(a.s,s.s)
  !cld          ;clear DF (Direction Flag)
  !mov edi,dword[esp]   ;load edi register with pointer to first string
  !mov esi,dword[esp+4] ;load esi register with pointer to second string (the string to search)
  !xor eax,eax    ;set eax register to NULL
  !mov bl,al      ;set bl register to NULL
  !mov edx,esi  ;save this value in edx to avoid, as much as possible, to have to read data from memory in the main loop.
  !;If any of two strings is empty then end program and matches found is 0:
  !cmp byte[esi],bl  ;test if second string is empty
  !jz fin           ;if so, then end
  !;Main loop:
  !mainloop:
  !cmp byte[edi],bl  ;check if end of first string is reached
  !jz fin   ;if not reached then end
  !mov esi,edx  ;restore this
  !cmpsb  ;what this instruction do is just compare byte[edi] with byte[esi] and increment edi and esi values by 1
  !jnz mainloop ;if byte[edi]=byte[esi] then goto match label, because a match byte was found...
  !;match: ;here we have got inside a second treatment: We are in a possible total match, lets see if it is a complete match or it is a fake:
  !mov ecx,edi ;save this position
  !@@:
  !cmp byte[esi],bl  ;check if end of second string is reached
  !jz @f   ;if so, here was a complete match
  !cmpsb   ;compare one more byte
  !jz @r   ;if equal, lets see if the deceit continues, or rather it could be a real complete match.
  !mov edi,ecx  ;ohhh! it was a deceit! Restore this
  !jmp mainloop ;What a patient! lets continue searching for another possible match and why not, a possible complete match...
  !;complete match was found:
  !@@:inc eax    ;increment complete matches counter
  !jmp mainloop   ;lets search for another possible complete match!
  !fin:
  ProcedureReturn
EndProcedure
;Grrr!: Z-80 had conditional CALL, Ix86 doesn't !?
a$="ureruPururePe ruPurePurPuPure uresdfhg ureeurPeruPuruee sPuuredil hPPPrtur eurePuree urePurePur"
b$="abcdeaaa"
c.s="Pur":PokeB(@c+3,0):PokeB(@c+4,Asc("e")):PokeB(@c+5,0)
d$="a"
MessageRequester("Should be 1",Str(CountStrings(PeekS(@c+4),"e")),0)
MessageRequester("Should be 1",Str(CountStrings(c,"Pur")),0)
MessageRequester("Should be 0",Str(CountStrings(c,"Pure")),0)
MessageRequester("Should be 1",Str(CountStrings(a$,"PPr")),0)
MessageRequester("Should be 4",Str(CountStrings(b$,"a")),0)
MessageRequester("Should be 1",Str(CountStrings(d$,"a")),0)
MessageRequester("Should be 0",Str(CountStrings(d$,"aa")),0)
MessageRequester("Should be 1",Str(CountStrings(b$,"aa")),0)
MessageRequester("Should be 4",Str(CountStrings(a$,"Pure")),0)


;Can use function input parameters as normal pointers:
;Procedure.l CountStrings(*a,*s)
;but then you have to call function using pointers too:
;CountStrings(@a$,@"Pure")
Final and bug-free promised :!:
User avatar
Psychophanta
Always Here
Always Here
Posts: 5153
Joined: Wed Jun 11, 2003 9:33 pm
Location: Anare
Contact:

Re: CountChars function in assembler

Post by Psychophanta »

Same idea but for any generic byte sequence, not just alfanumeric ones. This time not in assembler, because it does not worth it:

Code: Select all

Procedure.i EncontrarSecuenciaenCadena(*cadena.byte,*secuencia.byte,lc.i,ls.i,List e.i())
  ;Cuenta las veces que una cadena dada de bytes se repite dentro de otra cadena dada de bytes
  ; '*cadena.byte' es la cadena principal de bytes
  ; '*secuencia.byte' es la secuencia a buscar
  ; 'lc.i' es la longitud de la cadena principal
  ; 'ls.i' es la longitud de la secuencia a buscar
  ; 'List e.i()' es la lista para rellenar de en qué posiciones, dentro de '*cadena.byte', están las coincidencias encontradas
  ; Devuelve el número de coincidencias
  Protected *cadena0.byte=*cadena,*secuencia0.byte=*secuencia,n.i=ListSize(e())
  While *cadena-*cadena0<=lc
    While *cadena\b=*secuencia\b
      *secuencia+1:*cadena+1
      If *secuencia-*secuencia0=ls:AddElement(e()):e()=*cadena-*cadena0-ls
      ElseIf *cadena-*cadena0=lc:Break 2; => existe secuencia truncada al final de la cadena, concretamente en 'lc-(*secuencia-*secuencia0)'
      Endif
    Wend
    *secuencia=*secuencia0
    *cadena+1
  Wend
  ProcedureReturn ListSize(e())-n
EndProcedure
http://www.zeitgeistmovie.com

while (world==business) world+=mafia;
Post Reply