C-Blocks

 view release on metacpan or  search on metacpan

lib/C/Blocks.xs  view on Meta::CPAN

	
	count = call_pv("DynaLoader::dl_find_symbol", G_SCALAR);
	SPAGAIN;
	if (count != 1) croak("C::Blocks expected one return value from dl_find_symbol but got %d\n", count);
	SV * returned = POPs;
	void * to_return = NULL;
	if (SvOK(returned)) to_return = INT2PTR(void*, SvIV(returned));
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return to_return;
}

void * dynaloader_get_lib(pTHX_ char * name) {
	dSP;
	int count;
	
	ENTER;
	SAVETMPS;
	
	PUSHMARK(SP);
	XPUSHs(sv_2mortal(newSVpv(name, 0)));
	PUTBACK;
	
	count = call_pv("DynaLoader::dl_load_file", G_SCALAR);

	SPAGAIN;
	if (count != 1) croak("C::Blocks expected one return value from dl_load_file but got %d\n", count);
	void * to_return = INT2PTR(void*, POPi);
	
	PUTBACK;
	FREETMPS;
	LEAVE;
	
	return to_return;
}

/***************************/
/**** Testing Functions ****/
/***************************/

char * _c_blocks_get_msg() {
	dTHX;
	SV * msg_SV = get_sv("C::Blocks::_msg", 0);
	return SvPVbyte_nolen(msg_SV);
}
void _c_blocks_send_msg(char * msg) {
	dTHX;
	SV * msg_SV = get_sv("C::Blocks::_msg", 0);
	sv_setpv(msg_SV, msg);
}
void _c_blocks_send_bytes(char * msg, int bytes) {
	dTHX;
	SV * msg_SV = get_sv("C::Blocks::_msg", 0);
	sv_setpvn(msg_SV, msg, bytes);
}

/*****************************************/
/**** Extended symbol table callbacks ****/
/*****************************************/

TokenSym_p my_symtab_lookup_by_name(char * name, int len, void * data, extended_symtab_p* containing_symtab) {
	/* Unpack the callback data */
	extended_symtab_callback_data * callback_data = (extended_symtab_callback_data*)data;
	
	/* In all likelihood, name will *NOT* be null terminated */
	char name_to_find[len + 1];
	strncpy(name_to_find, name, len);
	name_to_find[len] = '\0';
	
	/* Run through all of the available extended symbol tables and look for this
	 * identifier. */
	int i;
	for (i = callback_data->N_tables - 1; i >= 0; i--) {
		extended_symtab_p my_symtab
			= callback_data->available_extended_symtabs[i].exsymtab;
		TokenSym_p ts = tcc_get_extended_tokensym(my_symtab, name_to_find);
		if (ts != NULL) {
			*containing_symtab = my_symtab;
			return ts;
		}
	}
	
	return NULL;
}

