Metropoli BBS
VIEWER: oopasm.asc MODE: TEXT (ASCII)
_AN OBJECT-ORIENTED ASSEMBLY LANGUAGE MACRO LIBRARY_
by Donald J. McSwain


[LISTING ONE]

Macro File: objects.mac

COMMENT % ===============================================================
Sets up stack, SI with object pointer, DX with message number, and calls
sendMsg procedure.
Passed: Obj - Name of receiving object; Msg - Message number
=========================================================================%
send    MACRO       Obj,Msg,ArgList
        pushArgs    ArgList             ;Push arguments onto stack
        IFIDN       <Obj>,<Self>        ;If object is Self
        mov         si,Wptr[Self]       ;Get object ptr from it
        ELSE
        IFDIF       <Obj>,<si>          ;If object ptr not in SI
        lea         si,Obj              ;Load SI with ptr to object
        ENDIF
        ENDIF

        IFDIF       <Msg>,<dx>          ;If msg number not in DX
        mov         dx,Msg              ;Put it in DX
        ENDIF

        call        sendMsg             ;Send message
        IFNB        <ArgList>           ;If arguments
        X       =   0                   ;Init stack depth counter
        IRP         Arg,<ArgList>       ;For every arg on stack
        X       =   X+2                 ;Increment depth counter
        ENDM
        add         sp,X                ;Reset stack pointer
        ENDIF
        ENDM

COMMENT % ===============================================================
Pushes up to ten arguments onto the stack.
=========================================================================%
pushArgs    MACRO      A0,A1,A2,A3,A4,A5,A6,A7,A8,A9
    IFB                <A0>                     ;If no more arguments
    EXITM                                       ;Exit macro
    ENDIF

    IFIDN              <A0>,<ax>                ;If arg in AX
    push               ax                       ;Push AX
    ELSE
    IFIDN              <A0>,<bx>                ;If arg in BX
    push               bx                       ;Push BX
    ELSE
    IFIDN              <A0>,<cx>                ;If arg in CX
    push               cx                       ;Push CX
    ELSE
    IFIDN              <A0>,<dx>                ;If arg in DX
    push               dx                       ;Push DX
    ELSE
    mov                bx,A0                    ;Else move into BX
    push               bx                       ;Push BX
    ENDIF
    ENDIF
    ENDIF
    ENDIF
    pushArgs           A1,A2,A3,A4,A5,A6,A7,A8,A9
    ENDM

COMMENT %  =============================================================
Finds the specified message for specified object.
Passed: Msg - Message number; Obj - Addr ptr to object structure
Passes: si - Pointer to combined method pointer
=========================================================================%
findMsg MACRO   Obj,Msg,Lbl
        LOCAL   fdmg1,fdmg2
        IFDIF       <Obj>,<si>      ;If object ptr is not in SI
        mov         si,Obj          ;Put it there
        ENDIF
        mov         di,Wptr[si].Instances   
                                    ;Addr of msg tbl end
        mov         si,Wptr[si].Messages
                                    ;Addr of msg tbl beginning 
fdmg1: lodsb                        ;Fetch msg number
       eq           al,Msg,fdmg2    ;Exit if message is found
       add          si,2            ;Else point to next message
       cmp          si,di           ;More messages?
       jb           fdmg1           ;If so continue search

       IFNB         <Lbl>           ;If label provided
       jmp          Lbl             ;Jump to it upon failure
       ENDIF
fdmg2:
       ENDM

Source File: objects.asm
    PUBLIC  sendMsg
COMMENT % ===================================================================
Sends the specified object the given message. This causes the execution of 
the combined message for the object.
Passed: dx - Message number; si - Combined method ptr
=============================================================================%
sendMsg PROC    NEAR
        findMsg          si,dl,smg2      ;Search for message
        mov              si,Wptr[si]     ;Get method addr
        mov              cx,Wptr[si]     ;Get method count
smg1:   add              si,2            ;Point to method
        pushData         <cx,si>         ;Save loop cnt, addr ptr
        call             Wptr[si]        ;Execute method
        popData          <si,cx>         ;Restore addr ptr, loop cnt
        loop             smg1            ;Loop
