Chapter 2. Manipulating Lisp objects

2.1. Objects representation
2.2. Constructing objects
2.3. Integers
2.4. Characters
2.5. Arrays
2.6. Strings
2.7. Bitvectors
2.8. Streams
2.9. Structures
2.10. Instances
2.11. Bytecodes

If you want to extend, fix or simply customize ECL for your own needs, you should understand how the implementation works.

2.1. Objects representation

In ECL a lisp object is represented by a type called cl_object. This type is a word which is long enough to host both an integer and a pointer. The least significant bits of this word, also called the tag bits, determine whether it is a pointer to a C structure representing a complex object, or whether it is an immediate data, such as a fixnum or a character.

  |    Fixnum value   |01|

  | Unused bits| char |10|

  |----------------------|     |--------|--------|-----|--------|
  |    Pointer to cell   |---->| word-1 | word-2 | ... | word-n |
  |----------------------|     |--------|--------|-----|--------|
  | ...................00|     |    actual data of the object   |
  |----------------------|     |--------------------------------|

The fixnums and characters are called immediate datatypes, because they require no more than the cl_object datatype to store all information. All other ECL objects are non-immediate and they are represented by a pointer to a cell that is allocated on the heap. Each cell consists of several words of memory and contains all the information related to that object. By storing data in multiples of a word size, we make sure that the least significant bits of a pointer are zero, which distinguishes pointers from immediate data.

In an immediate datatype, the tag bits determine the type of the object. In non-immediate datatypes, the first byte in the cell contains the secondary type indicator, and distinguishes between different types of non immediate data. The use of the remaining bytes differs for each type of object. For instance, a cons cell consists of three words:

  |CONS|    |          |
  |     car-pointer    |
  |     cdr-pointer    |

There is one important function which tells the type of an object, plus several macros which group several tests.

 C type: cl_object

This is the type of a lisp object. For your C/C++ program, a cl_object can be either a fixnum, a character, or a pointer to a union of structures (See the header object.h). The actual interpretation of that object can be guessed with the macro ecl_t_of.

For example, if x is of type cl_object, and it is of type fixnum, we may retrieve its value

    if (ecl_t_of(x) == t_fixnum)
    printf("Integer value: %d\n", fix(x));

If x is of type cl_object and it does not contain an immediate datatype, you may inspect the cell associated to the lisp object using x as a pointer. For example,

    if (ecl_t_of(x) == t_cons)
    printf("CAR = %x, CDR = %x\n", x->, x->cons.cdr);
    else if (ecl_t_of(x) == t_string)
    printf("String: %s\n", x->string.self);

You should see the following sections and the header object.h to learn how to use the different fields of a cl_object pointer.

 C type: cl_type

Enumeration type which distinguishes the different types of lisp objects. The most important values are t_cons, t_fixnum, t_character, t_bignum, t_ratio, t_singlefloat, t_doublefloat, t_complex, t_symbol, t_package, t_hashtable, t_array, t_vector, t_string, t_bitvector, t_stream, t_random, t_readtable, t_pathname, t_bytecodes, t_cfun, t_cclosure, t_gfun, t_instance, t_foreign and t_thread.

 Function: cl_type ecl_t_of (cl_object O)

If O is a valid lisp object, ecl_t_of(O) returns an integer denoting the type that lisp object. That integer is one of the values of the enumeration type cl_type.

 Function: bool FIXNUMP (cl_object o)
 Function: bool CHARACTERP (cl_object o)
 Function: bool CONSP (cl_object o)
 Function: bool LISTP (cl_object o)
 Function: bool ATOM (cl_object o)
 Function: bool ARRAYP (cl_object o)
 Function: bool VECTORP (cl_object o)
 Function: bool STRINGP (cl_object o)

Different macros that check whether o belongs to the specified type. These checks have been optimized, and are preferred over several calls to ecl_t_of.

 Function: bool IMMEDIATE (cl_object o)

Tells whether o is an immediate datatype.