Domain Implementation

Most types normally used in C form a subset of Visual Prolog domains, and hence have direct equivalents. Below we discuss both simple and complex domain equivalents in C.

Simple Domains

The implementation of Visual Prolog's simple domains are outlined in the following table:

Table 18.3: Visual Prolog Simple Domains




16-bit OS

32-bit OS

char, byte

1 byte (see note)

1 byte (see note)

(u)short, word

2 bytes

2 bytes

(u)long, dword

4 bytes

4 bytes

unsigned, integer

2 bytes

4 bytes


8 bytes (IEEE format)

8 bytes (IEEE format)


4 bytes

4 bytes

Note: The char and byte domains occupy a machine word when pushed on the stack (2 bytes for 16-bit programs, 4 bytes for 32-bit programs).

1. Complex Domains

All non-simple domains are implemented as pointers to things.

The string and symbol domains are pointers to null-terminated character arrays, with symbols being hashed and stored in the symbol table in the heap.

The binary domain is a pointer to a block of memory, prefixed by a dword (32bit platforms) or word (16bit platforms) indicating the net size of the block.






Special consideration must be given to allocation of memory for complex domains. This will be detailed in a later section.

(1) Ordinary Compound Objects and Structures

User-defined compound objects are pointers to records (structs and unions in C). The general format of these is a byte representing the functor (domain alternative), followed by the individual components of the term. These will vary, depending on which alternative we're dealing with. In any case, components belonging to simple domains are stored directly in the term record itself, while complex components are themselves stored as pointers. For example, in this code fragment:

        mydom = i(integer); c(char); s(string)

the functor number will be 1 for the first alternative, i(integer), 2 for the second, c(char), and 3 for the third.

A suitable C typedef for mydom would be:

    typedef struct {
        unsigned char func;
        union {
            int i;
            char c;
            char *s;
        } u;
    } MYDOM;

Here func will have the value 1, 2 or 3, depending on which domain alternative we're dealing with. This then indicates which of the union's components it's appropriate to access.

Functorless Terms (structs)

By prefixing a compound domain declaration with the compiler directive struct, the terms belonging to that domain will not carry functors with them:

        rec = struct record(d1,d2,...)

Apart from the struct directive, terms belonging to a functorless domain are used and written exactly like other terms in your program, except that there can be no alternatives in a functorless domain.

Functorless terms allow you to duplicate C structs when interfacing to C routines and libraries using predefined structs. Apart from that, they'll save you a bit of memory if you don't need alternatives in the domain.

(2) Lists

Lists are implemented exactly like ordinary compound domains, with a field at the end of the record pointing to the next. This is known as linked lists in C terminology. From a Prolog perspective lists are merely a notational convenience. Given for instance a declaration for a list of strings:

        strlist = string*

the C structures relevant for this are identical to those for:

        strlist = elem(string,strlist); endoflist()

The records for the elem alternative will contain:

1.    a functor

2.    a pointer to a string

3.    a pointer to the next element in the list

and the record for the endoflist alternative will only contain a functor.

This collection of fields is reflected in the C data structure for strlist:

    struct node {
        unsigned char functor;
                          /* The type */
        char *value;
                                /* A string pointer */
        struct node *next;
           /* A pointer to struct node */
    } strlist;

The functor field indicates the type of list record. The value is 1 if it's a list element, and 2 if it's the end of the list.