smg2:   ret
sendMsg ENDP


[LISTING TWO]


Include File: objects.inc

COMMENT % ==================================================================
Data structure used to hold pointers to an object's ancestors, messages, and
instance variables.
===========================================================================%
_Object STRUC
    Objects     DW  Nil
    Messages    DW  Nil
    Instances   DW  Nil
_Object ENDS

Macro File: objects.mac

COMMENT % ===================================================================
Defines an object.
Passed: Obj - Object name; Objs - Ancestor list; Instances - Instance 
variable list; Messages - Message list
=============================================================================%
defObj  MACRO   Obj,Objs,Instances,Messages
        LOCAL   ObjTbl,MsgTbl,InstTbl

        ObjTbl      LABEL   WORD
        objsDef     Obj,<Objs>

        MsgTbl      LABEL   WORD
        msgsDef     Obj,<Messages>
        InstTbl     LABEL   WORD
        instDef     <Instances>
        ALIGN   2
        PUBLIC  Obj
        Obj _Object     <ObjTbl,MsgTbl,InstTbl>
        ENDM

COMMENT % ===================================================================
Defines objects.
Passed: Obj - Object name; Objs - Ancestor list
=============================================================================%
objsDef MACRO   Obj,Objs
        DW      Obj
        IRP     Obj,<Objs>
        DW      Obj
        ENDM
        ENDM

COMMENT % ====================================================================
Defines messages.
Passed: Obj - Object name; Messages - Message list
=============================================================================%
msgsDef MACRO   Obj,Messages
        IRP     Msg,<Messages>
        DB      Msg         ;Msg# identifies msg
        IFNDEF  Obj&&Msg
        DW      Nil         ;Obj has no local methods
        ELSE
        DW      Obj&&Msg        ;Obj has local methods
        ENDIF
        ENDM
        ENDM

COMMENT % =================================================================== 
Defines instances variables.
Passed: Instances - Instance variable list
=============================================================================%
instDef MACRO   Instances
        X       =      0
        Y       =      0
        IRP            Inst,<Instances>
        defInst        Inst,%X,%Y
        ENDM
        ENDM

COMMENT % ====================================================================
Defines an instance variable.
Passed: Inst - Instance variable name; Cnt - Instance variable field number;
Size - Size of instance variable
=============================================================================%
defInst MACRO   Inst,Cnt,Size
        IFIDN       <Cnt>,<0>
        X       =   X+1
        ELSE
        IFIDN       <Cnt>,<1>
        X       =   X+1
        Y       =   Inst
        ELSE
        X       =   0
        defVar      Size,Inst
        ENDIF
        ENDIF
        ENDM

COMMENT % ====================================================================
Defines a data item.
Passed: Size - Size of data in bytes; Value - Value of data item
=============================================================================%
defVar  MACRO   Size,Value
        IFIDN       <Size>,<1>
        DB          Value
        ELSE
        IFIDN       <Size>,<2>
        DW          Value
        ELSE
        IFIDN       <Size>,<4>
        DD          Value
        ELSE
        IFIDN       <Size>,<8>
        DQ          Value
        ELSE
        IFIDN       <Size>,<10>
        DT          Value
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDM




[LISTING THREE]

Include File: objects.inc

COMMENT % ==================================================================
Data structure used to hold pointers to a message's Before, Primary, and
After methods.
===========================================================================%
_Message    STRUC
    Before      DW  Nil
    Primary     DW  Nil
    After       DW  Nil
_Message    ENDS

Macro File: objects.mac

COMMENT % ====================================================================
Defines a message.
Passed: Obj - Object name; Msg - Message name; Methods - Method list 
=============================================================================%
defMsg  MACRO   Obj,Msg,Methods
        ALIGN   2
        Obj&Msg _Message    <Methods>
        ENDM    




[LISTING FOUR]

Macro File: objects.mac

COMMENT % ====================================================================
Sets us SI to point to object, and calls initObject procedure.
=============================================================================%
initObj     MACRO   Obj
        lea         si,Obj          ;Pass object ptr
        call        initObject      ;Find all ancestors
        ENDM

Source File: objects.asm

    PUBLIC  initObject
