>it looks ugly. Currently the user just define the 'filter' part and then I >include this string in a larger code. Ant how should I design this if I want >to include modules, custom functions,... ?
I propose replacing the interface for filter part by (lambda (record) [more code here]) and evaluating this only once – i.e., the expression itself, not the value of the procedure at a particular record. Then the user can just do (letrec*() (define custom ...) (lambda (record) [stuff here])) for any custom functions. To include modules, you can just support --use-module (foo bar) in the main function, using the reflection API to import functions. Another option (IMO the best option) is let the user define an entire module (with optional initial (define-module (...)) – that’s not really important for the purposes of the program) and let the last expression be the return filter – you can use the compilation API for this. If you do that, it becomes easy to support other languages than Scheme as well, by passing #:from to procedures like ‘compile’ and adding a ‘--language language’ argument to the main function. >Furthermore, I'd like to include a module that would be embedded in the C code >, in a big const string to avoid any external file, it it possible ? Just do a big scm_eval_string(" (define-module (foo bar)) [code here]"). Be aware that this switches the current module to (foo bar), so you might want to do a module excursion or something. /** contains script as string */ char buffer[2048]; sprintf(global.buffer,"(while (_next) (if %s (_emit) ) (_dispose) ) ",argv[1]); This sprintf is terrible, please never do this. Maybe use scm_string_append + that function for making Scheme strings from C strings instead. In particular, note that if the total length of the text (excluding terminating \0) is 4096, then global.buffer doesn’t have a terminating zero so scm_c_eval_string(g->buffer) is not well-defined. And even if the lack of terminating zero wasn’t a problem, then only part of the script will be run. The “int ret = fscanf(global.in,"%d", &(global.value));” + error handling is also bad. Why does ‘main’ return 0 on input errors and syntax errors? Why is the cause of the error never printed (say, with perror or something) – that would give information on whether it is a mere syntax error or whether the underlying device has some I/O errors. And why are you writing normal output to stderrr instead of stdout? The sprint is also suboptimal for a different reason. For example, suppose that argv[1] is “#true #true)) (if”. This is invalid syntax, but it will be interpreted as something – likely leading to errors, but not the right kind of error, i.e., a syntax error. The simplest way to avoid this while still staying in C (I think it would be simpler to instead lead scheme call C but whatever(*)), I think, is to construct relevant S-expressions as S-expressions – first define “SCM filter_code” with scm_read(scm_open_input_string(argv[1])), then define SCM filter_lambda = scm_list_3(scm_from_utf8_symbol("lambda"),SCM_EOL, filter_code) and so on until you did the C equivalent of (define code #`(let ((filter (lambda () #,(vector-ref argv 1)))) (while (_next) ((if (filter) _emit _dispose))))) At last, you can do scm_eval(code,scm_current_module()). (*) I.e., write a C library that reads binary data from a port and then formats it in some Scheme record, e.g. with a function that reads a single record and then returns the Scheme representation (or an end-of-file marker). It can then be made available to Scheme with scm_c_define (I’m not sure about the name of the function, but surely there is a C function to define a Scheme ‘variable’ (in this case, constant)) etc. Best regards, Maxime Devos