home *** CD-ROM | disk | FTP | other *** search
/ Jason Aller Floppy Collection / 240.img / TASM20-1.ZIP / MANUAL.ZIP / PROLOG.DOC < prev    next >
Encoding:
Text File  |  1990-05-07  |  21.6 KB  |  684 lines

  1.  
  2. Interfacing Turbo Assembler with Turbo Prolog
  3.  
  4.  
  5. Turbo Prolog offers the programmer a wealth of predicates that
  6. provide a rich set of high-level functions, from screen window
  7. management to B+ tree database management. What Turbo Assembler
  8. adds to Turbo Prolog is a low-level programming facility.
  9.  
  10. We'll first take a look at the interface between
  11. Turbo Prolog and Turbo Assembler. Then we'll build some simple
  12. examples of interfacing assembly routines to Turbo Prolog. Finally,
  13. we'll discuss calling Turbo Prolog predicates from assembly code,
  14. using Turbo Prolog library calls and passing compound structures.
  15.  
  16. Note: When referring to Turbo Prolog, we mean versions 1.0 and
  17. greater.
  18.  
  19.  
  20.    Declaring external predicates
  21.  
  22. Turbo Prolog allows interfacing with other languages through the
  23. use of a global predicates declaration. A language specification is
  24. appended to the declaration so that Turbo Prolog knows a global
  25. predicate is implemented in another language:
  26.  
  27.   global predicates
  28.      add(integer,integer,integer) - (i,i,o),(i,i,i) language asm
  29.      scanner(string,token) - (i,o) language Pascal
  30.  
  31. Turbo Prolog makes the interfaced language explicit to simplify the
  32. problems of activation record and parameter format, calling and
  33. returning conventions, segment definition, linking, and
  34. initialization.
  35.  
  36.  
  37.    Calling conventions and parameters
  38.  
  39. The 8086 processor family gives the programmer a choice between
  40. near and far subroutine calls. Turbo Prolog creates large memory
  41. model programs and requires that all calls to and returns from
  42. subroutines be far.
  43.  
  44. Turbo Prolog supports a number of calling conventions; C, Pascal,
  45. and assembler. When interfacing to a routine written using the C
  46. calling convention, the parameters are pushed onto the stack in
  47. reverse order and, after returning, the stack pointer is
  48. automatically adjusted. When interfacing to other languages, the
  49. parameters are pushed in the normal order, and the called function
  50. is responsible for removing the parameters from the stack.
  51.  
  52. In many language compilers for the 8086 family, there is a choice
  53. between 16-bit and 32-bit pointers, where the 16-bit pointers refer
  54. to a default segment. Turbo Prolog always uses 32-bit pointers to
  55. access all memory.
  56.  
  57. Turbo Prolog types are implemented in the following way:
  58.  
  59.   integer   2 bytes
  60.   real      8 bytes (IEEE format)
  61.   char      1 byte (2 bytes when pushed on the stack)
  62.   string    4-byte dword pointer to a null-terminated string
  63.   symbol    4-byte dword pointer to a null-terminated string
  64.   compound  4-byte dword pointer to a record
  65.  
  66. An output parameter is pushed as a 32-bit pointer to a location
  67. where the return value must be assigned. For input parameters, the
  68. value is pushed directly, and the size of the parameter depends on
  69. its type.
  70.  
  71.  
  72.      Naming conventions
  73.  
  74. The same predicate in Turbo Prolog can have several type variants
  75. and several flow variants. Each type and flow variant must have its
  76. own procedure that's assigned a unique name. This is done by
  77. numbering the different procedures with the same predicate name
  78. from 0 upward. For example, given the declaration
  79.  
  80.   global predicates
  81.      add(integer,integer,integer)-(i,i,o),(i,i,i) language asm
  82.  
  83. the first variant--with flow pattern (i,i,o)--is named add_0, and
  84. the second--with flow pattern (i,i,i)--is named add_1.
  85.  
  86. Turbo Prolog also allows the programmer to declare an explicit name
  87. for a global predicate. This is done by succeeding the declaration
  88. with an "as public name" part. In the following example, the global
  89. predicate pred will be resolved by an identifier name my_pred, not
  90. pred_0.
  91.  
  92.   global predicates
  93.      pred(integer,integer)-(i,o) language asm as "my_pred"
  94.  
  95. This method is good when you're naming predicates that have only
  96. one flow pattern. If more than one flow pattern exists, you'll have
  97. to provide a name for each variant. Using the add predicate as an
  98. example, the predicate definition might read
  99.  
  100.   global predicates
  101.      add(integer,integer,integer)-(i,i,o) language asm as "doadd"
  102.      add(integer,integer,integer)-(i,i,i) language asm as
  103.   "add_check"
  104.  
  105. The first variant--with flow pattern (i,i,o)--is named doadd, and
  106. the second--with flow pattern (i,i,i)--is named add_check. Note
  107. that this naming method requires the variants to be declared
  108. separately.
  109.  
  110.  
  111.    Writing assembly language predicates
  112.  
  113. Perhaps the simplest predicates to write are those that have only
  114. input flow patterns. Suppose you wanted to scroll the contents of
  115. the current Turbo Prolog window horizontally. You could create the
  116. predicate scroll_left that scrolls a region of the screen one
  117. column to the left. In the SCROLLH.PRO example, scroll_left will
  118. take four integer arguments and one flow pattern.
  119.  
  120. The Turbo Prolog module SCROLLH.PRO contains a global predicates
  121. declaration for the predicate scroll_left. The scroll_left
  122. predicate is defined as an assembly predicate.
  123.  
  124.   /* SCROLLH.PRO */
  125.  
  126.   global predicates
  127.      scroll_left(integer,integer,integer,integer) -
  128.         (i,i,i,i) language asm
  129.  
  130.   predicates
  131.      scrollh
  132.  
  133.   clauses
  134.      scrollh :-
  135.         makewindow(_,_,_,_,Row,Col,Nrows,Ncols),
  136.         scroll_left(Row,Col,Nrows,Ncols),
  137.         readchar(C),
  138.         char_int(C,CI),
  139.         not(CI = 27),
  140.         scrollh.
  141.  
  142.   goal
  143.      makewindow(1,7,7," A SCROLLING MESSAGE ",10,20,4,60),
  144.      write("This message will scroll across the window"),nl,
  145.      write("Look at it go!"),
  146.      readchar(_),
  147.      scrollh,
  148.      readchar(_).
  149.  
  150. The following assembly language source is the implementation of the
  151. scroll_left predicate. Notice that the name given to the predicate
  152. is SCROLL_LEFT_0. This name conforms (as it must) to the naming
  153. conventions discussed earlier.
  154.  
  155.   ;  SCROL.ASM
  156.   ;
  157.        name   scrol
  158.   ;
  159.   ;    scroll_left(integer,integer,integer,integer) -
  160.   ;       (i,i,i,i) language asm
  161.   ;
  162.   SCROL_TEXT     SEGMENT  BYTE PUBLIC 'CODE'
  163.        ASSUME    cs:SCROL_TEXT
  164.   PUBLIC SCROLL_LEFT_0
  165.   SCROLL_LEFT_0  PROC FAR
  166.   ;
  167.   ; parameters
  168.   arg  NCOLS:WORD, NROWS:WORD, COL:WORD, ROW:WORD = ARGLEN
  169.   ;
  170.   ; local variable
  171.   local      SSEG :WORD = LSIZE
  172.        push  bp
  173.        mov   bp,sp
  174.        sub   sp,lsize        ;room for local variables
  175.        push  si
  176.        push  di
  177.        mov   SSEG, 0B800h
  178.        sub   NCOLS, 3        ;NCOLS = NCOLS - 3
  179.        mov   ax, ROW         ;DEST = ROW*160 + (COL+1)*2
  180.        mov   dx,160
  181.        mul   dx
  182.        mov   dx, COL
  183.        inc   dx              ;added
  184.        shl   dx,1
  185.        add   dx,ax
  186.        push  ds
  187.        push  es
  188.        mov   bx , NROWS      ;loop NROWS times using BX as counter
  189.        dec   bx              ;NROWS = NROWS - 2
  190.        dec   bx
  191.   Top: cmp   bx ,0
  192.        je    Done
  193.        add   dx, 160         ;dest = dest + 160
  194.        mov   ax,NCOLs        ;lastchar = dest + nc*2
  195.        shl   ax,1
  196.        add   ax,dx
  197.        push  ax              ;push lastchar offset on stack
  198.        mov   ax,SSEG         ;load screen segment into ES, DS
  199.        mov   es,ax
  200.        mov   ds,ax
  201.        mov   di,dx           ;set up SI and DI for movs
  202.        mov   si,di           ;source is 2 bytes above DEST
  203.        add   si,2
  204.        mov   ax,[di]         ;save the char in col 0 in AX
  205.        mov   cx,NCOLS        ;mov NCOLS words
  206.        cld
  207.        rep   movsw
  208.        pop   di              ;pop lastchar offset to DI
  209.        mov   [di],ax         ;put char in AX to last column
  210.        dec   bx
  211.        jmp   TOP
  212.   Done:pop   es
  213.        pop   ds
  214.        pop   di
  215.        pop   si
  216.        mov   sp,bp
  217.        pop   bp
  218.        ret   ARGLEN
  219.   SCROLL_LEFT_0  ENDP
  220.   SCROL_TEXT     ENDS
  221.        END
  222.  
  223. To create an executable file from SCROLLH.PRO and SCROL.ASM, first
  224. compile the Turbo Prolog file to an .OBJ file using Turbo Prolog.
  225. (When Turbo Prolog compiles a module, it creates an .OBJ file and a
  226. .SYM file.) Then assemble SCROL.ASM to an .OBJ file with Turbo
  227. Assembler, and link the modules together with the following TLINK
  228. command line:
  229.  
  230.   TLINK init scrollh scrol scrollh.sym,scroll,,prolog
  231.  
  232. The resultant executable file will be named SCROLL.EXE.
  233.  
  234.  
  235.      Implementing the double predicate
  236.  
  237. Suppose an assembly language routine is to be called into operation
  238. via the clause
  239.  
  240.   double(MyInVar,MyOutVar)
  241.  
  242. with MyInVar bound to an integer value before the call so that,
  243. after the call, MyOutVar is bound to twice that value.
  244.  
  245. The following assembly language function implements the double
  246. predicate:
  247.  
  248.   ;
  249.   ; MYASM.ASM
  250.   ;
  251.   A_PROG     SEGMENT BYTE
  252.              ASSUME cs:a_prog
  253.              PUBLIC double_0
  254.   double_0   PROC   FAR
  255.              push   bp
  256.              mov    bp,sp
  257.              mov    ax, [bp]+6         ;get the value to which
  258.                                        ; MyInVar is bound
  259.              add    ax,ax              ;double that value
  260.              lds    si,DWORD PTR [bp]+10
  261.              mov    [si],ax            ;store the value to which
  262.                                        ; MyOutVar is to be bound in
  263.                                        ; the appropriate address
  264.              pop    bp
  265.              mov    sp,bp
  266.              ret    6
  267.   double_0  ENDP
  268.   A_PROG    ENDS
  269.  
  270. The Turbo Prolog program containing the call to double must contain
  271. the following global predicates declaration:
  272.  
  273.   global predicates
  274.      double(integer,integer) - (i,o) language asm
  275.  
  276. Otherwise, the Turbo Prolog program is no different from any other
  277. program.
  278.  
  279. The following program uses this double:
  280.  
  281.   /* MYPROLOG.PRO */
  282.  
  283.   global predicates
  284.      double(integer,integer) - (i,o) language asm
  285.  
  286.   goal
  287.      write("Enter an integer "),
  288.      readint(I),
  289.      double(I,Y),
  290.      write(I," doubled is ",Y).
  291.  
  292. If this assembly language program module is assembled into the file
  293. MYASM.OBJ, and the calling Turbo Prolog object module is
  294. MYPROLOG.OBJ, the two can be linked via this command line
  295.  
  296.   TLINK init myprolog myasm myprolog.sym,double,,prolog
  297.  
  298. and produce an executable, stand-alone program in the file
  299. DOUBLE.EXE (using the Turbo Prolog library in PROLOG.LIB). It is
  300. important that MYPROLOG.SYM appear as the last file name before the
  301. first comma in the TLINK command.
  302.  
  303. In general, the format of an activation record will depend on the
  304. number of parameters in the calling Turbo Prolog predicate and the
  305. domain types corresponding to those parameters.
  306.  
  307. Each parameter occupies a corresponding number of bytes. For
  308. output parameters, the size is always 4 bytes (used for segment
  309. address and offset).  For input parameters, the size is determined
  310. by the value actually pushed onto the stack, so it is dependent on
  311. the corresponding domain.
  312.  
  313. Val1 and Val2, belonging to an integer domain and being used with
  314. an (i) flow pattern, both occupy 2 bytes; Sum, being used with an
  315. (o) flow pattern, occupies 4 bytes.
  316.  
  317. Note also that, within the Turbo Prolog compiler, a call to an
  318. external predicate takes the form
  319.  
  320.   mov  ax,SEGMENT data
  321.   mov  ds,ax
  322.   call FAR PTR external_predicate_implementation
  323.  
  324. so the data segment that's addressed while a procedure for an
  325. external predicate is being executed is the segment called DATA.
  326.  
  327.  
  328.    Implementing predicates with multiple flow patterns
  329.  
  330. When implementing predicates with multiple flow patterns, you must
  331. be careful that the assembly language functions adhere to the Turbo
  332. Prolog naming convention. For example, suppose you want to
  333. implement the predicate add, which has multiple flow patterns. add
  334. will find the missing value in the equation X + Y = Z when any two
  335. of the three arguments are bound at the time of the call to add.
  336.  
  337. The following Turbo Prolog program, ADDPRO.PRO, declares the global
  338. assembly language predicate add. Notice that add has three flow
  339. patterns, (i,i,o), (i,o,i), and (o,i,i).
  340.  
  341.   /* ADDPRO.PRO */
  342.  
  343.   global predicates
  344.      add(integer,integer,integer) -
  345.          (i,i,o),(i,o,i),(o,i,i) language asm
  346.  
  347.   goal
  348.      add(2,3,X), write("2 + 3 = ",X),nl,
  349.      add(2,Y,5), write("5 - 2 = ",Y),nl,
  350.      add(Z,3,5), write("5 - 3 = ",Z),nl.
  351.  
  352. The following assembly language program, ADD.ASM, contains the code
  353. to implement add. ADD_0 corresponds to the (i,i,o) flow pattern,
  354. ADD_1 corresponds to (i,o,i), and ADD_2 to (o,i,i).
  355.  
  356.          name     add
  357.   ADD_TEXT        SEGMENT   BYTE PUBLIC 'CODE'
  358.          ASSUME   cs:ADD_TEXT
  359.          PUBLIC   ADD_0                       ;(i,i,o) flow pattern
  360.   ADD_0  PROC     FAR
  361.          arg      Z:DWORD, Y:WORD, X:WORD = ARGLEN1
  362.          push     bp
  363.          mov      bp,sp
  364.          mov      ax,X
  365.          add      ax,Y
  366.          les      bx,Z
  367.          mov      WORD PTR es:[bx],ax
  368.          pop      bp
  369.          ret      ARGLEN1
  370.   ADD_0  ENDP
  371.          PUBLIC   ADD_1                       ;(i,o,i) flow pattern
  372.   ADD_1  PROC     FAR
  373.   arg    Z:WORD,  Y:DWORD, X:WORD = ARGLEN2
  374.          push     bp
  375.          mov      bp,sp
  376.          mov      ax, Z
  377.          sub      ax, X
  378.          les      bx, Y
  379.          mov      WORD PTR es:[bx],ax
  380.          pop      bp
  381.          ret      ARGLEN2
  382.   ADD_1  ENDP
  383.          PUBLIC   ADD_2                       ;(o,i,i) flow pattern
  384.   ADD_2  PROC     FAR
  385.   arg    Z:WORD,  Y:WORD, X:DWORD = ARGLEN3
  386.          push     bp
  387.          mov      bp,sp
  388.          mov      ax, Z
  389.          sub      ax, Y
  390.          les      bx, X
  391.          mov      WORD PTR es:[bx],ax
  392.          pop      bp
  393.          ret      ARGLEN3
  394.   ADD_2  ENDP
  395.   ADD_TEXT        ENDS
  396.          END
  397.  
  398. After ADDPRO.PRO and ADD.ASM have been translated to .OBJ files,
  399. you can create an .EXE file with the following command line:
  400.  
  401.   TLINK init addpro add addpro.sym,addpro,,prolog
  402.  
  403.  
  404.    Calling Turbo Prolog predicates from assembly functions
  405.  
  406. Now that we've discussed calling assembly language functions from
  407. Turbo Prolog, we'll cover it in reverse--calling Turbo Prolog
  408. predicates from assembly language.
  409.  
  410. When a predicate is declared as a global predicate, the predicate's
  411. variants become global functions that can be called by any other
  412. module. The naming and calling conventions are the same as for
  413. predicates defined in assembly language.
  414.  
  415. The following Turbo Prolog module defines two global predicates:
  416. popmessage and from_asm. popmessage is declared as a C language
  417. predicate and from_asm is declared as an assembly language
  418. predicate.
  419.  
  420. To build SHOWMESS, compile SHOWMESS.PRO to .OBJ from the Turbo
  421. Prolog development environment. Then compile FROM_ASM.ASM with
  422.  
  423.   tasm from_asm
  424.  
  425. and link with
  426.  
  427.   TLINK init showmess from_asm showmess.sym,showmess,,prolog
  428.  
  429. Here's SHOWMESS:
  430.  
  431.   /* SHOWMESS.PRO */
  432.  
  433.   global predicates
  434.      popmessage(string) - (i) language c        /* predicate called from
  435.                                      assembly language procedure */
  436.      from_asm - language asm      /* assembly language procedure */
  437.  
  438.   clauses
  439.      popmessage(S) :-   /* can be called as a c function named popmessage_0 */
  440.         str_len(S,L),
  441.         LL = L + 4,
  442.         makewindow(13,7,7,"",10,10,3,LL),
  443.         write(S),
  444.         readchar(_),
  445.         removewindow.
  446.  
  447.   goal
  448.      from_asm.                                       /* external */
  449.  
  450. The following assembly code implements from_asm and issues a call
  451. to popmessage:
  452.  
  453.           EXTRN   PopMessage_0:FAR
  454.   DGROUP  GROUP   _DATA
  455.           ASSUME  cs:SENDMESS_TEXT,ds:DGROUP
  456.   _DATA   SEGMENT WORD PUBLIC 'DATA'
  457.   mess1   DB      "Report: Condition Red",0
  458.   _DATA   ENDS
  459.   SENDMESS_TEXT   SEGMENT   BYTE PUBLIC 'CODE'
  460.           PUBLIC  FROM_ASM_0
  461.   FROM_ASM_0      PROC    FAR
  462.           push  ds
  463.           mov   ax,OFFSET DGROUP:mess1
  464.           push  ax
  465.           call  FAR PTR PopMessage_0
  466.           pop   cx
  467.           pop   cx
  468.           ret
  469.   FROM_ASM_0      ENDP
  470.   SENDMESS_TEXT   ENDS
  471.           END
  472.  
  473. A program follows, using high-level assembly extensions to build
  474. the same executable program. To build it, compile SHOWNEW.PRO to
  475. .OBJ from the Turbo Prolog development environment, then compile
  476. FROM_ASM.ASM with
  477.  
  478.   tasm /jmasm51 /jquirks from_new
  479.  
  480. and link with
  481.  
  482.   TLINK init shownew from_new shownew.sym,show2,,prolog
  483.  
  484. Here's SHOWNEW:
  485.  
  486.   /* SHOWNEW.PRO */
  487.   global predicates
  488.      popmessage(string) - (i) language c   /* predicate called from
  489.                                      assembly language procedure */
  490.     from_asm - language c as "_from_asm"      /* define public name of
  491.                                         assembly language procedure */
  492.  
  493.   clauses
  494.      popmessage(S) :-
  495.         str_len(S,L),
  496.         LL=L+4,
  497.         makewindow(13,7,7,"window",10,10,3,LL),
  498.         write(S),
  499.         readchar(_),
  500.         removewindow.
  501.  
  502.   goal
  503.      from_asm.               /* call assembly language procedure */
  504.  
  505. The following assembly code implements from_asm and issues a call
  506. to popmessage (like in the preceding example).
  507.  
  508.   ; FROM_NEW.ASM
  509.  
  510.          EXTRN  PopMessage_0:far
  511.          .MODEL large,c
  512.          .CODE
  513.  
  514.   FROM_ASM     PROC
  515.          push  ds
  516.          mov   ax, OFFSET DGROUP:mess1
  517.          push  ax
  518.          call  FAR PTR PopMessage_0
  519.          pop   cx
  520.          pop   cx
  521.          ret
  522.   FROM_ASM     ENDP
  523.  
  524.          .DATA
  525.   mess1  DB       "Report: Condition Red",0
  526.          END
  527.  
  528.  
  529.        Lists and
  530.         functors
  531.  
  532. In this section, we'll discuss the method used to pass lists and
  533. functors to assembly language predicates. As mentioned previously,
  534. compound Turbo Prolog objects are not passed directly; instead,
  535. Turbo Prolog passes a 4-byte pointer to a structure.
  536.  
  537. The record structure used for both lists and functors is simple and
  538. straightforward. Suppose you had the following Turbo Prolog
  539. domains:
  540.  
  541.   domains
  542.      ilist = integer*
  543.      ifunc = int(integer)
  544.  
  545. The corresponding list-node structure for the ilist domain would be
  546. as follows:
  547.  
  548.   STRUC ILIST
  549.      NodeType DB ?
  550.      Value    DW ?
  551.      NextNode DD ?
  552.   ENDS
  553.  
  554. As you can see from this structure, a list node has three parts:
  555.  
  556.    1) the node type (a byte)
  557.    2) the node value (depends on the type)
  558.    3) the pointer to the next node (4 bytes)
  559.  
  560. The node type can contain two meaningful values: Value 1 means that
  561. the node is a list node, while Value 2 means that the node is an
  562. end-of-list node. (An end-of-list node contains no other meaningful
  563. information.) The node value can be any Turbo Prolog domain.
  564.  
  565. The corresponding structure for the ifunc functor would be as
  566. follows:
  567.  
  568.   STRUC IFUNC
  569.      FuncType DB ?
  570.      Value    DW ?
  571.   ENDS
  572.  
  573. A functor structure has two parts: the functor type and the functor
  574. record. The functor type is an integer associated with the position
  575. of the functor variant in the list of alternates. The first
  576. alternate is type 1, the second is type 2, and so on.
  577.  
  578. In the following Turbo Prolog and Turbo Assembler modules, we've
  579. implemented a predicate that returns a functor to Turbo Prolog:
  580.  
  581. Here's the Turbo Prolog module:
  582.  
  583.   /* FUNC.PRO */
  584.  
  585.   domains
  586.      ifunc = int(integer)
  587.   global predicates
  588.      makeifunc(integer,ifunc) - (i,o) language c
  589.  
  590.   goal
  591.      makeifunc(4,H),
  592.      write(H).
  593.  
  594. And this is the Turbo Assembler module:
  595.  
  596.   ;
  597.   ; IFUNC.ASM
  598.   ;
  599.        EXTRN   _alloc_gstack:FAR   ;_alloc_gstack returns
  600.                                    ; pointer to memory block
  601.   STRUC IFUNC
  602.      FuncType  DB ?
  603.      Value     DW ?
  604.   ENDS
  605.   IFUNC_TEXT     SEGMENT  WORD PUBLIC 'CODE'
  606.        ASSUME    cs:IFUNC_TEXT
  607.        PUBLIC    Makeifunc_0
  608.   Makeifunc_0    PROC FAR
  609.        arg       __inval:WORD, __outp:DWORD
  610.        push      bp
  611.        mov       bp,sp
  612.        mov       ax,3                             ;allocate 3 bytes
  613.        push      ax
  614.        call      FAR PTR _alloc_gstack
  615.        pop       cx
  616.        les       bx,__outp
  617.        mov       [WORD PTR es:bx+2],dx
  618.        mov       [WORD PTR es:bx],ax
  619.        mov       ax,__inval
  620.   ;;   les       bx,__outp
  621.        les       bx,[DWORD PTR es:bx]
  622.        mov       [(IFUNC PTR es:bx).VALUE],ax     ;value = __inval
  623.        mov       [(IFUNC PTR es:bx).FUNCTYPE],1   ;type  = 1
  624.        pop       bp
  625.        ret
  626.   Makeifunc_0    ENDP
  627.   IFUNC_TEXT     ENDS
  628.        END
  629.  
  630. This example used only one functor type for ifunc. If you were to
  631. declare another functor, like so:
  632.  
  633.   myfunc = int(integer); char(char); r(real); d2(integer,real)
  634.  
  635. the structure would become somewhat more complicated. The structure
  636. would still have two parts, but the second part would be a union of
  637. the data structures required to define all the variants for myfunc.
  638. The following structure is a possible implementation of myfunc in
  639. Turbo Assembler:
  640.  
  641.   STRUC MyFunc
  642.         FuncType DB ?
  643.         UNION
  644.            STRUC
  645.               _int DW ?
  646.            ENDS
  647.            STRUC
  648.               _char DB ?
  649.            ENDS
  650.            STRUC
  651.               _real DQ ?
  652.            ENDS
  653.            STRUC
  654.               v1   DW ?
  655.               v2   DQ ?
  656.            ENDS
  657.         ENDS
  658.   ENDS
  659.  
  660. The types associated with functor alternates would be
  661.  
  662.     int(integer)      1
  663.     char(char)        2
  664.     r(real)           3
  665.     d2(integer,real)  4
  666.  
  667. To help put lists and functors into focus, take a look at the
  668. earlier domains declaration of ilist. Why are the valid node types
  669. 1 and 2? Because Turbo Prolog treats ilist as a structure that
  670. could have been just as easily declared as
  671.  
  672.   ilist = listnode(integer,listnode); end_of_list.
  673.  
  674. Keep in mind that when you pass compound objects, you pass a
  675. pointer to a structure. More specifically: An input flow pattern
  676. list or functor is passed by reference; an output flow pattern list
  677. or functor is passed as a pointer to a reference to a structure.
  678. (Turbo Prolog passes the address of a pointer to the returned
  679. structure.) All structures returned to Turbo Prolog should use
  680. memory allocated with Turbo Prolog's memory allocation functions.
  681. (Refer to the Turbo Prolog User's Guide and the Turbo Prolog
  682. Reference Guide.)
  683.  
  684.