home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / RiscOS / APP / DEVS / LISP / FOOLS.ZIP / Fools / doc / primitives < prev   
Text File  |  1991-10-31  |  4KB  |  127 lines

  1. writing primitives
  2.  
  3. A primitive in fools' lisp is essentially a wrapper for a C function.
  4. The arguments applied to the primitive are passed to the function in
  5. an array along with the argument count.
  6.  
  7. The functions must be declared properly.  A macro, DEFINE(func) in prim.h,
  8. expands into the proper declaration.  The function's formal parameters are
  9. argv, the argument array, and argc, the argument count.  You may not modify
  10. the elements of argv.  When argc is zero, argv is garbage.
  11.  
  12. The function newPrim will create a lisp object to representing the primitive:
  13.  
  14. Obj newPrim(alloc, name, cfunc, env, opts, args)
  15.     F_OBJ alloc;
  16.     char *name;
  17.     Obj (*cfunc)(), env;
  18.     int opts, args;
  19.  
  20. alloc is either gcNew or gcTemp (see below)
  21. name is the name to which the primitive will be bound
  22. cfunc is the pointer to the C function of the primitive
  23. env is the environment where the primitive will be defined (usually
  24.     GlobalEnv or UserEnv)
  25. opts is either 0 or OPTARG (for a variable number of arguments)
  26. args is the number of arguments expected (or if opts is OPTARG, the
  27.     minimum number)
  28.  
  29. There are two object allocators, gcNew and gcTemp.
  30.  
  31. gcNew returns an object with a reference count of zero, so the
  32. object's reference count must be maintained manually (or it might never
  33. get freed).  When it is possible to add an actual reference to a newly
  34. created object, gcNew is appropriate.  Primitives, for example, use
  35. gcNew to allocate objects that they return.  By convention, the caller
  36. of a primitive will add a real reference to whatever the primitive
  37. returns.
  38.  
  39. gcTemp allocates objects that are disposed of automatically.  Because
  40. of the way errors are handled and for ease of use, most objects are
  41. allocated by this routine.  gcTemp is not used everywhere because of
  42. the extra overhead for for automatically freeing them.  gcBegin and
  43. gcEnd is a block structured-like mechanism for managing objects.
  44. Objects allocated after a gcBegin call are freed by the matching gcEnd
  45. if they did not gain an additional reference count in the meantime.
  46. The begin/end pairs can nest but not overlap.
  47.  
  48. Before the C function is called, the number of arguments passed to the
  49. primitive is checked.  The function will never be called with the wrong
  50. number of arguments unless it accepts a variable number (opt = OPTARG).
  51. In this case, the interpreter only checks for a minimum number of
  52. arguments.  The primitive ought to check for excess arguments itself.
  53. The argc parameter is unnecessary except for the variable argument
  54. primitives.
  55.  
  56. Examples:
  57.  
  58. /* (list ...)  Return a list of the args. */
  59. DEFINE(primList)
  60. {
  61.     Obj list;
  62.  
  63.     list = NilSymb;
  64.     argv += argc;
  65.     while (--argc >= 0)
  66.         list = newPair(gcNew, *(--argv), list);
  67.     return list;
  68. }
  69.  
  70. /* (set-car! pair val)  Replace the car of pair with val and return val. */
  71. DEFINE(primSetCar)
  72. {
  73.     Obj res = argv[1];
  74.  
  75.     if (!objIsClass(argv[0], Pair))
  76.         errorPrint(BadClass, "%O is not a pair", argv[0]);
  77.     objSetCdr(argv[0], res);
  78.     return res;
  79. }
  80.  
  81. /* (square x)   Return the square of x */
  82. DEFINE(primSquare)
  83. {
  84.     double num;
  85.     
  86.     if (!objIsClass(argv[0], Number));
  87.         errorPrint(BadClass, "%O is not a number", argv[0]);
  88.     num = objNum(argv[0]);
  89.     return newNumber(gcNew, num * num);
  90. }
  91.  
  92. /* Create the primitives. */
  93. void primInit()
  94. {
  95.     ...
  96.     newPrim(gcNew, "list", primList, GlobalEnv, OPTARG, 0);
  97.     newPrim(gcNew, "set-car!", primSetCdr, GlobalEnv, 0, 2);
  98.     newPrim(gcNew, "square", primSquare, GlobalEnv, 0, 2);
  99.     ...
  100. }
  101.  
  102. primList is called with argc equal to 0 and garbage for argv when
  103. (list) is evaluated.  (list a b c) results in argc set to 3 and argv[0]
  104. through argv[2] filled with the symbol objects a, b, and c.
  105.  
  106. Although set-car! does not have to return anything in particular, many
  107. implementations return the previous value of the pair.  This requires
  108. a direct manipulation of the reference counts:
  109.  
  110. DEFINE(primSetCar)
  111. {
  112.     Obj prev;
  113.  
  114.     if (!objIsClass(argv[0], Pair))
  115.         errorPrint(BadClass, "%O is not a pair", argv[0]);
  116.  
  117.     prev = objCar(argv[0]);
  118.     objLink(argv[1]);
  119.     DATA(argv[0], car, pairInst) = argv[1];
  120.     --DATA(prev, rc, basicInst);
  121.     return prev;
  122. }
  123.  
  124. The reference to the original car of pair, due to the pair itself, must
  125. be removed without triggering the car's automatic destruction if that
  126. was the only reference.
  127.