Page 1 of 2

Gosub Return macros

Posted: Sun Jun 30, 2013 11:21 pm
by idle
Redefined Gosub, Return, Goto macros for those that want them
your labels need to be defined with inline asm directive "!"

Code: Select all

!some_label: 
It uses Pb macro expansion to change the variables in the Fasm preprocesor directives
If you Gosub from within a select statement you need to specify the nest depth you're breaking out of
eg from a nest of two Selects statement Gosub(label,2) will assemble

Code: Select all

;Gosub(label,2)
pop rax 
pop rax  
!jmp label 
!label__Return:
!@@:   
And the Return(label) will automatically rebalance the stack

Code: Select all

!label: 

;Return(label)
!push rax
!push rax 
!jmp label__Return

The Macros

Code: Select all

;Reimplimentation of Gosub Return Goto for use in procedures via PB macro and  fasm preprocesor directives
;Idle 2/4/2013 PB4.61 -> 5.20 x86/x64 
;notes
;Uses inline asm labels prefix with "!" mark 
;In some cases you will need to manually set depth parameter to suit the nesting level 
;specifically when using Gossub and Goto from within Select statements 

;v1.1 
;removed the need to specify depth on return macro  

Macro Gosub(label,depth=0)  ;depth is needed to jmp and return out and in of nested selects 
   CompilerIf depth
      CompilerIf SizeOf(integer) = 8  
         !label#_a=depth                               ;set a fasm preprocesor variable for the nest depth 
         !repeat label#_a                                 
           !pop rax                                           ;assmebless pop rax  
           !end repeat
       CompilerElse 
          !label#_a=depth 
          !repeat label#_a
           !pop eax
         !end repeat 
     CompilerEndIf   
  CompilerElse   
      !label#_a=0 
  CompilerEndIf
   !jmp label                                                   
   !if ~ defined label#__return | defined @f       ;defines the return label if it's not defined  
      !label#__return:                                            ;assembles return label          
      !@@:                                                             ;assembles anonymous label 
   !end if    
 EndMacro 

Macro Return(label)  
   
   !if label#_a > 0  
   CompilerIf SizeOf(integer) = 8  
         !repeat label#_a
           !push rax
         !end repeat   
     CompilerElse 
       !repeat label#_a
            !push eax
         !end repeat   
     CompilerEndIf  
 !end if 
 !jmp label#__return 
EndMacro    

Macro Goto(label,depth=0)  ;depth is needed to jmp and return out and in of nested selects 
   CompilerIf depth 
      CompilerIf SizeOf(integer) = 8 
         !repeat depth 
            !pop rax
         !end repeat    
      CompilerElse 
         !repeat depth 
            !pop eax 
         !end repeat    
    CompilerEndIf    
 CompilerEndIf 
   !jmp label 
EndMacro    

Macro label(name)
   !name#:
EndMacro 

;example 
  
Procedure b()
  Protected  v.i=5 ,x=6
      
  Repeat              
    Select x 
      Case 6      
        Select v
          Case 5   
            Gosub(l1,2)   ;we are nested in 2 selects and exiting 2 levels to l1 
            Debug "after gosub Select l1 "+Str(v)
          Case 6        
            Gosub(l2,2) ;
            Debug "after gosub select l2 "+Str(v)
          Default 
            Goto(l3,2) ;we are nested in 2 selects and exiting 2 levels to l3 
        EndSelect
    EndSelect 
  ForEver  
    
  label(l3)    
   ProcedureReturn v
      
  !l1:             ;we jumped here from within the select statement using Gosub(l1,2) the stack pointer is ballanced    
    v+1            ;without the stack adjustment the protected variables wouldn't be accessible after the jump  
    Return(l1);l,2)  ;return back to the select statement which is nested 2 levels using Return(l1,2) and restore the stack pointer   
      
  !l2:          
    v+1 
    Return(l2);  ;comment out  
    Debug "goto l3"  
    Goto(l3)        ;if you commented out Return(l2,2) you will jump to l3 from here no need to adjust depth
    ;you got here having exited the Select at Case 6 of Select v 
 EndProcedure
 
 
Procedure c()
            
  w.s=Chr(65)
  For i=Asc("B") To Asc("Z")
    Gosub(cc)                 
    Gosub(cc1)
    w+Chr(i)
  Next i
  Debug w
  ProcedureReturn
  
  !cc:
  w.s+"-"
  Gosub(ee)
  Return(cc)
  
  !cc1: 
  w.s+"-"
  Return(cc1)
  
  !ee:
  w.s+"."
  Return(ee)
          
 EndProcedure
 
 
 b()
 c()
 Debug "done"  
     