COMMENT % ====================================================================
Initializes an object by flattening its inheritance lattice to create 
combined methods for its messages.
Passed: si - Addr ptr to object structure
=============================================================================%
initObject  PROC    NEAR
          lea       di,Buffer           ;Get buffer addr
          call      findAncestors       ;Find/Save all ancestors
          call      evalMsgs            ;Evaluate messages
          ret
initObject  ENDP

COMMENT % ====================================================================
Finds all of an object's ancestors and saves them for use by the message 
evaluator.
Passed: bx - Addr ptr to message table (end of object table); di - Addr ptr 
to temporary object table; si - Addr ptr to object structure
=============================================================================%
findAncestors   PROC    NEAR
        pushData        <bx,si>                  ;Save obj ptr
        mov             bx,Wptr[si].Messages     ;Get addr ptr to msg tbl
        mov             si,Wptr[si].Objects      ;Get addr of object tbl
        movsw                                    ;Move obj ptr
fas1:   eq              bx,si,fas2               ;Exit if end of tbl
        push            si
        mov             si,Wptr[si]              ;Get next object
        call            findAncestors            ;Find others
        pop             si
        add             si,2
        jmp             fas1                     ;More in tbl - Loop
fas2:   mov             Wptr[di],Nil             ;Mark end of list
        popData         <si,bx>                  ;Restore obj ptr
        ret
findAncestors   ENDP

COMMENT % ====================================================================
Creates combined methods for all of an object's messages.
Passed: si - Addr ptr to object structure
=============================================================================%
evalMsgs    PROC        NEAR
        mov             bx,Wptr[si].Messages    ;Get addr of message tbl
        mov             cx,Wptr[si].Instances   ;Get addr of instance tbl
ems1:   mov             dl,Bptr[bx]             ;Get msg number
        xor             dh,dh
        call            combineMethods          ;Combine methods
        add             bx,3                    ;Point to next tbl entry
        neq             bx,cx,ems1              ;More in tbl? - loop
        ret
evalMsgs    ENDP

COMMENT % ==================================================================== 
Combines methods for all included objects.
Passed: dx - Message number; si - Addr ptr to object structure
=============================================================================%
combineMethods  PROC    NEAR
       push             bx
       mov              ?Compiled,Nil           ;Clear compiled flag
       mov              bx,Wptr[CompileStart]   ;Get start of combined mthd
       mov              Wptr[CompilePtr],bx ;Init location ptr
       mov              di,Nil                  ;Zero count word
       call             saveMethodAddr          ;Save value
       call             saveBefores             ;Save Before methods
       mov              bx,Primary              ;Select Primary method type
       lea              di,Buffer               ;Get addr of tmp object tbl
       mov              di,Wptr[di]             ;Get tbl entry
       call             saveMethod              ;Save method
       call             saveAfters              ;Save After methods
       null             ?Compiled,cms1          ;Nothing compiled? - Exit
       call             updatePtrs              ;Update message, location ptrs
cms1:  pop              bx
       ret
combineMethods  ENDP

COMMENT % ====================================================================
Updates the message and location pointers.
Passed: dx - Message number; si - Addr ptr to object structure
=============================================================================%
updatePtrs  PROC        NEAR
       push             si
       findMsg          si,dl                   ;Find message
       mov              di,Wptr[CompileStart]   ;Get ptr to combined method
       mov              Wptr[si],di             ;Change message ptr

       mov              bx,Wptr[CompilePtr]     ;Get current compile location
       mov              Wptr[CompileStart],bx   ;Reset start of combined mthd 
       pop              si
       ret
updatePtrs  ENDP

COMMENT % ====================================================================
Save the Before method type for the specified object.
Passed: dx - Message number
=============================================================================%
saveBefores PROC    NEAR
        push        si
        mov         bx,Before       ;Select Before method type
        lea         si,Buffer       ;Get addr of tmp object tbl
        mov         di,Wptr[si]     ;Get tbl entry
sbs1:   call        saveMethod      ;Save method
        add         si,2            ;Point to next tbl entry
        mov         di,Wptr[si]     ;Get next tbl entry
        identity    di,sbs1         ;More in table? - loop
        pop         si
        ret
saveBefores ENDP

