libtcc doesn't give you much control AST wise, you basically just feed it strings. I'm using it for the purpose you mentioned though--scripting language backend--since for my current "scripting-language" project I can emit C89, and it's plenty fast enough for a REPL!
/* add a file (either a C file, dll, an object, a library or an ld script). Return -1 if error. */
int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return non zero if error. */
int tcc_compile_string(TCCState *s, const char *buf);