#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "libtcc.h" typedef TCCState TCCStateObj; /* Error handling should store the message and return to the normal execution * order. In other words, croak is inappropriate here. */ void my_tcc_error_func (void * context, const char * msg ) { /* set the message in the error_message key of the compiler context */ hv_store((HV*)context, "error_message", 13, newSVpv(msg, 0), 0); } typedef void (*my_void_func)(void); MODULE = C::TinyCompiler PACKAGE = C::TinyCompiler ############ Creation/Delection ############ void _create_state(context) HV * context CODE: /* create a new state with error handling */ TCCState * state = tcc_new(); if (!state) { croak("Unable to create C::TinyCompiler state!\n"); } tcc_set_error_func(state, context, my_tcc_error_func); tcc_set_output_type(state, TCC_OUTPUT_MEMORY); /* Add the state to the context */ hv_store(context, "_state", 6, newSViv(PTR2IV(state)), 0); void DESTROY(context) HV * context CODE: /* Retrieve and delete the state from the context */ SV * state_sv = hv_delete(context, "_state", 6, 0); /* The hv_delete will only return non-null if the _state actually * existed. Of course, it's possible for somebody to create a compiler * state and never actually compile, in which case _state will not be * present. So, make sure we have something. */ if (state_sv != NULL) { /* Free the compiler state memory XXX not thread-safe */ IV state = SvIV(state_sv); tcc_delete(INT2PTR(TCCState *, state)); } ############ Preprocessor ############ # The next two are pretty much direct copies of each other void _add_include_paths(state, ...) TCCStateObj * state PREINIT: char * path_name; int i, ret; CODE: for (i = 1; i < items; i++) { path_name = SvPVbyte_nolen(ST(i)); ret = tcc_add_include_path(state, path_name); /* As of this time of writing, tcc_add_include always returns zero, * but if that ever changes, this croak is ready to catch it */ if (ret < 0) { croak("Unkown tcc error including path [%s]\n", path_name); } } void _add_sysinclude_paths(state, ...) TCCStateObj * state PREINIT: char * path_name; int i, ret; CODE: for (i = 1; i < items; i++) { path_name = SvPVbyte_nolen(ST(i)); ret = tcc_add_sysinclude_path(state, path_name); /* As of this time of writing, tcc_add_sysinclude always returns * zero, but if that ever changes, this croak is ready to catch it */ if (ret < 0) { croak("Unkown tcc error including syspath [%s]\n", path_name); } } void _define(state, symbol_name, value) TCCStateObj * state const char * symbol_name const char * value CODE: tcc_define_symbol(state, symbol_name, value); ############ Libraries ############ void _add_libraries(state, ...) TCCStateObj * state PREINIT: char * lib_name; int i; CODE: for (i = 1; i < items; i++) { lib_name = SvPVbyte_nolen(ST(i)); if (-1 == tcc_add_library(state, lib_name)) { /* Returns 0 on success, -1 on failure */ croak("Unable to add library %s", lib_name); } } void _add_library_paths(state, ...) TCCStateObj * state PREINIT: char * path; int i; CODE: for (i = 1; i < items; i++) { path = SvPVbyte_nolen(ST(i)); tcc_add_library_path(state, path); } ############ Compiler ############ void _compile(state, code) TCCStateObj * state const char * code CODE: /* Compile and croak if error */ int ret = tcc_compile_string(state, code); if (ret != 0) croak("Something fishy happened\n"); void _add_symbols(state, ...) TCCStateObj * state PREINIT: char * symbol_name; void * symbol_ptr; CODE: /* Make sure we've got an even number of arguments (aside from self) */ if (items % 2 == 0) { croak("INTERNAL ERROR: _add_symbols should only get key => value pairs\n"); } int i; for (i = 1; i < items; i += 2) { symbol_name = SvPVbyte_nolen(ST(i)); symbol_ptr = INT2PTR(void*, SvIV(ST(i+1))); tcc_add_symbol(state, symbol_name, symbol_ptr); } void _relocate(state) TCCStateObj * state CODE: /* Relocate and croak if error */ int ret = tcc_relocate(state, TCC_RELOCATE_AUTO); if (ret < 0) croak("Relocation error\n"); ############ Post-Compiler ############ void _call_void_function(state, func_name) TCCStateObj * state const char * func_name CODE: /* Get a pointer to the function */ my_void_func p_func = (my_void_func)tcc_get_symbol(state, func_name); /* Croak if we encountered errors */ if (p_func == 0) croak("Unable to locate %s", func_name); /* Call it with no inputs and no outputs */ p_func(); void _get_symbols(state, ...) TCCStateObj * state PREINIT: char * symbol_name; void * symbol_pointer; int i; PPCODE: EXTEND(SP, 2*items); for (i = 1; i < items; i++) { /* Get the tentative name */ symbol_name = SvPVbyte_nolen(ST(i)); /* Get a pointer to the symbol */ symbol_pointer = tcc_get_symbol(state, symbol_name); /* croak if the symbol retrieval was not successful, as this is * likely to be the result of a typo on the programmer's part */ if (symbol_pointer == 0) croak("Unable to locate %s", symbol_name); /* Push the resulting key => value onto the return list */ PUSHs(sv_2mortal(newSVpv(symbol_name, strlen(symbol_name)))); PUSHs(sv_2mortal(newSViv(PTR2IV(symbol_pointer)))); }