Announcement

Collapse
No announcement yet.

Gosub dword

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Gosub dword

    Could someone show me an example of GOSUB DWORD....

    When would us use such a thing??

  • #2
    It can be used to pre-calculate jump targets to allow subsequent faster calling of code.
    For example, if you had a complex function based on some variables that had a number of discrete outcomes then you could do the complex calculations once and store the outcomes in a jump table.
    Then, when you need to do a million calculations based on those variables you can quickly look up the precalculated address to jump to rather than recalculating it every time or using IF-THEN structures.

    Code:
    FUNCTION PBMAIN () AS LONG
    
    LOCAL JumpTable() AS LONG
    
    DIM jumpTable(5)
    
    JumpTable(1) = CODEPTR(Code1)
    JumpTable(2) = CODEPTR(Code2)
    JumpTable(3) = CODEPTR(Code3)
    JumpTable(4) = CODEPTR(Code4)
    JumpTable(5) = CODEPTR(Code5)
    
    
    
    INPUT "Where to (1-5)",x&
    
    GOSUB DWORD JumpTable(x&)   'no need to calculate where to go, just look it up directly instead.
    
    
    WAITKEY$
    EXIT FUNCTION
    
    Code1:
    PRINT "1"
    
    Code2:
    PRINT "2"
    
    code3:
    
    PRINT "3"
    
    Code4:
    PRINT "4"
    
    Code5:
    PRINT "5"
    RETURN
    
    END FUNCTION

    Comment


    • #3
      Its just 'GOSUB DWORD addr'

      where addr = CODEPTR(label)

      I don't know why you'd use it instead of simply GOSUB label except maybe if the label is long and you do a lot of them and it becomes easier to type "DWORD addr" than it is to type 'label'

      It would also allow you to use a subroutine located in another module..

      Code:
      #COMPILE DLL  "foo.dll"
      
      FUNCTION GetSubroutineAddress () EXPORT AS DWORD
      
         FUNCTION =  CODEPTR (SubrStartsHere)
         EXIT FUNCTION
      
      SubrStartsHere:
          MSGBOX "we're here"
          RETURN   ' required
      
      END FUNCTION
      Code:
      #COMPILE EXE
      
      DECLARE FUNCTION GetSubrotineAddress ALIAS "GETSUBROUTINEADDRESS" LIB "FOO.DLL" () AS DWORD
      
         addr =  GetSubroutineAddress()
      
      ...
      
         GOSUB DWORD Addr
      
      .....
      Either, if you ask me, is a totally silly way to perform the same set of instructions. (Although you COULD use GLOBAL or STATIC variables in the function in the DLL which you have set some other way which "might" offer you something)

      Maybe it's just a marketing thing.. you know, "hey, you can even do THIS, ain't that wonderful?"

      I only use subroutines when I have one or two variables which change AND I need to current values of other variables which are being modified in the current procedure... which is not very often. The one place I can remember doing this was in a print routine I wrote in which I had labels like

      PrintPageOneHEader:

      PrintPageTwoHeader:

      AddLogo:

      .. all of which needed a document handle ("file number) and used (I-O) other variables in the routine (eg current page number, current location on current page)
      AND
      I found it easiest to use the subroutine format to separate out the individual routines rather than pass ten or twelve variables to a procedure.

      I'm going back to the "because we can/marketing reasons" explanation as the reason for this feauture's inclusiion in the compilers unless I, too, see a real good example of why this feature is useful.

      I think I saw some code here once which used it something like..

      Code:
         SELECT CASE FOO
           CASE 1
             addr =  CODEPTR (valueone)
           CASE 2
              addr = CODEPTR (valuetwo)
           CASE 3
              addr =  CODEPTR (valuethree)
           [more cases ]
          END SELECT
         GOSUB DWORD addr
      ...which could be a lot "cleaner" (easier to maintain?) at the source code level if there are a lot of CASEs.

      MCM
      Michael Mattias
      Tal Systems Inc.
      Racine WI USA
      mmattias@talsystems.com
      http://www.talsystems.com

      Comment


      • #4
        Um, Paul, your subroutines need RETURN statements!

        Well, unless you really meant that code to execute ALL the routines from "CodeN" to "Code5" ....

        Michael Mattias
        Tal Systems Inc.
        Racine WI USA
        mmattias@talsystems.com
        http://www.talsystems.com

        Comment


        • #5
          GOSUB label and GOTO label only work within a procedure (function or sub). To access code in other procedures use GOSUB DWORD or GOTO DWORD.

          CALL DWORD is similar, but is used when LOADLIBRARY() method is used to load DLL.
          Dale

          Comment


          • #6
            I would suggest that Paul's code would be faster as its a one pass, get all of the addresses which you do at startup then directly call each item without running through a sequence of comparisons. It would not matter with a few options but imagine hundreds to thousands of options and you will see why Paul's code would be faster.
            hutch at movsd dot com
            The MASM Forum

            www.masm32.com

            Comment


            • #7
              > Maybe it's just a marketing thing

              Nope. GOSUB address goes all the way back to interpreted BASIC. Extremely fast compared to calculating the CODEPTRs over and over.

              It's a legacy command, not something fluffy added by Bob. He always tried to maintain backward compatibility.



              "Not my circus, not my monkeys."

              Comment


              • #8
                ..

                Last edited by Simon Whittam; 12 Jan 2017, 03:19 AM.

                Comment


                • #9
                  Another use of GOSUB DWORD might be in writing a Finite State Machine.

                  Code:
                  FUNCTION PBMAIN
                  
                     DIM dwStatePointer AS GLOBAL DWORD
                     DIM liEvent        AS GLOBAL LONG
                     DIM liMyCount      AS GLOBAL LONG
                  
                     liEvent   = 1
                     liMyCount = 1
                  
                     dwStatePointer = CODEPTR(State1)
                  
                     WHILE (-1)
                        'Would normally fetch liEvent here from a circular queue/buffer
                        GOSUB DWORD dwStatePointer
                     WEND
                  
                  
                     PBMAIN = 0
                  
                  END FUNCTION  'PBMAIN
                  
                  '=============================================================================
                  
                  SUB State1
                     SELECT CASE liEvent
                        CASE 1
                           liEvent   = 2
                           liMyCount = liMyCount + 1
                        CASE 2
                           liEvent        = 3
                           liMyCount      = liMyCount + 2
                           dwStatePointer = CODEPTR(State2)
                     END SELECT
                  END SUB
                  
                  '=============================================================================
                  
                  SUB State2
                     SELECT CASE liEvent
                        CASE 3
                           liEvent   = 4
                           liMyCount = liMyCount + 4
                        CASE 4
                           liEvent        = 4
                           liMyCount      = liMyCount + 8
                           IF liMyCount > 32  THEN
                              liEvent        = 1
                              dwStatePointer = CODEPTR(State1)
                           END IF
                     END SELECT
                  END SUB
                  
                   '=============================================================================

                  Comment


                  • #10
                    Nope. GOSUB address goes all the way back to interpreted BASIC. Extremely fast compared to calculating the CODEPTRs over and over.
                    Interpreted BASIC did not have CODEPTRs. It had line numbers, and since the program was interpreted - converted source to machine instructions - line-by-line 'as encountered' the machine instructions had not been generated yet so there would have been no way to predict a "label or procedure address."

                    You may be thinking of CALL ABSOLUTE, although that would be more akin to CALL DWORD.
                    .
                    Michael Mattias
                    Tal Systems Inc.
                    Racine WI USA
                    mmattias@talsystems.com
                    http://www.talsystems.com

                    Comment


                    • #11
                      > Interpreted BASIC did not have CODEPTRs.

                      I meant compared to calculating the equivalent of CODEPTRs (determining the runtime address of a label) over and over, but you're right, I looked at the old GW-BASIC docs and my memory is faulty. I'd have sworn that's where I used it, early-on; maybe it was Apple Basic. Oh well.
                      "Not my circus, not my monkeys."

                      Comment


                      • #12
                        I meant compared to calculating the equivalent of CODEPTRs (determining the runtime address of a label) over and over,
                        Except, a runtime address of a label or procedure in a compiled program - a PB CODEPTR - could be calculated at COMPILE time (it's just an offset from the code start) meaning there should be no runtime cost at all. I do not know if PB actually implements CODEPTR() this way, but "in theory" it certainly is possible.

                        Just think, Eric: not many members here ever actually used an Interpreted BASIC development tool and all this talk is just so much gobbledy-gook. (or more likely they just call it "old fart talk").

                        MCM
                        Michael Mattias
                        Tal Systems Inc.
                        Racine WI USA
                        mmattias@talsystems.com
                        http://www.talsystems.com

                        Comment


                        • #13
                          > I do not know if PB actually implements CODEPTR() this way, but "in theory" it certainly is possible.

                          This is in fact the only way you can do it in a compiled binary, an OFFSET from the start address of the binary to an instruction location. My only great lament with the current versions of PB was that I could not talk Bob into retaining the capacity to have global scope labels as they work exactly the same way. You can actually fudge your way around it but it does not look much like basic.

                          TRUE CONFESSIONS : Long ago there was a lady who used to do some typing for me and she had an original IBM twin floppy PC and I remember having to get hold of the ROM BASIC data to write some simple software for her so I guess I have made it into the "old fart" big time.
                          hutch at movsd dot com
                          The MASM Forum

                          www.masm32.com

                          Comment


                          • #14
                            GOSUB DWORD and GOTO DWORD seem to be PowerBASIC re-implementations of what is known in the world of GNU C Extensions as "computed gotos". These are primarily used to pre-generate efficient lookup tables (LUTs) to replace conditional branching in shorter switch and if clauses that the compiler tends to generate at the machine code level. (longer switches and if/else ifs are usually converted to respective LUTs by the optimizing GCC compiler automatically)

                            If you are familiar with the basics of C programming and/or are interested in practical virtual machine implementations, perhaps you might find the following article interesting, at least for starters. It depicts one use case of computed gotos along with some benchmark data and the resultant AT&T assembly listings. Historically, a few interpretative BASIC dialects did support computed numeric label (in fact, line number) arithmetics since the times of ZX Spectrum but I think analogy with such BASICs would be purely coincidental here. In fact substantially faster performance is what the method is all about.

                            Comment


                            • #15
                              Originally posted by Michael Mattias View Post

                              not many members here ever actually used an Interpreted BASIC development tool and all this talk is just so much gobbledy-gook. (or more likely they just call it "old fart talk").

                              MCM
                              PetBASIC was the ultimate BASIC and nothing will ever be as good.
                              And it did have a GO xxxx command, where xxxx was a specific memory location for a machine code segment!
                              The world is strange and wonderful.*
                              I reserve the right to be horrifically wrong.
                              Please maintain a safe following distance.
                              *wonderful sold separately.

                              Comment


                              • #16
                                So basically an inline 8-bit assembly instruction?
                                "Not my circus, not my monkeys."

                                Comment


                                • #17
                                  Yes, it boils down respectively to a CALL or unconditional JMP instruction plus an 8-, 16-, 32-, or 64-bit code pointer.

                                  Comment


                                  • #18
                                    Ancient Fortran 77 had assigned goto thus:

                                    GOTO variable

                                    which “Transfers execution to the statement label assigned to variable”. It also had a computed goto thus,

                                    GOTO (label1, label2,…), n

                                    which “Transfers control to the statement at the nth label in the list.

                                    Comment


                                    • #19
                                      > Ancient Fortran 77 had assigned goto thus:

                                      So did COBOL, the 'ALTER' statement Although it actually took TWO statements to pull this off, ALTER plus GO [TO].

                                      ALTER was removed from the ANSI COBOL standard in I think 2002. It was considered antiquated and dangerous. GO [TO] remains part of the standard.

                                      BTW..
                                      >GOTO (label1, label2,…), n

                                      The BASIC...
                                      Code:
                                         ON X GOTO (a, b, c)
                                      .. is functionally equivalent. (does PB/WIN have that? let me look.. how about that, it has both ON X GOTO and ON X GOSUB!)

                                      MCM
                                      Michael Mattias
                                      Tal Systems Inc.
                                      Racine WI USA
                                      mmattias@talsystems.com
                                      http://www.talsystems.com

                                      Comment

                                      Working...
                                      X