📄 cmacros.new
字号:
;; regptr n,s,o
;; where:
;; n is the name the argument will be known as
;; s is the register containing the segment portion
;; of the pointer
;; o is the register containing the offset portion
;; of the pointer
;;
;; 2/14/85 - made obsolete with farptr
regPtr macro n,s,o
farPtr n,s,o
endm
;; farPtr generates information allowing a 32-bit pointer to be
;; pushed as a parameter to a subroutine using the cCall macro.
;;
;; usage:
;; farptr n,s,o
;; where:
;; n is the name the argument will be known as
;; s is the segment portion of the pointer
;; o is the offset portion of the pointer
;;
;; Note that any cast must have been made in the argument itself
;; (i.e. regptr ptr1,ds,<word ptr 3[si]>)
farPtr macro n,s,o
n macro
push s
push o
endm
endm
endif ; ?NOPTR
;; arg - declare arguements
;;
;; The given arguments(s) is added to the argument list structure
;;
;; format:
;; arg a
;;
;; where:
;; a is any valid arugment(s) to push
;;
;; If any element in arglist has not been defined or isn't 16-bit
;; register, then a compilete specification must have been given in
;; a text equate and a defx also given (if not, you'll pay the penalty!)
;;
arg macro args
ifnb <args>
ifnb ??CM_ArgList
??CM_ArgList textequ ??CM_ArgList, <,>, <args>
else
??CM_ArgList textequ <args>
endif
endif
endm
;; ?CM_IsIdent - is the arguement a legal identifier?
;;
;;
;; Need to enforce the following additional rules:
;; Digit may not be first character
;; Assorted other characters may be used
;; Dot may be the first character
?CM_IsIdent macro name:REQ
LOCAL result
result = 1
forc char,<name>
if ('A' LE '&char') AND ('&char' LE 'Z')
goto next
endif
if ('a' LE '&char') AND ('&char' LE 'z')
goto next
endif
if ('0' LE '&char') AND ('&char' LE '9')
goto next
endif
result = 0
exitm
:next
endm
exitm %result
endm
;; @reverse
;;
@reverse macro list
LOCAL newlist
newlist textequ <>
for x,<list>
newlist catstr <x>, <,>, newlist
endm
ifnb newlist
newlist substr newlist, 1, @sizestr(%newlist)-1
endif
exitm newlist
endm
;; ?ap - process arguments and place onto stack
;;
;; The given argument is processed (type checking) and placed
;; on the stack for a pending call. There must be a type
;; definition for all arguments (except words). This can be
;; done using text equates and the defx macro.
;;
?ap macro n
?argl=?argl+2 ;; assume one word is pushed
if 0 EQ (OPATTR n)
if ?CM_IsIdent(n)
ifdef n
n
exitm
endif
endif
% .err <'&n' is not valid to push>
exitm
else
i = (TYPE n)
if i EQ 1 ;; byte type
push word ptr(n)
exitm
endif
if i EQ 2 ;; word type
push n
exitm
endif
if i EQ 4 ;; dword type
push word ptr (n)[2]
push word ptr (n)
?argl=?argl+2
exitm
endif
if i EQ 8 ;; qword type
push word ptr (n)[6]
push word ptr (n)[4]
push word ptr (n)[2]
push word ptr (n)
?argl=?argl+6
exitm
endif
push word ptr (n) ;; variable storage
exitm
endif
endm
;; cCall - call a 'c' language procedure
;;
;; The given procedure is called with the given parameters. If the
;; calling convention is C, the arguments are pushed in reverse order,
;; and removed after the called procedure returns. If the calling
;; convention is PL/M, the arguments are pushed as they were encountered,
;; and the called procedure is assumed to have removed them
;; from the stack.
;;
;; The calling convention priority will be:
;; 1) that specified on the cCall if present,
;; 2) that defined by the target,
;; 3) the default (?PLM flag).
;;
;; format:
;; cCall n,<a>,c
;;
;; where:
;; n is the name of the procedure to call
;; a are the arguments to be pushed (optional, may be specified
;; with the "arg" macro.
;; c is the calling convention, C for C, PLM or PASCAL for
;; PL/M. The default (?PLM flag) will be used if
;; not specified).
;;
cCall macro name:req,args,langType
ifnb <args> ;; add any passed in arguments
arg <args> ;; to the list of arguments
endif ;; for this procedure
ifnb ??CM_RegSaveList ;; If there are any resgisters
% for reg,<??CM_RegSaveList> ;; to be saved across the call
push reg ;; save then on the stack
endm ;;
endif ;;
ifnb <langType> ;; If a lang type was specified then
setDefLangType langType ;; it overrides all common sense
else
i = ((OPATTR name) SHR 8) AND 7 ;; Get the lang type from the symbol
if i EQ 0 ;; No lang type ---
setDefLangType ;; Use the default lang type
elseif i EQ 1 ;; C lang type
defLangType textequ <C> ;;
elseif i EQ 4 ;; Pascal Lang Type
defLangType textequ <PASCAL> ;;
else ;; Unknown lang type
.err <Unknown lang type specfied for '&name'> ;;
endif
endif
ifidn defLangType,<C> ;; If using C calling convention
??CM_ArgList textequ @reverse(%??CM_ArgList) ;; then reverse the arguements
endif ;;
?argl=0 ;; Clear arguement byte count
% for arg,<??CM_ArgList> ;; Push the procedures arguements
?ap <arg> ;; onto the stack. ?ap takes
endm ;; care of sizing arguements
call name ;; Do the actual call
ifidn defLangType,<C> ;; If this is a C proc and there
if ?argl NE 0 ;;
add sp,?argl ;; are parameters then pop them
endif ;; off the stack
endif ;;
ifnb ??CM_RegSaveList ;; If there were any saved registers
??CM_RegSaveList textequ @reverse(%??CM_RegSaveList) ;; then pop them off the stack
% for reg,<??CM_RegSaveList> ;; at this point.
pop reg ;;
endm ;;
endif ;;
??CM_RegSaveList textequ <> ;; Clear out the global state
??CM_ArgList textequ <> ;; variable used by the cCall macro
endm
;; save - flag that the indicated registers are to be saved/restored
;; on the next cCall invocation
;;
;; usage:
;; save <r>
;;
;; where:
;; r is the list of registers to be saved.
;;
;; the macro generates a value for the variable ??CM_RegSaveList
;;
save macro r
??CM_RegSaveList textequ <r>
endm
;; parmX - generate reference to parameter(s) on the stack
;;
;; usage:
;; parmX n
;; where:
;; x is the type of the argument(s) b=byte, w=word, d=dword
;; n is the name(s) to be given the parmeter(s).
;;
;; Byte are considered to be two bytes long for alignment.
;;
;; The parmd form of the macro generates two equates:
;;
;; off_name - for accessing the offset (lsw) of the parameter
;; seg_name - for accessing the segment (msw) of the parameter
;;
parmB macro names:req
for name,<names>
??CM_addParm <&name:BYTE>
endm
endm
parmW macro names:req
for name,<names>
??CM_addParm <&name:WORD>
endm
endm
parmD macro names:req
for name,<names>
??CM_addParm <&name:DWORD>
??CM_Paste(off_, name) textequ <word ptr name[0]>
??CM_Paste(seg_, name) textequ <word ptr name[2]>
endm
endm
parmQ macro names:req
for name,<names>
??CM_addParm <&name:QWORD>
endm
endm
parmT macro names:req
for name,<names>
??CM_addParm <&name:TBYTE>
endm
endm
if sizec
parmCP macro n
parmD <n>
endm
else
parmCP macro n
parmW <n>
endm
endif
if sized
parmDP macro n
parmD <n>
endm
else
parmDP macro n
parmW <n>
endm
endif
if 0
;; parmR - register parameter
;;
;; parmR is the macro used for generating register parameters.
;; The space allocated for the register parameters will be
;; the ?ia (interface adjust) area which is between the old
;; BP and the first parameter. Normally this is empty (?ia=0),
;; or has the saved ds for a windows far procedure.
;;
;; Byte and dword register parameters will be allowed.
;;
;; usage:
;; parmR n,r,r2
;; where:
;; n is the name of the parameter
;; r is the register it is in
;; r2 is the offset register if a dword
ifndef ?NOPARMR
.xcref
.xcref ?pr,parmR
.cref
parmR macro n,r,r2
?pr n,r,r2,%?rp,%(?ia+2)
endm
;; ?pr - register parameter
;;
;; ?pr is the actual macro for generating the equates for
;; register parameters.
;;
;; usage:
;; parmR n,r,r2,i,o
;; where:
;; n is the name of the parameter
;; r is the register it is in
;; r2 is the offset register if a dword
;; i is the index of the ?rp to generate
;; o is the offset from bp where the parm will be
?pr macro n,r,r2,i,o
.xcref
ifnb <r2> ;;if a dword parameter
parmR seg_&n,r ;;define segment equate
parmR off_&n,r2 ;;define offset equate
n equ (dword ptr [bp-o-2]) ;;define dword equate
.xcref ?t&n
?t&n=4 ;;show a dword to cmacros
else
.xcref ?rp&i
?rp&i=0 ;;show no register(s)
ifdef ?&r ;;define register if valid
?rp&i=?&r
endif
if ??? or (?cpd eq 0) or (?rp&i eq 0)
??error <invalid parmR encountered: &n,&r>
exitm
endif
n equ (word ptr [bp-o]) ;;assume a word register
?t&n=2 ;;show a word to cmacros
irp x,<bh,ch,dh,bl,cl,dl,ah,al>
if ?&&x eq ?&r ;;if really a byte register
n equ (byte ptr [bp-o]) ;; then make it a byte
?t&n=1 ;;show a byte to cmacros
exitm
endif
endm
?ia=?ia+2 ;;show this guy is out there
?rp=?rp+1 ;;show one more register parameter
endif
.cref
endm
endif
endif
localB macro name
??CM_addLocal ??CM_Paste(name, <:BYTE>)
endm
localW macro name
??CM_addLocal ??CM_Paste(name, <:WORD>)
endm
localD macro name
??CM_addLocal ??CM_Paste(name, <:DWORD>)
off_&name textequ <word ptr name[0]>
seg_&name textequ <word ptr name[2]>
endm
localQ macro name
??CM_addLocal ??CM_Paste(name, <:QWORD>)
endm
localT macro name
??CM_addLocal ??CM_Paste(name, <:TBYTE>)
endm
if sizec
localCP macro n
localD <n>
endm
else
localCP macro n
localW <n>
endm
endif
if sized
localDP macro n
localD <n>
endm
else
localDP macro n
localW <n>
endm
endif
localV macro name,a
local t1
t1 catstr <name>, < [>, %a, <]:BYTE>
% ??CM_addLocal <t1>
endm
ife ?DF
;;
;; Define all segments that will be used. This will allow the
;; assume and groups to be set up at one given place, and also
;; allow quick changes to be made
;;
createSeg _TEXT,Code,word,public,CODE
ife ?NODATA
createSeg _DATA,Data,word,public,DATA,DGROUP
endif
endif
; errnz exp - generate error message if expression isn't zero
;
; The errnz will generate an error message if the expression "exp"
; does not evaluate to zero. This macro is very useful for testing
; relationships between items, labels, and data that was coded into
; an application.
;
; errnz <offset $ - offset label> ;error if not at "label"
; errnz <eofflag and 00000001b> ;eofflag must be bit 0
;
; For expressions involving more than one token, the angle brackets
; must be used.
;
; The macro is only evaluated on pass 2, so forward references may be
; used in the expression.
errnz macro x ;;display error if expression is <>0
.errnz x
endm
; errn$ label,exp - generate error message if label (exp) <> $
;
; The errnz will generate an error message if the label and "exp"
; does not evaluate to the current value of the location counter.
; This macro is very useful for testing relationships between
; labels and the location counter that was coded into an application.
;
; examples: errn$ label ;error if not at "label"
; errn$ label,+3 ;error if not three bytes from "label"
; errn$ label,-3 ;error if not three bytes past "label"
;
; If no "exp" is given, it is the same as specifying 0
;
; The macro is only evaluated on pass 2, so forward references may be
; used in the expression.
errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
errnz <offset $ - offset l x>
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Extra macros for the c-runtime package
;
; Macro for calling another run-time-library function.
; Does a PUSH CS/CALL NEAR in compact/large models, except
; for QuickC. --PHG, 5-24-89
callcrt MACRO funcname
ifdef _QC2
call funcname
else
if sizeC
push cs
call near ptr (funcname)
else
call funcname
endif
endif
ENDM
.cref ; Permit symbols to be listed again
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -