guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: using guile like a awk filter in a C program.


From: Maxime Devos
Subject: RE: using guile like a awk filter in a C program.
Date: Mon, 10 Jun 2024 11:08:37 +0200

>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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]