home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l224 / 1.img / MANUAL.ZIP / PROLOG.DOC < prev    next >
Encoding:
Text File  |  1990-10-29  |  23.3 KB  |  675 lines

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