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