TIP: Click on subject to list as thread! ANSI
echo: power_bas
to: ALL
from: JAMSHID KHOSHRANGI
date: 1995-10-14 00:00:00
subject: Kludge #998

$IF 0
        ARRDESC.BAS                                 ARRDESC.BAS
                       Passing Arrays Using BDECL
                 Written by Jamshid "The Kludge" Khoshrangi
         NOTES:
        PowerBASIC version 3.2 introduces a new concept for BASIC
        programmers: code pointers.  Without laboring the point, imagine
        being able to call a SUB from a pointer, while still passing
        it parameters, as in:
            CALL DWORD ThePtr BDECL(Parm1, Parm2, ...)
        This works fine, until you decide that you wish to pass an
        array using the new BDECL format, as in:
            CALL DWORD ThePtr BDECL(Parm1, TheArray(), Parm3)
        Put simply, the version 3.2 compiler accepts the above
        statement, but when the code is run, the code pointed to
        by ThePtr is never called because the parameter list includes
        a reference to an array.  What to do?  Is there a kludge to
        work our way around this oversight of the overworked PB
        development team?
        Well, of course there's a kludge.  I live for a good kludge.
        Rather than passing the array itself using the BDECL format,
        we must pass the array descriptor by value.  Say what?  The
        array what?
        Each PowerBASIC array has a 64 byte descriptor that we don't
        need to worry about most of the time.  But, when we wish to
        call a code pointer that points to code that expects a given
        parameter to be an array -- well, what it actually expects is
        a 32 bit pointer to the array descriptor.  That's how
        PowerBASIC passes arrays to SUBs by reference in such a timely
        manner.
        And, simple as it all sounds ... it creates a problem.  Just
        how do we go about ascertaining the address of a given
        array's descriptor?  Well, 3.1 introduced us to the ANY
        parameter, and the rest is only logical.  We write a FUNCTION
        that simply passes back the Array Descriptor of the array
        it was passed.  Then, once we have that descriptor, we
        pass it by value on the BDECL stack.... and BAM!  It works.
        Let's call this magical widget ARRAYDESC32().
        The SUB that is then called by the CALL DWORD statement in
        all respects treats the array parameter as we would expect.
        I don't normally sit down and try to find the hidden
        oversights in a compiler.  Since the introduction of code
        pointers, well, I've been using them in lots of ways, so
        I needed this for my pattern matching language.  It took
        me about $500.00 of my time to figure out what needed to
        be done.  You're getting my sweat and blood for free.
        All this to say -- if you're ever in Vancouver, Canada,
        you owe me a rum and Coke.
        Jamshid
$ENDIF
DEFINT A-Z
CLS
'We'll need this array later
DIM OurArray(1:10) AS STRING
OurArray(1) = "Pussy cat, pussy cat, where have you been?"
'   First, we call up ARRAYDESC32() to get the pointer to the
'   descriptor....
DIM TheArrayPtr AS DWORD
TheArrayPtr = ARRAYDESC32(OurArray())
'The empty parens are needed      ^^
'   We then point our code ptr to the Test SUB
DIM TheCodePtr AS DWORD
TheCodePtr = CODEPTR32(Test)
CALL DWORD TheCodePtr BDECL(BYVAL TheArrayPtr)
'This BYVAL is *required*   ^^^^^
PRINT OurArray(1)
OurArray(1) = "Pussy cat, pussy cat, what did you do there?"
'   The following line, although we would expect such, will not
'   be called because of    VVVVVVVVVV <- this array reference
CALL DWORD TheCodePtr BDECL(OurArray())
'   But this one will...
CALL DWORD TheCodePtr BDECL(BYVAL TheArrayPtr)
PRINT OurArray(1)
END
'   This sub just prints the first element of the array it's passed
'   and then changes it to the cat's meow....
SUB Test (TheArray() AS STRING)
    PRINT TheArray(1)
    '   Let's change the value just to prove that the array was
    '   passed by reference and is therefore modifiable....
    SELECT CASE INSTR(TheArray(1), "been")
        CASE 0
            TheArray(1) = "I chased a mouse under a chair there...."
        CASE ELSE
            TheArray(1) = "I've been to London to visit the Queen...."
    END SELECT
END SUB
'   This is the crucial FUNCTION that you might want to clip out and
'   use for your own purposes....
FUNCTION ARRAYDESC32 (ANY) AS DWORD
    DIM Desc AS DWORD
    ! mov ax, [bp+6]
    ! mov bx, [bp+8]
    ! mov Desc[0], ax
    ! mov Desc[2], bx
    ! mov ax, Desc
    ! mov FUNCTION, ax
END FUNCTION
--- Maximus/2 2.01wb
---------------
* Origin: Sound Stage BBS - Live Via Satellite - (604)944-6476 (1:153/7070)

SOURCE: echomail via exec-pc

Email questions or comments to sysop@ipingthereforeiam.com
All parts of this website painstakingly hand-crafted in the U.S.A.!
IPTIA BBS/MUD/Terminal/Game Server List, © 2025 IPTIA Consulting™.