Emacs: This is English -*- Text -*- $Header: prims.txt,v 1.1 87/12/04 10:19:31 GMT cph Rel $ Information on primitives: * Primitives are routines written in the interpreter implementation language (C in this case) which accept Scheme objects as arguments and return a Scheme object as their values. Some of them (APPLY, SCODE-EVAL, CATCH) are really entry points into the interpreter, and in other languages or implementations would be special forms. These depend on the way the interpreter works and should not be modified. Most (all?) of these hooks into the interpreter live in the file hooks.c . * Most primitives are basic in some sense. Their functionality cannot easily be achieved with a procedure written in Scheme (e.g. CAR, PRIMITIVE-TYPE, TTY-READ-CHARACTER, etc). Some exist only for efficiency - they are used very frequently, are easily written in the interpreter implementation language, and this extra work is worth the speed that they provide (eg LENGTH, MEMQ, etc). * The runtime system depends on many primitives (some are fossils and others are used by specialized subsystems only). Users may, however, add new primitives to suit their applications (graphics, matrix multiplication, etc.), and are encouraged to do so. * The system provides some facilities for declaring new primitives, which can then be accessed from Scheme. The linking of the C code which implements these user-supplied (we call them "external") primitives is done at interpreter (microcode) generation time (e.g. when you use "make" to link a new version of scheme under Unix). These externals are handled in such a way that Scheme programs which use them can be loaded on any system, including systems that do not have those primitives. If you run a program which tries to apply one of these undefined externals to arguments, you will, of course, get an error. * The original primitives (provided with CScheme) must always exist, and are not linked in the same way as user defined primitives for historical reasons. They will eventually be linked in the same way, and then there will be no difference between both kinds. As far as linking is concerned, there are two relevant files in the microcode: usrdef.c and bltdef.c . usrdef.c contains the tables which describe the user provided primitives. The position of any primitive in the tables is arbitrary, and can change witouth affecting the behavior of the system. bltdef.c contains the tables which describe the original (or "built in") primitives. The position of any primitive in the table is fixed (in particular, it must match the position in the file utabmd.scm). Both of these C source files are generated by the Findprim program, which assigns arbitrary numbers to user defined primitives every time it generates the tables. * Primitives have 2 names: The C name (the name of the C routine that implements them), and the Scheme linking name. The latter is the name which when given to MAKE-PRIMITIVE-PROCEDURE will return the appropriate procedure object. Note that this name is not usually initially bound in Scheme, and it may be bound to anything at all, though for some of the most common primitives it is bound to the primitive object. In other words, you must choose names for your primitives so that neither the C name nor the linking name have conflicts with other linked primitives, but you need not worry about name conflicts with the Scheme environment. Note also that the linking name is currently ignored for "built in" primitives. * Define_Primitive is a macro used to declare a primitive to the linking mechanism. It is both a C macro (defined in primitive.h) and a special token searched for by the Findprim program to generate the file usrdef.c when a new scheme microcode is linked together. See the file README for information on how to generate a new microcode which includes primitives you have defined. You should not write built-in primitives, since the numbers you allocate for them will probably conflict with numbers chosen at MIT for other primitives. You should also avoid adding your primitives to system files. Write your own new files with user defined primitives. * Define_Primitive expects 3 arguments which are the C name, the number of arguments that the primitive expects (currently primitives cannot receive variable numbers of arguments), and the Scheme linking name. Original primitives make use of the Built_In_Primitive macro instead, which takes a fourth argument declaring what position the primitive occupies in the built-in primitive tables. The position in the table is used for linking, rather than the symbolic name. * One last note: Unless very special care is taken (and we do not recommend it), primitives cannot call other primitives. If you want to share code between two primitives, write a third procedure which implements the common work, and have both primitives call it as appropriate. The reason for this is that the primitive calling convention may change without notice, and the way arguments are accessed may therefore change. As long as you only use Primitive_N_Args to access them, your code will continue to work. In particular, if you write primitives which do not expect any arguments, make sure to use Primitive_0_Args anyway since it will take care of any initialization needed. Define_Primitive, Built_In_Primitive, Primitive_N_Args, and other utilities for primitives are defined in the file primitive.h. * For examples of user defined primitives, look at the files sample.c, xdebug.c, Sgraph.c, or Xgraph.scm in the microcode subdirectory. For an example on how to access these primitives from scheme look at ngraph.scm or Xgraph.scm in the runtime subdirectory.