TCC

https://bellard.org/tcc/

Compilateur C en langage C écrit par Fabrice Bellard un véritable gourou informatique (pour moi il y en a quatre: Dennis Ritchie et Bryan Kernigan qui ont créé le C, Linus Thorwalds et Fabrice).
Il est rapide et sans dépendance exotique genre bison lex yacc qui sont de bons choix pour écrire un compilateur (beaucoup d'applications GNU s'en servent, ce sont des outils qui génèrent le code C pour créer un compilateur), mais Fabrice a tout fait à la main.

Petit et puissant, ce compilateur C peut se compiler sous la forme d'une librairie statique, qu'un exécutable vient embarquer pour exposer certaines de ses fonctions dans un script syntaxe C (et LibC).

Comme Fabrice l'explique dans les documents, voir libtcc.h et libtcc_test.c qui montre comment exposer une fonction, comment appeler une fonction du script depuis le C.


Pour compiler la lib sur Linux 64 bits

Télécharger tcc-0.9.24 et décompresser
$ cd tcc-0.9.24
Créer config.h
#define TCC_VERSION "0.9.24"
// j'ai trouvé un config.h windows dans la source, on est en ELF donc j'ai mis PE 0 et pas 1, ça marche
#define TCC_TARGET_PE 0
#define CONFIG_TCCDIR "."
Créer la librairie statique
// 32 bits: $ gcc -m32 -Os -fno-strict-aliasing tcc.c -D LIBTCC -c -o libtcc.o
$ gcc tcc.c -D LIBTCC -c -o libtcc.o
$ ar rcs libtcc.a libtcc.o
Récupérer libtcc.h et libtcc.a, pas besoin du reste.

Le programme de test qui embarque l'interpréteur TCC

(c'est libtcc_test.c amélioré)
#include <stdlib.h>
#include <stdio.h>
#include "libtcc.h"
TCCState *tcc;
/*============================================================================*/
void triggerScriptCallback(const char*fonc, int a){
    int (*func)(int);
    unsigned long val;

    tcc_get_symbol(tcc, &val, fonc);
    func = (void *)val;
    func(a);
}
/*============================================================================*/
// simule que le des données sont disponibles sur un descripteur socket
// programmation évènementielle des sockets comme faisait VB
void triggerOnDataArrival(int sk, char* msg, int len){
    int (*func)(int,char*,int);
    unsigned long val;

    tcc_get_symbol(tcc, &val, "onDataArrival");
    func = (void *)val;
    func(sk, msg, len);
}
/*============================================================================*/
void sayHello(int a){
    printf("Hello from C function %d\n", a);
}
/*============================================================================*/
char* loadFile(){
    FILE * f;
    long len;
    char * s;

    f = fopen ("script.c", "rb");
    if (f==NULL) return NULL;

    fseek (f, 0, SEEK_END);
    len = ftell (f);
    rewind (f);

    s = (char*) malloc (len);
    if (s == NULL) return NULL;

    fread (s,1,len,f);
    fclose (f);
    return s;
}
/*============================================================================*/
int main(int argc, char **argv)
{
    TCCState *tcc;
    char* script; // code C

    tcc = tcc_new();
    if (!tcc) {
        fprintf(stderr, "Could not create tcc state\n");
        return 1;
    }
    tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY);

    script = loadFile();
    tcc_compile_string(tcc, script);

    // Fonctions exposées. Le script appelle une fonction C
    tcc_add_symbol(tcc,   "sayHello", (unsigned long)&sayHello);
    // ici on peut en mettre d'autres, mais ne pas exposer celle-là!
    //tcc_add_symbol(tcc, "loadFile", (unsigned long)&loadFile);
    tcc_relocate(tcc);

    triggerScriptCallback("main");// Appelle une fonction du script
    triggerScriptCallback("onAccept", 404); // en appelle une 2e pour voir si ça marche
    triggerOnDataArrival(404,"le message", 11);

     free(script);
    tcc_delete(tcc);
    return 0;
}
Le script interprété:
// script.c
int main(int a)
{
    printf("Script started\n");
    sayHello(25); // appelle fonction C
    return 0;
}

void onAccept(int sk){
    printf("accepted %d\n", sk);
}

void onDataArrival(int sk, char* buf, int len){
    printf("data du socket %d [%s] %d\n", sk, buf, len);
}
Compiler la tourelle en embarquant la librairie statique 32 bits
$ gcc -m32 main.c -L. -ltcc -ldl -o test
$ ./test
Script started
Hello from C function 25
accepted 404
data du socket 404 [le message] 11
$