home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / d_b_a / 86_11 / seg() < prev   
Text File  |  1986-10-06  |  10KB  |  516 lines

  1. ;----------------------------------
  2. ;
  3. ; EXTENDA.MAC
  4. ;
  5. ;   by Ralph Davis
  6. ;
  7. ; Placed in the public domain.
  8. ;
  9. ; Assembly language macros for Clipper interface
  10. ;
  11. ;----------------------------------
  12.  
  13.           ; Declare all Clipper internal functions
  14.  
  15.           EXTRN    _PARINFO:FAR
  16.           EXTRN    _PARC:FAR
  17.           EXTRN    _PARNI:FAR
  18.           EXTRN    _PARNL:FAR
  19.           EXTRN    _PARND:FAR
  20.           EXTRN    _PARDS:FAR
  21.           EXTRN    _PARL:FAR
  22.  
  23.           EXTRN    _RETC:FAR
  24.           EXTRN    _RETNI:FAR
  25.           EXTRN    _RETNL:FAR
  26.           EXTRN    _RETND:FAR
  27.           EXTRN    _RETDS:FAR
  28.           EXTRN    _RETL:FAR
  29.  
  30.  
  31. ; Equates from EXTEND.H
  32.  
  33. UNDEF     EQU      0
  34. CHARACTER EQU      1
  35. NUMERIC   EQU      2
  36. LOGICAL   EQU      4
  37. DATE      EQU      8
  38. ALIAS     EQU      16
  39.  
  40. TRUE      EQU      1
  41. FALSE     EQU      0
  42.  
  43.  
  44. ;--------------------------------------
  45. ;
  46. ; _PAR functions
  47. ;
  48. ;-----------------
  49.  
  50. ; get number of parms passed--returned in AX
  51.  
  52. GET_PCOUNT MACRO
  53.           XOR      AX,AX
  54.           PUSH     AX
  55.           CALL     _PARINFO
  56.           ADD      SP,2
  57.           ENDM
  58.  
  59.  
  60. ; get type of requested parm--returned in AX
  61.  
  62. GET_PTYPE MACRO    N
  63.           MOV      AX,N
  64.           PUSH     AX
  65.           CALL     _PARINFO
  66.           ADD      SP,2
  67.           ENDM
  68.  
  69.  
  70. ; get requested parm as string--returns segment and offset in AX:BX
  71.  
  72. GET_CHAR  MACRO    N
  73.           MOV      AX,N
  74.           PUSH     AX
  75.           CALL     _PARC
  76.           ADD      SP,2
  77.           ENDM
  78.  
  79.  
  80. ; get requested parm as integer--returned in AX
  81.  
  82. GET_INT   MACRO    N
  83.           MOV      AX,N
  84.           PUSH     AX
  85.           CALL     _PARNI
  86.           ADD      SP,2
  87.           ENDM
  88.  
  89.  
  90. ; get requested parm as long integer--returned in AX:BX
  91.  
  92. GET_LONG  MACRO    N
  93.           MOV      AX,N
  94.           PUSH     AX
  95.           CALL     _PARNL
  96.           ADD      SP,2
  97.           ENDM
  98.  
  99.  
  100. ; get requested parm as double--returned in AX:BX:CX:DX
  101.  
  102. GET_DBL   MACRO    N
  103.           MOV      AX,N
  104.           PUSH     AX
  105.           CALL     _PARND
  106.           ADD      SP,2
  107.           ENDM
  108.  
  109.  
  110. ; get requested parm as date string
  111. ; returns segment and offset as AX:BX
  112.  
  113. GET_DATESTR MACRO N
  114.           MOV      AX,N
  115.           PUSH     AX
  116.           CALL     _PARDS
  117.           ADD      SP,2
  118.           ENDM
  119.  
  120.  
  121. ; get requested parm as logical true or false--returned in AX
  122.  
  123. GET_LOGICAL MACRO N
  124.           MOV      AX,N
  125.           PUSH     AX
  126.           CALL     _PARL
  127.           ADD      SP,2
  128.           ENDM
  129.  
  130.  
  131. ;--------------------------------------
  132. ;
  133. ; _RET functions
  134. ;
  135. ;---------------
  136. ; return char pointer in REG1:REG2
  137.  
  138. RET_CHAR  MACRO    REG1,REG2
  139.           IRP      X,<REG1,REG2>
  140.           PUSH     X
  141.           ENDM
  142.           CALL     _RETC
  143.           ADD      SP,4
  144.           ENDM
  145.  
  146.  
  147. ; return integer in REG1
  148.  
  149. RET_INT   MACRO    REG1
  150.           PUSH     REG1
  151.           CALL     _RETNI
  152.           ADD      SP,2
  153.           ENDM
  154.  
  155.  
  156. ; return long integer in REG1:REG2
  157.  
  158. RET_LONG  MACRO    REG1,REG2
  159.           IRP      X,<REG1,REG2>
  160.           PUSH     X
  161.           ENDM
  162.           CALL     _RETNL
  163.           ADD      SP,4
  164.           ENDM
  165.  
  166.  
  167. ; return 8-byte floating-point number in REG1:REG2:REG3:REG4
  168.  
  169. RET_DBL   MACRO    REG1,REG2,REG3,REG4
  170.           IRP      X,<REG1,REG2,REG3,REG4>
  171.           PUSH     X
  172.           ENDM
  173.           CALL     _RETND
  174.           ADD      SP,8
  175.           ENDM
  176.  
  177.  
  178. ; return date string pointed to by REG1:REG2
  179.  
  180. RET_DATESTR MACRO REG1,REG2           ; return pointer to date string
  181.                                       ; in REG1:REG2
  182.           IRP      X,<REG1,REG2>
  183.           PUSH     X
  184.           ENDM
  185.           CALL     _RETDS
  186.           ADD      SP,4
  187.           ENDM
  188.  
  189.  
  190. ; return logical true (1) or false (0) in REG1
  191.  
  192. RET_LOGICAL MACRO REG1                ; return 1 or 0 in REG1
  193.           PUSH     REG1
  194.           CALL     _RETL
  195.           ADD      SP,2
  196.           ENDM
  197.  
  198. ; EOF:  EXTENDA.MAC
  199.  
  200.  
  201.  
  202.      Notice that all the Clipper extend system functions must be 
  203.  
  204.  
  205.  
  206. declared as FAR symbols in EXTRN statements.  The assembler does 
  207.  
  208.  
  209.  
  210. not care what kind of values the functions return; it only needs 
  211.  
  212.  
  213.  
  214. to know that it will be generating FAR CALLs to reach them.  The 
  215.  
  216.  
  217.  
  218. EQUates come directly from the #define statements at the 
  219.  
  220.  
  221.  
  222. beginning of EXTEND.H, and translate only the statements we will 
  223.  
  224.  
  225.  
  226. need.
  227.  
  228.      The first two macros, GET_PCOUNT and GET_PTYPE, use 
  229.  
  230.  
  231.  
  232. _parinfo().  As I mentioned earlier, this is a very useful 
  233.  
  234.  
  235.  
  236. function, and deserves some special attention.
  237.  
  238.      Here are some of the statements in EXTEND.H having to do 
  239.  
  240.  
  241.  
  242. with _parinfo() (also on page 62 of January 1986 DBA):
  243.  
  244.  
  245.           #define PCOUNT     (_parinfo(0))
  246.           #define ISCHAR(n)  (_parinfo(n) & CHARACTER)
  247.           #define ISNUM(n)   (_parinfo(n) & NUMERIC)
  248.           #define ISLOG(n)   (_parinfo(n) & LOGICAL)
  249.           #define ISDATE(n)  (_parinfo(n) & DATE)
  250.  
  251.  
  252. _parinfo() gives us the very important ability to pass a variable 
  253.  
  254.  
  255.  
  256. number of parameters to a user-defined function, and also to pass 
  257.  
  258.  
  259.  
  260. parameters of varying types.  If we are writing C code, we simply 
  261.  
  262.  
  263.  
  264. include these macros to check the number of parameters passed, 
  265.  
  266.  
  267.  
  268. and their type, and then execute the appropriate section of code.  
  269.  
  270.  
  271.  
  272. To apply _parinfo() to assembler code, we have to look at these 
  273.  
  274.  
  275.  
  276. macro definitions closely to understand what they mean, then 
  277.  
  278.  
  279.  
  280. express them accordingly.  PCOUNT, for instance, is defined as 
  281.  
  282.  
  283.  
  284. _parinfo(0).  The macro GET_PCOUNT simply PUSHes a zero in AX 
  285.  
  286.  
  287.  
  288. onto the stack, then calls _PARINFO.  Clipper returns the number 
  289.  
  290.  
  291.  
  292. of parameters passed in AX.  ISCHAR(n) is defined as (_parinfo(n) 
  293.  
  294.  
  295.  
  296. & CHARACTER).  So to obtain the type of the nth parameter, we 
  297.  
  298.  
  299.  
  300. PUSH n onto the stack and CALL _PARINFO.  This is what the macro 
  301.  
  302.  
  303.  
  304. GET_PTYPE does.  _PARINFO returns a numeric code in AX 
  305.  
  306.  
  307.  
  308. corresponding to the type of the variable, as defined in EXTEND.H 
  309.  
  310.  
  311.  
  312. and EXTENDA.MAC.  As the definition of ISCHAR tells us, to 
  313.  
  314.  
  315.  
  316. determine if the variable is of CHARACTER type, we AND AX with 
  317.  
  318.  
  319.  
  320. the CHARACTER constant we have defined, i.e. 1.  If we are left 
  321.  
  322.  
  323.  
  324. with a zero, the parameter is NOT character data.  Otherwise, it 
  325.  
  326.  
  327.  
  328. is.  The code would look like this.
  329.  
  330.  
  331.           GET_PTYPE   1         ; Get type of first parameter
  332.           AND     AX,CHARACTER  ; Is it character?
  333.           JZ      NOT_CHAR      ; No, branch
  334.  
  335.           ; Code for character parameter follows here
  336.  
  337.  
  338.      The GET and RET macros perform the tasks I described above:  
  339.  
  340.  
  341.  
  342. the GETs PUSH a number onto the stack and call Clipper to 
  343.  
  344.  
  345.  
  346. retrieve the corresponding variable; the RETs PUSH the computed 
  347.  
  348.  
  349.  
  350. values onto the stack and call Clipper to return them.  All the 
  351.  
  352.  
  353.  
  354. macros are courteous enough to restore the stack pointer (SP). 
  355.  
  356.  
  357.  
  358.      Before I present the code for an assembly-language function 
  359.  
  360.  
  361.  
  362. which uses these macros, there are a couple of subtleties I want 
  363.  
  364.  
  365.  
  366. to mention.
  367.  
  368.      Remember that _parc() and _pards() are declared as returning 
  369.  
  370.  
  371.  
  372. pointers to character data.  This would seem to suggest that they 
  373.  
  374.  
  375.  
  376. pass us the address of the corresponding variable.  For instance, 
  377.  
  378.  
  379.  
  380. suppose we have a user-defined function CAPITALS() which converts 
  381.  
  382.  
  383.  
  384. letters to upper-case.  It does not return a value, it simply 
  385.  
  386.  
  387.  
  388. takes the character string passed and converts all the letters.  
  389.  
  390.  
  391.  
  392. What would we expect the following Clipper code to produce?
  393.  
  394.  
  395.           m_string1 = 'data-based advisor'
  396.           ? CAPITALS( m_string1 )
  397.           ? m_string1
  398.  
  399.  
  400. We would expect that because our function does not return a 
  401.  
  402.  
  403.  
  404. value, the second statement would not output anything, and the 
  405.  
  406.  
  407.  
  408. third one would output DATA-BASED ADVISOR.  In fact, the third 
  409.  
  410.  
  411.  
  412. outputs data-based advisor.  This is because _parc() and _pards() 
  413.  
  414.  
  415.  
  416. pass a character pointer, yes, but NOT a pointer to the actual 
  417.  
  418.  
  419.  
  420. variable--only a pointer to a temporary copy of that variable.  
  421.  
  422.  
  423.  
  424. Essentially, Clipper passes all parameters to functions by value, 
  425.  
  426.  
  427.  
  428. not by reference.  This may seem like a silly design at first 
  429.  
  430.  
  431.  
  432. sight, but it is quite consistent with the role most high-level 
  433.  
  434.  
  435.  
  436. languages assign to functions:  to return a value.  They use 
  437.  
  438.  
  439.  
  440. procedures to alter variables or perform significant tasks.  
  441.  
  442.  
  443.  
  444. Clipper's CALL statement DOES pass the address of the actual 
  445.  
  446.  
  447.  
  448. variable.
  449.  
  450.      I have come across some situations where this was an 
  451.  
  452.  
  453.  
  454. inconvenience, for example when I wanted to write functions 
  455.  
  456.  
  457.  
  458. returning the segment and offset addresses of a variable.  I 
  459.  
  460.  
  461.  
  462. wanted the syntactical brevity of a function call, but I also had 
  463.  
  464.  
  465.  
  466. to have the address of the actual variable.  The solution is to 
  467.  
  468.  
  469.  
  470. write a little Clipper function which does the CALL, and pass it 
  471.  
  472.  
  473.  
  474. the name of the variable as a character string.  The function 
  475.  
  476.  
  477.  
  478. then issues the CALL statement using macro expansion with the 
  479.  
  480.  
  481.  
  482. string passed to it.  Here is the function SEG() from Tom 
  483.  
  484.  
  485.  
  486. Rettig's and my Clip-On library:
  487.  
  488.  
  489.  
  490. .cp13
  491. *************
  492. *
  493. *  SEG() FUNCTION
  494. *
  495. *      SYNTAX:  SEG( <expC> )
  496. *
  497. *  PARAMETERS:  <expC> = name of memory variable
  498. *                        as a character string
  499. *
  500. *     RETURNS:  segment address of memory variable
  501. *               as a hexadecimal string
  502. *
  503. *************
  504.  
  505. FUNCTION SEG
  506. PARAMETERS m_var_in
  507. PRIVATE m_var_out
  508. m_var_out = SPACE(4)
  509.  
  510. * Note use of &m_var_in
  511. CALL segment WITH &m_var_in, m_var_out
  512. RETURN m_var_out
  513.  
  514. * End of function:  SEG()
  515.  
  516.