| How to extend C programs with Guile | ||
|---|---|---|
| <<< Previous | Next >>> | |
At the center of the Guile language is a universal type, called a variable. Both data and procedures are stored in variables, and thus both are access in similar ways. This is different than C, where functions and variables are treated rather differently.
In this chapter, we'll look at how Guile declares and uses this universal variable type, discuss its namespace, and show how a C program can use the Guile API to look up variables and the values they contain.
There are three parts to a variable, a name, a container, and the information stored in the container. In C, this is (more or less) the variable name, the pointer, and the value.
In Guile, there is also a variable name, a container, and a value.
Guile and C have slightly different rules for their variable names.
In C, a name can be upper or lower case and may have the underscore character. The variable names are case sensitive. For example, count and Count are different variables in C.
For Guile, a name can be upper or lower case and have a larger variety of punctuation characters. Underscore, hyphen, question mark, and exclamation point are all valid in a Guile variable name. However, the variable names are not case sensitive. For example, count and Count refer to the same variable.
There is a special Guile type for a string that is a name of a variable. It is called a symbol. The Guile functions that deal with symbols are not case sensitive and would know that count and Count are equivalent.
In C, the variable names are used for the convenience of the coder and the compiler. After compilation, the names of the variables need not appear anywhere in the executable. The compiled code may just have pointers to memory locations instead of using variable names. After the compiler does its job, the names of the variables are not necessary to keep around.
In Guile, however, the interpreted nature of the language requires that there be a symbol table that can be queried to find a variable. When a variable is defined, the name of that variable is put in a symbol table, so that the variable may be looked up by name later on. In finding Guile variables from C, this is something that we will do often: we'll look up a symbol in the symbol table to find a variable.
Thus, there is a distinction between a variable and its name. A variable doesn't know its own name. In C, the compiler keeps track the names of variables, converting them into stack and heap locations during the compilation process. In Guile, the interpreter keeps a symbol table so that it can look up variables by name.
In C, each variable points to a location on the stack or the heap, and as such, each variable can be accessed as a pointer, the memory location of the data on the stack or the heap.
The Guile memory model is less direct, but, each variable is encoded in a data structure of type SCM. One could consider this (not too erroneously) as a Guile pointer.
The SCM has two parts. First it contains an encoding of the variable's type. It knows if the data it contains is supposed to be a real number, a string, or a function. Second, it contains the value, or, if the value is too big to be encoded in the SCM, it contains a pointer to a location on the heap where the value lies.
Like C pointers, SCM types can be used to access and modify a variable without knowing the variable's name.
In fact, standard operating procedure will be to look up a variable's name in the Guile name table. This will return the SCM. Then, any access or modification of the value will be made by using functions that operate on the SCM.
From the C point of view, SCM is a very difficult structure with which to deal directly. It is a sort of union of pointer types or integers, and trying to write code that interacts with a SCM directly is not recommended.
Throughout the section, it will be demonstrated that there is already a full API to deal the data of type SCM, so its opaqueness is not a real problem.
The process for looking up a Guile top-level variable by name is the same as looking up a Guile function by name, as seen in the hello_world example on Page here. When looking up a function or a variable, the first step is looking up a Guile symbol.
A Guile symbol binds a name to a variable or function. Scheme is something of an unusual language in that a variable or function does not need to have a name. Unless a symbol binds a name to a variable or function, the variable or function is anonymous. Anonymous functions, lambda functions, are a core feature of Scheme.
The quickest method of looking up a symbol is to use this function \begin{description} \item[SCM scm\_c\_lookup (const char *name);] This function searches the Guile top-level environment for a symbol with the given name. If found, it returns a SCM containing the symbol. If not found, it exits with an error. \end{description}
The disadvantage to using scm_c_lookup is that it terminates if a symbol is not found. Sometimes one wants to search for a symbol and not have it bomb out if it is not found. This can be done, but, unfortunately it really isn't easy to do without using some of the internal functions not really intended as API. So in lieu of explaining the internals of Guile lookups, let me just say that the function does_scm_symbol_exist that follows, tests to see if a symbol is defined, and is presented without explanation. It returns 1 if it is defined and 0 if it is not.
int does_scm_symbol_exist(const char *name)
{
SCM sym;
SCM var;
assert(name != (const char *)NULL);
sym = scm_str2symbol(name);
/* Check to see if the symbol exists */
var = scm_sym2var (sym,
scm_current_module_lookup_closure(),
SCM_BOOL_F
);
if (var != SCM_BOOL_F)
{
return 1;
}
return 0;
}
|
By using this function to pre-test that a symbol exists before calling scm_c_lookup, one can be sure that scm_c_lookup will not exit with an error.
The function scm_c_lookup returns the variable, which is analogous the pointer in C. Usually one does not want to deal with the variable, but instead, it is the variable's value that is desired. Just as in C, one does not want to operate on the pointer, but, on its value. So, to get the value, the variable needs to be dereferenced.
The function that dereferences a variable is scm_variable_ref. It takes a Guile variable and returns its value, encoded into a type SCM.
The value may be a common data type, like a string or real number, or it may be a procedure. It can also be an aggregate data type, like an array.
Once the value has been returned in an SCM type, it can be converted into something usable by C.
If the value is a data type, like a string or real number, there are a set of functions that will convert the SCM to a C type. These will be discussed in the next chapter.
If the value is a procedure, there is a set of functions that will allow that procedure to be called from C. This is discussed in chapter FIXME.
| <<< Previous | Home | Next >>> |
| Summary | Data and Values |