How do I create a scheme list inside a C function, and return that list? I couldn't find any documentation on this, so I searched through gambit.h and came up with this, which fails to compile due to "___hp" being "undeclared".
___hp seems to be used in the definition of ___CONS.
;;======================================== ;; Is this the correct way to create lists?
(c-declare #<<c-declare-end
___SCMOBJ getList () { ___SCMOBJ *a, *b, *c; ___S8 one, two, three;
one = 1; two = 2; three = 3;
return ___CONS(one, ___CONS(two, ___CONS(three, ___NUL))); }
c-declare-end )
(define get-list (c-lambda () scheme-object "getList"))
(read) ;So that I can enter the REPL by interrupting the program.
;;========================================
~ TJay ~
Afficher les réponses par date
At 3:57 Uhr +0730 31.12.2005, TJay wrote:
How do I create a scheme list inside a C function, and return that list? I couldn't find any documentation on this, so I searched through gambit.h and came up with this, which fails to compile due to "___hp" being "undeclared".
I've failed to do things like this as well, due to missing knowledge about those details. (In my gambit->perl interface, I had to use "trampoline" functions to be able to allocate `values' tuples, which is nasty since I had to generate one for each of the possible lengths, alas I limited the possible lengths to 0..10 to be practical, and am waiting for a better way to do this.)
Gambit-compiled functions do set up such variables in their code. I guess that ___hp might stand for "heap pointer" and for some reason (possibly using multiple gambit systems in one program binary?) it is not a global.
Marc: can you give more info? Which parts of the Gambit source do you recommend to try to understand first?
___S8 one, two, three; one = 1; two = 2; three = 3;
return ___CONS(one, ___CONS(two, ___CONS(three, ___NUL)));
Note that you would also have to convert the ___S8 values to ___SCMOBJ, using ___FIX() probably.
(read) ;So that I can enter the REPL by interrupting the program.
Maybe you would like to use (##repl) instead.
Christian.
On 30-Dec-05, at 9:44 PM, Christian wrote:
Marc: can you give more info? Which parts of the Gambit source do you recommend to try to understand first?
___S8 one, two, three; one = 1; two = 2; three = 3;
return ___CONS(one, ___CONS(two, ___CONS(three, ___NUL)));
Note that you would also have to convert the ___S8 values to ___SCMOBJ, using ___FIX() probably.
Some quick notes about allocating Scheme objects in C code...
Scheme objects can be allocated using one of 3 allocation policies:
___MOVABLE the object's location can change as a result of garbage collection ___STILL the object's location cannot change as a result of garbage collection ___PERM the object's location cannot change and it is never reclaimed by the GC
The macro ___CONS(car,cdr) allocates movable pairs, ___BEGIN_ALLOC_VECTOR(n) allocates movable vectors, etc. Movable objects are allocated by incrementing the heap pointer (the local variable ___hp which is a copy of the hp field of the processor state structure). Still pairs are allocated with ___make_pair (car,cdr,policy), still vectors are allocated with ___make_vector (length,init,policy), etc. Still objects have a reference count, initialized to 1 at allocation time, which is taken into account by the garbage collector to infer liveness (in **addition** to the normal roots). This makes it easy to manipulate still objects from C code because the garbage collector does not have to be aware of local C variables referencing still objects (as long as the reference count is > 0 the references will stay valid).
Although it is technically possible, it is a bad idea to allocate movable objects from C code because any allocation can cause a garbage collection (and the C stack is neither treated as a root or updated by the garbage collector).
So the simplest is for C code to only allocate still Scheme objects, and to decrement the reference count back to 0 when the C code returns the object to Scheme code.
Below is an example inspired from sample code in the Gambit manual.
Marc
(c-declare #<<end-c-declare
___SCMOBJ square_alist (int n) { /* builds an association list of the squares of 0 to n-1 */
___SCMOBJ result = ___NUL; /* start with the empty list */ int i = n;
/* build the list starting at the tail */
while (--i >= 0) { ___SCMOBJ elem; ___SCMOBJ new_result;
/* * Invariant: result is either the empty list or a ___STILL pair * with reference count equal to 1. This is important because * it is possible that ___make_pair will invoke the garbage * collector and we don't want the reference in result to become * invalid (which would be the case if result was a ___MOVABLE * pair or if it had a zero reference count). */
elem = ___EXT(___make_pair) (___FIX(i), ___FIX(i*i), ___STILL);
if (___FIXNUMP(elem)) { ___EXT(___release_scmobj) (result); /* allow GC to reclaim result */ return elem; /* fixnum indicates allocation failed */ }
/* * Note that elem will be a ___STILL object with reference count * equal to 1, so there is no risk that it will be reclaimed or * moved if the following call to ___make_pair invokes the * garbage collector. */
new_result = ___EXT(___make_pair) (elem, result, ___STILL);
/* * We can zero the reference count of elem and result (if not * the empty list) because the pair now references these objects * and the pair's reference count is > 0 (it can't be reclaimed * or moved by the garbage collector). */
___EXT(___release_scmobj) (elem); ___EXT(___release_scmobj) (result);
result = new_result;
if (___FIXNUMP(result)) return result; /* fixnum indicates allocation failed */ }
/* * Note that result is either the empty list or a ___STILL pair with * a reference count equal to 1. The reference count must be * decremented to 0 when it is handed back to the Scheme world, so * that it can be reclaimed when the Scheme world no longer * references it. */
___EXT(___release_scmobj) (result);
return result; }
end-c-declare )
(define square-alist (c-lambda (int) scheme-object "square_alist"))
(pp (square-alist 10)) ; test it