This section shows how to pass arguments to a new primitive written in C. To illustrate our purpose, we will rewrite the primitive posix-ctime to be conform to POSIX.1 (this function should take an integer, a count of seconds, and should return corresponding date as a string). A second writing of previous function could be:
This function has one parameter since Scheme primitive arity is one. The C primitives parameters are always SCM objects. An object of this type is a pointer to a struct obj: the type which permits to represent all the Scheme objects. The SCM and struct obj types definitions can be found in the Src/stk.h header file.
The first job of this function consists to convert the Scheme parameter (seconds) to a C integer long int. This is done with the function STk_integer_value_no_overflowwhich takes a SCM and returns a long int. This functions returns LONG_MIN if the argument is not a an integer number (or a number which don't fit in the C representation of a C long int). Once this conversion is done, the rest of the job is similar to the code presented above.
To add this primitive to the global Scheme environment, we have to change the previous STk_add_new_primitive for this primitive by:
in the init section. This call states that the type of this primitive is fixed to a tc_subr_1 (a arity-1 primitive).
However, this function is not too satisfying, even if close to the POSIX definition: it obliges to pass a parameter which will be probably most of the time the result of the primitive posix-time (i.e. the most frequent usage of this function will be
which is not very elegant). A better approach consists to allow this
primitive to have a optional parameter. This permits to be at the
same time conform to the POSIX convention and close to Scheme habits.
The following version implements the posix-ctime with a optional
parameter:
If the Scheme posix-ctime primitive is called with one parameter, it will be passed to the C function in the seconds parameter. If posix-ctime is called without parameter, seconds is set to the special value UNBOUND. So, the first test in this function consists to set a correct value to the variable sec; this value is either the current time, either the given integer, depending of the number of parameters given to posix-ctime.
Of course, the type of this new primitive must be changed to allow 0 or 1 parameter. This is done by changing the tc_subr_0 in the previous STk_add_new_primitive by tc_subr_0_or_1.
The following types are available for C primitives:
PRIMITIVE function(SCM arglist, int argcount);Note that all the Scheme arguments are evaluated during the construction of the list which is passed to the C function.
PRIMITIVE function(SCM arglist, SCM env, int argcount);See
To illustrate how to write a tc_lsubr primitive, let's have a look at the code, given below, of the function which implement the Scheme primitive vector:
PRIMITIVE STk_vector(SCM arglist, int argcount) { int j; SCM z = STk_makevect(argcount, NULL); for (j = 0; j < argcount; j++, arglist=CDR(arglist)) { VECT(z)[j] = CAR(arglist); } return z; }
This function receives the values passed to the vector primitives in the list arglist (the length of this list is stored in argcount). This function uses STk_makevect which returns a Scheme vector. Its first argument is the length of the vector and its second argument is the initial value of the vector's elements. Next section will show how to implement a primitive which evaluates itself its parameters (i.e. a tc_fsubr primitive.