home *** CD-ROM | disk | FTP | other *** search
- writing primitives
-
- A primitive in fools' lisp is essentially a wrapper for a C function.
- The arguments applied to the primitive are passed to the function in
- an array along with the argument count.
-
- The functions must be declared properly. A macro, DEFINE(func) in prim.h,
- expands into the proper declaration. The function's formal parameters are
- argv, the argument array, and argc, the argument count. You may not modify
- the elements of argv. When argc is zero, argv is garbage.
-
- The function newPrim will create a lisp object to representing the primitive:
-
- Obj newPrim(alloc, name, cfunc, env, opts, args)
- F_OBJ alloc;
- char *name;
- Obj (*cfunc)(), env;
- int opts, args;
-
- alloc is either gcNew or gcTemp (see below)
- name is the name to which the primitive will be bound
- cfunc is the pointer to the C function of the primitive
- env is the environment where the primitive will be defined (usually
- GlobalEnv or UserEnv)
- opts is either 0 or OPTARG (for a variable number of arguments)
- args is the number of arguments expected (or if opts is OPTARG, the
- minimum number)
-
- There are two object allocators, gcNew and gcTemp.
-
- gcNew returns an object with a reference count of zero, so the
- object's reference count must be maintained manually (or it might never
- get freed). When it is possible to add an actual reference to a newly
- created object, gcNew is appropriate. Primitives, for example, use
- gcNew to allocate objects that they return. By convention, the caller
- of a primitive will add a real reference to whatever the primitive
- returns.
-
- gcTemp allocates objects that are disposed of automatically. Because
- of the way errors are handled and for ease of use, most objects are
- allocated by this routine. gcTemp is not used everywhere because of
- the extra overhead for for automatically freeing them. gcBegin and
- gcEnd is a block structured-like mechanism for managing objects.
- Objects allocated after a gcBegin call are freed by the matching gcEnd
- if they did not gain an additional reference count in the meantime.
- The begin/end pairs can nest but not overlap.
-
- Before the C function is called, the number of arguments passed to the
- primitive is checked. The function will never be called with the wrong
- number of arguments unless it accepts a variable number (opt = OPTARG).
- In this case, the interpreter only checks for a minimum number of
- arguments. The primitive ought to check for excess arguments itself.
- The argc parameter is unnecessary except for the variable argument
- primitives.
-
- Examples:
-
- /* (list ...) Return a list of the args. */
- DEFINE(primList)
- {
- Obj list;
-
- list = NilSymb;
- argv += argc;
- while (--argc >= 0)
- list = newPair(gcNew, *(--argv), list);
- return list;
- }
-
- /* (set-car! pair val) Replace the car of pair with val and return val. */
- DEFINE(primSetCar)
- {
- Obj res = argv[1];
-
- if (!objIsClass(argv[0], Pair))
- errorPrint(BadClass, "%O is not a pair", argv[0]);
- objSetCdr(argv[0], res);
- return res;
- }
-
- /* (square x) Return the square of x */
- DEFINE(primSquare)
- {
- double num;
-
- if (!objIsClass(argv[0], Number));
- errorPrint(BadClass, "%O is not a number", argv[0]);
- num = objNum(argv[0]);
- return newNumber(gcNew, num * num);
- }
-
- /* Create the primitives. */
- void primInit()
- {
- ...
- newPrim(gcNew, "list", primList, GlobalEnv, OPTARG, 0);
- newPrim(gcNew, "set-car!", primSetCdr, GlobalEnv, 0, 2);
- newPrim(gcNew, "square", primSquare, GlobalEnv, 0, 2);
- ...
- }
-
- primList is called with argc equal to 0 and garbage for argv when
- (list) is evaluated. (list a b c) results in argc set to 3 and argv[0]
- through argv[2] filled with the symbol objects a, b, and c.
-
- Although set-car! does not have to return anything in particular, many
- implementations return the previous value of the pair. This requires
- a direct manipulation of the reference counts:
-
- DEFINE(primSetCar)
- {
- Obj prev;
-
- if (!objIsClass(argv[0], Pair))
- errorPrint(BadClass, "%O is not a pair", argv[0]);
-
- prev = objCar(argv[0]);
- objLink(argv[1]);
- DATA(argv[0], car, pairInst) = argv[1];
- --DATA(prev, rc, basicInst);
- return prev;
- }
-
- The reference to the original car of pair, due to the pair itself, must
- be removed without triggering the car's automatic destruction if that
- was the only reference.
-