void my_symtab_sym_used(char * name, int len, void * data) {
	/* Unpack the callback data */
	extended_symtab_callback_data * callback_data = (extended_symtab_callback_data*)data;
	
	/* Name *IS* null terminated */
	
	/* Run through all of the available extended symbol tables and look for this
	 * identifier. If found, add the symbol to the state. */
	int i;
	void * pointer = NULL;
	for (i = callback_data->N_tables - 1; i >= 0; i--) {
		available_extended_symtab lookup_data
			= callback_data->available_extended_symtabs[i];
		
		/* Scan the dlls first */
		void ** curr_dll = lookup_data.dlls;
		if (curr_dll != NULL) {
			while (*curr_dll != NULL) {
				pointer = dynaloader_get_symbol(
					C_BLOCKS_CALLBACK_MY_PERL(callback_data) *curr_dll, name);
				if (pointer) break;
				curr_dll++;
			}
		}
		
		/* If we didn't find it, check if it's in the exsymtab */
		if (pointer == NULL) {
			pointer = tcc_get_extended_symbol(lookup_data.exsymtab, name);
		}
		
		/* found it? Then we're done */
		if (pointer != NULL) {
			tcc_add_symbol(callback_data->state, name, pointer);

lib/C/Blocks.xs  view on Meta::CPAN

	 * already initialized. */
	GV * glob = (GV*)HeVAL(entry);
	if (isGV(glob)) {
		my_warnif(aTHX_ "import", sv_2mortal(newSVpvf("Could not inject 'import' "
			"into package %s: 'import' method already found",
			SvPVbyte_nolen(PL_curstname))));
		SvREFCNT_dec(name);
		return;
	}
	
	/* initialize the glob */
	SvREFCNT_inc(glob);
	gv_init(glob, PL_curstash, "import", 6, 1);
	if (HeVAL(entry)) {
		SvREFCNT_dec(HeVAL(entry));
	}
	HeVAL(entry) = (SV*)glob;
	
	/* Add the method to the symbol table entry. See Package::Stash::XS
	 * GvSetCV preprocessor macro (specifically taken from v0.28) */
	SvREFCNT_dec(GvCV(glob));
	GvCV_set(glob, import_method_to_inject);
	GvIMPORTED_CV_on(glob);
	GvASSUMECV_on(glob);
	GvCVGEN(glob) = 0;
	mro_method_changed_in(GvSTASH(glob));

	SvREFCNT_dec(name);
	return;

fail:
	if (name != NULL) SvREFCNT_dec(name);
	warn("Internal error while injecting 'import' into package %s: %s",
		SvPVbyte_nolen(PL_curstname), warn_message);
}

void setup_compiler (pTHX_ TCCState * state, c_blocks_data * data) {
	/* Get and reset the compiler options */
	SV * compiler_options = get_sv("C::Blocks::compiler_options", 0);
	if (SvPOK(compiler_options)) tcc_set_options(state, SvPVbyte_nolen(compiler_options));
	SvSetMagicSV(compiler_options, get_sv("C::Blocks::default_compiler_options", 0));
	
	/* Ensure output goes to memory */
	tcc_set_output_type(state, TCC_OUTPUT_MEMORY);
	
	/* Set the error function to write to the error message SV */
	tcc_set_error_func(state, data->error_msg_sv, my_tcc_error_func);
}

void execute_compiler (pTHX_ TCCState * state, c_blocks_data * data, int keyword_type) {
	int len = (int)(data->end - PL_bufptr);
	
	/* Set the extended callback handling */
	extended_symtab_callback_data callback_data = { state, aTHX_ NULL, 0 };
	
	/* Set the extended symbol table lists if they exist */
	if (SvPOK(data->exsymtabs) && SvCUR(data->exsymtabs)) {
		callback_data.N_tables = SvCUR(data->exsymtabs) / sizeof(available_extended_symtab);
		callback_data.available_extended_symtabs = (available_extended_symtab*) SvPV_nolen(data->exsymtabs);
	}
	tcc_set_extended_symtab_callbacks(state, &my_symtab_lookup_by_name,
		&my_symtab_sym_used, &my_prep_table, &callback_data);
	
	/* set the block function's argument, if any */
	if (keyword_type == IS_CBLOCK) {
		/* If this is a block, we need to define C_BLOCKS_THX_DECL.
		 * This will be based on whether tTHX is available or not. */
		#ifdef PERL_IMPLICIT_CONTEXT
			void * return_value_ignored;
			if (my_symtab_lookup_by_name("aTHX", 4, &callback_data, (void*) &return_value_ignored))
				tcc_define_symbol(state, "C_BLOCKS_THX_DECL", "PerlInterpreter * my_perl");
			else
				tcc_define_symbol(state, "C_BLOCKS_THX_DECL", "void * my_perl_NOT_USED");
		#else
			tcc_define_symbol(state, "C_BLOCKS_THX_DECL", "");
		#endif
	}
	
	/* compile the code, which is (by this time) stored entirely in main */
	STRLEN main_len;
	char * to_compile = SvPVbyte(data->code_main, main_len);
	tcc_compile_string_ex(state, to_compile, main_len,
		CopFILE(PL_curcop), CopLINE(PL_curcop));
	
	/* Handle any compilation errors */
	if (SvPOK(data->error_msg_sv)) {
		/* rewrite implicit function declarations as errors */
		char * loc;
		while(loc = strstr(SvPV_nolen(data->error_msg_sv),
			"warning: implicit declaration of function")
		) {
			/* replace "warning: implicit declaration of" with an error */
			sv_insert(data->error_msg_sv, loc - SvPV_nolen(data->error_msg_sv),
				32, "error: undeclared", 17);
		}
		/* Look for errors and croak */
		if (strstr(SvPV_nolen(data->error_msg_sv), "error")) {
			croak("C::Blocks compiler error:\n%s", SvPV_nolen(data->error_msg_sv));
		}
		
		/* Otherwise, report and clear the compiler warnings */
		my_warnif(aTHX_ "compiler", sv_2mortal(newSVsv(data->error_msg_sv)));
		SvPOK_off(data->error_msg_sv);
	}
}

OP * build_op(pTHX_ TCCState * state, int keyword_type) {
	/* build a null op if not creating a cblock */
	if (keyword_type != IS_CBLOCK) return newOP(OP_NULL, 0);
	
	/* get the function pointer for the block */
	IV pointer_IV = PTR2IV(tcc_get_symbol(state, "op_func"));
	if (pointer_IV == 0) {
		croak("C::Blocks internal error: got null pointer for op function!");
	}
	
	/* Store the address of the function pointer on the stack */
	OP * o = newUNOP(OP_RAND, 0, newSVOP(OP_CONST, 0, newSViv(pointer_IV)));
	
	/* Create an op that pops the address off the stack and invokes it */
	o->op_ppaddr = Perl_tcc_pp;



( run in 1.792 second using v1.01-cache-2.11-cpan-437f7b0c052 )