_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 , ;If object is Self mov si,Wptr[Self] ;Get object ptr from it ELSE IFDIF , ;If object ptr not in SI lea si,Obj ;Load SI with ptr to object ENDIF ENDIF IFDIF , ;If msg number not in DX mov dx,Msg ;Put it in DX ENDIF call sendMsg ;Send message IFNB ;If arguments X = 0 ;Init stack depth counter IRP Arg, ;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 ;If no more arguments EXITM ;Exit macro ENDIF IFIDN , ;If arg in AX push ax ;Push AX ELSE IFIDN , ;If arg in BX push bx ;Push BX ELSE IFIDN , ;If arg in CX push cx ;Push CX ELSE IFIDN , ;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 , ;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 ;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 ;Save loop cnt, addr ptr call Wptr[si] ;Execute method popData ;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, MsgTbl LABEL WORD msgsDef Obj, InstTbl LABEL WORD instDef ALIGN 2 PUBLIC Obj Obj _Object ENDM COMMENT % =================================================================== Defines objects. Passed: Obj - Object name; Objs - Ancestor list =============================================================================% objsDef MACRO Obj,Objs DW Obj IRP Obj, DW Obj ENDM ENDM COMMENT % ==================================================================== Defines messages. Passed: Obj - Object name; Messages - Message list =============================================================================% msgsDef MACRO Obj,Messages IRP Msg, 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, 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 ,<0> X = X+1 ELSE IFIDN ,<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 ,<1> DB Value ELSE IFIDN ,<2> DW Value ELSE IFIDN ,<4> DD Value ELSE IFIDN ,<8> DQ Value ELSE IFIDN ,<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 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 ;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 ;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 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 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 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 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 IFIDN , mov si,WORD PTR[Self] mov si,WORD PTR[si].Instances ELSE IFIDN , 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 IFIDN , 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 , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN ,
mov BYTE PTR[si+Var],Source ELSE IFIDN , mov BYTE PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN , mov WORD PTR[si+Var],Source ELSE IFIDN ,<1> mov BYTE PTR[si+Var],Source ELSE IFIDN ,<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, ;Send Self msg pointed to by ; BX register [Example 2] defObj Window,\ ;Define Window object <>,\ ;As a base object <>,\ ;With no inst vars ;Responds to Refresh msg defObj Border,\ ;Define Border object <>,\ ;As a base object <>,\ ;With no inst vars ;Responds to Refresh msg defObj Screen,\ ;Define Screen object ,\ ;As a derived object ,\ ;Responds to Refresh msg [Example 3] defMsg Window,\ ;Define for Window object Refresh,\ ;The Refresh msg ;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 ;Responds to Refresh msg defMsg Screen,\ ;Define for Screen object Refresh,\ ;The Refresh msg <,drawBackDrop,> ;To draw back drop defObj Screen,\ ;Define Screen object ,\ ;As a derived object ,\ ;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