Re: Gosub Return macros

Posted: Sun Jun 30, 2013 11:43 pm
by luis
I don't use gosub/return but this is chic :)

Thanks.

It's a shame the debugger skip the Gosub line and jump just before it, if only we had a Basic "NOP" to put inside the macro... uhmmmm.....

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 12:14 am
by idle
I don't use them either but they can be useful.

there are still some restrictions on use though, like if you use them from within a Select
you need to ensure that you return to that point or it'll fail

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 7:09 am
by idle
added GosubS() ReturnS() and GotoS() to be used from and to Select statements

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 12:39 pm
by yrreti
I haven't used them yet in PB, but they can be useful.
Thank you for sharing this and along with some nice code commenting.

yrreti

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 1:28 pm
by Kwai chang caine
Oooh !!! a GOSUB like FRED try to do and remove immediately after :shock:
Thanks a lot IDLE 8)

Now... if you can create a procedure into a procedure like in Algol, Pascal, Ada, Scheme, Common Lisp, Python, C (no standard), D et Perl like this :

Code: Select all

Structure result
  hWnd.i
  String.s
EndStructure

Procedure.s EnumereProcess()

  Procedure EnumWindowsProc(hWnd, *lParam.result)
   Protected Title.s{260}
   GetWindowText_(hWnd, @Title, 260)

   If FindString(Title, *lParam\String)
     *lParam\String = Title
     *lParam\hWnd = hWnd
     ProcedureReturn #False
   EndIf

   ProcedureReturn #True

  EndProcedure

  Define param.result 
  param\String = " 5.10 ("
  
  If Not EnumWindows_(@EnumWindowsProc(), @param)
    ProcedureReturn "Found: " + param\String + " with hWnd: " + Str(param\hWnd)
  EndIf

EndProcedure
I marry you this weekend :mrgreen:

Image

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 8:32 pm
by idle
It would be possible to do nested procedures with fasm macros
but it wouldn't be practicable due to the limitations of PB's macro processing.
So no marrying this weekend kcc! :lol:

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 9:06 pm
by LuCiFeR[SD]
good thing too, cause that would mean me and KCC would have to get divorced :)

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 9:17 pm
by idle
LuCiFeR[SD] wrote:good thing too, cause that would mean me and KCC would have to get divorced :)
:lol:

Re: Gosub Return macros

Posted: Mon Jul 01, 2013 10:05 pm
by idle
Updated the macros to handle nesting depth
so they take the form
Gosub(label,depth=0) ;depth is needed to jmp and return out and in of nested selects

Re: Gosub Return macros

Posted: Wed Jul 03, 2013 5:32 am
by Kwai chang caine
but it wouldn't be practicable due to the limitations of PB's macro processing.
It's a shame :(
So no marrying this weekend kcc!
But i love you, when even :D
Thanks to share all your knowledge and have always original idea 8)

Re: Gosub Return macros

Posted: Tue Jul 23, 2013 10:13 pm
by idle
updated the macros and removed the need to specify a depth on Return

Re: Gosub Return macros

Posted: Wed Oct 24, 2018 10:18 am
by gurj
hope Gosub and Goto not use label, use address

Gosub ?label and Goto ?label
Gosub 199999 and Goto aaa.l

your to this:
Macro Gosub(address,depth=0)
Macro Return(address)
Macro Goto(address,depth=0)

see:
Chang 'Goto <label>' To 'Goto <?label>'
so will can use Variables for label
http://www.purebasic.fr/english/viewtop ... =3&t=68346

Re: Gosub Return macros

Posted: Wed Oct 24, 2018 9:18 pm
by idle
gurj wrote:hope Gosub and Goto not use label, use address

Gosub ?label and Goto ?label
Gosub 199999 and Goto aaa.l

your to this:
Macro Gosub(address,depth=0)
Macro Return(address)
Macro Goto(address,depth=0)

see:
Chang 'Goto <label>' To 'Goto <?label>'
so will can use Variables for label
http://www.purebasic.fr/english/viewtop ... =3&t=68346
I don't think that will be possible as the labels address isn't fixed until the file is assembled.

Re: Gosub Return macros

Posted: Thu Oct 25, 2018 2:26 am
by gurj
in pb's code, ?label mean get address
but regret , pb not use :
Gosub ?label and Goto ?label
Gosub 199999 and Goto aaa.l