COMMENT % ===================================================================
Save the After method type for the specified object.
Passed: dx - Message number
=============================================================================%
saveAfters  PROC    NEAR
        pushData    <cx,si>
        mov         bx,After        ;Select After method type
        lea         si,Buffer       ;Get addr of tmp object tbl
        mov         cx,si           ;Save addr of object tbl
sas1:   mov         ax,Wptr[si]     ;Get tbl entry
        null        ax,sas2         ;Null? - End of tbl, exit
        add         si,2            ;Point to next tbl entry
        jmp         sas1            ;Loop
sas2:   sub         si,2            ;Point to previous tbl entry
        mov         di,Wptr[si]     ;Get next tbl entry
        call        saveMethod      ;Save method
        neq         si,cx,sas2
        popData     <si,cx>
        ret
saveAfters  ENDP

COMMENT % ====================================================================
Save the specified method for specified object.
Passed: bx-Method type; di-Addr ptr to object structure; dx-Message number
=============================================================================%
saveMethod  PROC    NEAR
        pushData    <bx,di,si>
        findMsg     di,dl,svm3      ;Find message
        mov         di,Wptr[si]     ;Get method tbl addr ptr
        null        di,svm3         ;Exit if no local methods
        mov         di,Wptr[di+bx]  ;Get method addr ptr
        null        di,svm3         ;Exit if no message
        mov         bx,Wptr[CompileStart]   ;Get start of combined mthd
svm1:   eq          bx,Wptr[CompilePtr],svm2
        eq          di,Wptr[bx],svm3    ;Exit if duplicate method
        add         bx,2            ;Point to next addr
        jmp         svm1            ;Check next addr
svm2:   call        saveMethodAddr  ;Save method addr
svm3:   popData     <si,di,bx>
        ret
saveMethod  ENDP

COMMENT % ====================================================================
Save value at current compile location, and increments location pointer.
Passed: di - Value to store
=============================================================================%
saveMethodAddr  PROC    NEAR
    mov                 ?Compiled,1         ;Set compiled flag
    mov                 bx,Wptr[CompilePtr] ;Get ptr to combined mthd end
    mov                 Wptr[bx],di         ;Save value
    add                 bx,2                ;Point to next location
    mov                 Wptr[CompilePtr],bx ;Reset location ptr 
    mov                 bx,Wptr[CompileStart]   ;Get ptr mthd count
    mov                 di,Wptr[bx]         ;Get mthd count
    inc                 di                  ;Increments mthd count
    mov                 Wptr[bx],di         ;Save value
    ret
saveMethodAddr  ENDP



[LISTING FIVE]

Macro File: objects.mac

COMMENT % ====================================================================
Gets an object's instance variable.
Passed: Dest- Destination register; Var - Instance variable name; 
Obj - Source object 
=============================================================================%
getInst MACRO   Dest,Var,Obj
        IFNB            <Obj>
        IFIDN           <Obj>,<Self>
        mov             si,WORD PTR[Self]
        mov             si,WORD PTR[si].Instances
        ELSE
        IFIDN           <si>,<Obj>
        mov             si,WORD PTR[si].Instances
        ELSE
        mov             si,Obj&.Instances
        ENDIF
        ENDIF
        ENDIF
        mov             Dest,[si+Var]
        ENDM

COMMENT % ====================================================================
Sets an object's instance variable.
Passed: Var - Instance variable name; Source - Source register; Obj - Source 
object; Size - Size of data
=============================================================================%
setInst       MACRO       Var,Source,Obj,Size
              IFNB        <Obj>
              IFIDN       <Obj>,<Self>
              mov         si,WORD PTR[Self]
              mov         si,WORD PTR[si].Instances
              ELSE
              mov         si,Obj&.Instances
              ENDIF
              ENDIF
              setInst_     Var,Source,Size
              ENDM

COMMENT % ====================================================================
Assembles move instruction based on source register.
=============================================================================%
setInst_      MACRO        Var,Source,Size
        IFIDN              <Source>,<al>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<ah>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<bl>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<bh>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<cl>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<ch>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<dl>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<dh>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<ax>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<bx>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<cx>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<dx>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<di>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Source>,<si>
        mov                WORD PTR[si+Var],Source
        ELSE
        IFIDN              <Size>,<1>
        mov                BYTE PTR[si+Var],Source
        ELSE
        IFIDN              <Size>,<2>
        mov                WORD PTR[si+Var],Source
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDIF
        ENDM





[LISTING SIX]

Macro File: objects.mac

COMMENT % ====================================================================
Gets an object's instance variable, but object is pointed to by one of 
Self's instance variables.
Passed: Dest- Destination register; Var - Instance variable name; 
Obj - Source object instance variable
=============================================================================%
getInst$    MACRO   Dest,Var,Obj
    mov             si,WORD PTR[Self]         
    mov             si,WORD PTR[si].Instances 
    mov             si,[si+Obj]               
    mov             si,WORD PTR[si].Instances 
    mov             Dest,[si+Var]             
    ENDM

COMMENT % ====================================================================
Sets an object's instance variable, but object is pointed to by one of 
Self's instance variables.
Passed: Var - Instance variable name; Source - Source register; Obj - Source 
object instance variable; Size - Size of data
=============================================================================%
setInst$    MACRO   Var,Source,Obj,Size
    mov             si,WORD PTR[Self]          
    mov             si,WORD PTR[si].Instances  
    mov             si,[si+Obj]                
    mov             si,WORD PTR[si].Instances  
    setInst_        Var,Source,Size        
    ENDM




[Example 1]

send Screen,Refresh,DoubleBdr  ;Send Screen a Refresh msg
send Self,Read                 ;Send Self a Read msg
send Self,<WORD PTR[bx]>       ;Send Self msg pointed to by
                               ;  BX register


[Example 2]

defObj Window,\     ;Define Window object
       <>,\         ;As a base object
       <>,\         ;With no inst vars
       <Refresh>    ;Responds to Refresh msg

defObj Border,\     ;Define Border object
       <>,\         ;As a base object
       <>,\         ;With no inst vars
       <Refresh>    ;Responds to Refresh msg

defObj Screen,\     ;Define Screen object
       <Window,Border>,\  ;As a derived object
       <Row1,1,1,\  ;With these inst vars
       Col1,1,0,\
       Row2,1,23,\
       Col2,1,79,\
       Color,1,34h,\
       BdrColor,1,30h,\
       MemSeg,2,Nil>,\
       <Refresh>     ;Responds to Refresh msg



[Example 3]

defMsg Window,\     ;Define for Window object
       Refresh,\    ;The Refresh msg
       <clrWin,,>   ;To clear window 

defMsg Border,\     ;Define for Border object
       Refresh,\    ;The Refresh msg
       <,,drawBdr>  ;To draw border

defMsg Screen,\     ;Define for Screen object
       Refresh,\    ;The Refresh msg
       <,drawBackDrop,drawLabel>
                    ;To draw back drop and label


[Example 4]

defMsg Label,\        ;Define for Label object
       Refresh,\      ;The Refresh msg
       <,,drawLabel>  ;To draw label

defObj label,\        ;Define Label object
       <>,\           ;As a base object
       <>,\           ;With no inst vars
       <Refresh>      ;Responds to Refresh msg

defMsg Screen,\        ;Define for Screen object
       Refresh,\       ;The Refresh msg
       <,drawBackDrop,> ;To draw back drop 

defObj Screen,\        ;Define Screen object
       <Window,Border,Label>,\      
                       ;As a derived object
       <Row1,1,1,\     ;With these inst vars
       Col1,1,0,\
       Row2,1,23,\
       Col2,1,79,\
       Color,1,34h,\
       BdrColor,1,30h,\
       MemSeg,2,Nil>,\
       <Refresh>         ;Responds to Refresh msg




[Example 5]

initObj Screen   ;Combine methods for Screen


[Example 6]

getInst bl,Color,Screen  ;Fetch Screen color
setInst BdrColor,bl      ;Copy it to BdrColor
setInst Color,bl,Self    ;And Self's color



[Example 7]

getInst$ bl,Color,Master  ;Fetch color from object
                          ; pointed to by Master
setInst  Color,bl,Self    ;Copy it to Self's color


[ RETURN TO DIRECTORY ]