home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
d_b_a
/
86_11
/
seg()
< prev
Wrap
Text File
|
1986-10-06
|
10KB
|
516 lines
;----------------------------------
;
; EXTENDA.MAC
;
; by Ralph Davis
;
; Placed in the public domain.
;
; Assembly language macros for Clipper interface
;
;----------------------------------
; Declare all Clipper internal functions
EXTRN _PARINFO:FAR
EXTRN _PARC:FAR
EXTRN _PARNI:FAR
EXTRN _PARNL:FAR
EXTRN _PARND:FAR
EXTRN _PARDS:FAR
EXTRN _PARL:FAR
EXTRN _RETC:FAR
EXTRN _RETNI:FAR
EXTRN _RETNL:FAR
EXTRN _RETND:FAR
EXTRN _RETDS:FAR
EXTRN _RETL:FAR
; Equates from EXTEND.H
UNDEF EQU 0
CHARACTER EQU 1
NUMERIC EQU 2
LOGICAL EQU 4
DATE EQU 8
ALIAS EQU 16
TRUE EQU 1
FALSE EQU 0
;--------------------------------------
;
; _PAR functions
;
;-----------------
; get number of parms passed--returned in AX
GET_PCOUNT MACRO
XOR AX,AX
PUSH AX
CALL _PARINFO
ADD SP,2
ENDM
; get type of requested parm--returned in AX
GET_PTYPE MACRO N
MOV AX,N
PUSH AX
CALL _PARINFO
ADD SP,2
ENDM
; get requested parm as string--returns segment and offset in AX:BX
GET_CHAR MACRO N
MOV AX,N
PUSH AX
CALL _PARC
ADD SP,2
ENDM
; get requested parm as integer--returned in AX
GET_INT MACRO N
MOV AX,N
PUSH AX
CALL _PARNI
ADD SP,2
ENDM
; get requested parm as long integer--returned in AX:BX
GET_LONG MACRO N
MOV AX,N
PUSH AX
CALL _PARNL
ADD SP,2
ENDM
; get requested parm as double--returned in AX:BX:CX:DX
GET_DBL MACRO N
MOV AX,N
PUSH AX
CALL _PARND
ADD SP,2
ENDM
; get requested parm as date string
; returns segment and offset as AX:BX
GET_DATESTR MACRO N
MOV AX,N
PUSH AX
CALL _PARDS
ADD SP,2
ENDM
; get requested parm as logical true or false--returned in AX
GET_LOGICAL MACRO N
MOV AX,N
PUSH AX
CALL _PARL
ADD SP,2
ENDM
;--------------------------------------
;
; _RET functions
;
;---------------
; return char pointer in REG1:REG2
RET_CHAR MACRO REG1,REG2
IRP X,<REG1,REG2>
PUSH X
ENDM
CALL _RETC
ADD SP,4
ENDM
; return integer in REG1
RET_INT MACRO REG1
PUSH REG1
CALL _RETNI
ADD SP,2
ENDM
; return long integer in REG1:REG2
RET_LONG MACRO REG1,REG2
IRP X,<REG1,REG2>
PUSH X
ENDM
CALL _RETNL
ADD SP,4
ENDM
; return 8-byte floating-point number in REG1:REG2:REG3:REG4
RET_DBL MACRO REG1,REG2,REG3,REG4
IRP X,<REG1,REG2,REG3,REG4>
PUSH X
ENDM
CALL _RETND
ADD SP,8
ENDM
; return date string pointed to by REG1:REG2
RET_DATESTR MACRO REG1,REG2 ; return pointer to date string
; in REG1:REG2
IRP X,<REG1,REG2>
PUSH X
ENDM
CALL _RETDS
ADD SP,4
ENDM
; return logical true (1) or false (0) in REG1
RET_LOGICAL MACRO REG1 ; return 1 or 0 in REG1
PUSH REG1
CALL _RETL
ADD SP,2
ENDM
; EOF: EXTENDA.MAC
Notice that all the Clipper extend system functions must be
declared as FAR symbols in EXTRN statements. The assembler does
not care what kind of values the functions return; it only needs
to know that it will be generating FAR CALLs to reach them. The
EQUates come directly from the #define statements at the
beginning of EXTEND.H, and translate only the statements we will
need.
The first two macros, GET_PCOUNT and GET_PTYPE, use
_parinfo(). As I mentioned earlier, this is a very useful
function, and deserves some special attention.
Here are some of the statements in EXTEND.H having to do
with _parinfo() (also on page 62 of January 1986 DBA):
#define PCOUNT (_parinfo(0))
#define ISCHAR(n) (_parinfo(n) & CHARACTER)
#define ISNUM(n) (_parinfo(n) & NUMERIC)
#define ISLOG(n) (_parinfo(n) & LOGICAL)
#define ISDATE(n) (_parinfo(n) & DATE)
_parinfo() gives us the very important ability to pass a variable
number of parameters to a user-defined function, and also to pass
parameters of varying types. If we are writing C code, we simply
include these macros to check the number of parameters passed,
and their type, and then execute the appropriate section of code.
To apply _parinfo() to assembler code, we have to look at these
macro definitions closely to understand what they mean, then
express them accordingly. PCOUNT, for instance, is defined as
_parinfo(0). The macro GET_PCOUNT simply PUSHes a zero in AX
onto the stack, then calls _PARINFO. Clipper returns the number
of parameters passed in AX. ISCHAR(n) is defined as (_parinfo(n)
& CHARACTER). So to obtain the type of the nth parameter, we
PUSH n onto the stack and CALL _PARINFO. This is what the macro
GET_PTYPE does. _PARINFO returns a numeric code in AX
corresponding to the type of the variable, as defined in EXTEND.H
and EXTENDA.MAC. As the definition of ISCHAR tells us, to
determine if the variable is of CHARACTER type, we AND AX with
the CHARACTER constant we have defined, i.e. 1. If we are left
with a zero, the parameter is NOT character data. Otherwise, it
is. The code would look like this.
GET_PTYPE 1 ; Get type of first parameter
AND AX,CHARACTER ; Is it character?
JZ NOT_CHAR ; No, branch
; Code for character parameter follows here
The GET and RET macros perform the tasks I described above:
the GETs PUSH a number onto the stack and call Clipper to
retrieve the corresponding variable; the RETs PUSH the computed
values onto the stack and call Clipper to return them. All the
macros are courteous enough to restore the stack pointer (SP).
Before I present the code for an assembly-language function
which uses these macros, there are a couple of subtleties I want
to mention.
Remember that _parc() and _pards() are declared as returning
pointers to character data. This would seem to suggest that they
pass us the address of the corresponding variable. For instance,
suppose we have a user-defined function CAPITALS() which converts
letters to upper-case. It does not return a value, it simply
takes the character string passed and converts all the letters.
What would we expect the following Clipper code to produce?
m_string1 = 'data-based advisor'
? CAPITALS( m_string1 )
? m_string1
We would expect that because our function does not return a
value, the second statement would not output anything, and the
third one would output DATA-BASED ADVISOR. In fact, the third
outputs data-based advisor. This is because _parc() and _pards()
pass a character pointer, yes, but NOT a pointer to the actual
variable--only a pointer to a temporary copy of that variable.
Essentially, Clipper passes all parameters to functions by value,
not by reference. This may seem like a silly design at first
sight, but it is quite consistent with the role most high-level
languages assign to functions: to return a value. They use
procedures to alter variables or perform significant tasks.
Clipper's CALL statement DOES pass the address of the actual
variable.
I have come across some situations where this was an
inconvenience, for example when I wanted to write functions
returning the segment and offset addresses of a variable. I
wanted the syntactical brevity of a function call, but I also had
to have the address of the actual variable. The solution is to
write a little Clipper function which does the CALL, and pass it
the name of the variable as a character string. The function
then issues the CALL statement using macro expansion with the
string passed to it. Here is the function SEG() from Tom
Rettig's and my Clip-On library:
.cp13
*************
*
* SEG() FUNCTION
*
* SYNTAX: SEG( <expC> )
*
* PARAMETERS: <expC> = name of memory variable
* as a character string
*
* RETURNS: segment address of memory variable
* as a hexadecimal string
*
*************
FUNCTION SEG
PARAMETERS m_var_in
PRIVATE m_var_out
m_var_out = SPACE(4)
* Note use of &m_var_in
CALL segment WITH &m_var_in, m_var_out
RETURN m_var_out
* End of function: SEG()