810 likes | 938 Views
Join us for an engaging London Perl Workshop on December 4th, designed for those who know some Perl and have a little familiarity with C but are apprehensive about diving deeper. Led by Alex Gough, this hands-on workshop will focus on advanced Perl integration with C, covering stack management, scalar functions, and configuration parsing. Come prepared to expand your skills, tackle practical challenges, and learn how to optimize your programs by combining Perl's strengths with C's efficiency.
E N D
Running Away to C XS – More faff than fear London Perl Workshop – Dec 04Alex Goughalex@earth.li
You’re here because… • You know some Perl • You recognise some C • But fear it a little • You’re an evil brigand • You know it’s warmer in here
Stack Functions dSP; Declare stack varsPUSHMARK(SP) start of argumentsEXTEND make spaceXPUSHstuff push stuff, making spacePUSHstuff push stuff, need spacePUTBACK done adding arguments . . . Make a call . . .SPAGAIN refresh our stackret = POPstuff grab stuff from stackPUTBACK we’re done grabbing stuff
Scope • Start and end a scope • Tell Perl we’re creating temporary stuff • Tell Perl when we’re done with it
Scope Functions ENTER Opening brace {SAVETMPS start making temps . . . Call function . . .FREETMPS done with my temps LEAVE Closing brace }
Scalars $thing = 12 12.3 “harry” \ @array \ %hash \ $thing bless(\$object) *FILE qr{.*} {code}
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions I SV* get_sv(char* name, I32 create)SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho”IV intv = SvIV(sv)NV fltv = SvNV(sv)char* foo = SvPV(sv)sv_setpv(sv, “honk”); sv_setiv(sv, 12)
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }”I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv)SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len . . . }
A Puzzle • Find the longest set of three words that when listed form three letter words down all columns. padsareatend
Array Functions AV *av = get_av(“ARGV”, TRUE)SV** ret = av_store(av, 12, sv) SV** ret = av_fetch(av, 12, sv, lval) SV* sv = av_pop(av) av_shift(av) void av_push(av, sv) av_unshift(av, 3) [3 undefs] I32 len = av_len(av)
Hash Functions HV *hv = get_hv(“hash”, TRUE) BOOL hv_exists(hv, “key”, 3) SV** sv = hv_fetch(hv, “key”, 3, lval) SV** sv = hv_store(hv, “key”, 3, sv, 0) Or you can play with HE (Hash Entries)
Function Functions CV* cv = get_cv(“subname”, TRUE) call_pv(“subname”, context) call_sv(sv, context) Context: G_VOID } G_SCALAR } context G_ARRAY } G_NOARGS no arguments G_DISCARD “no return values” G_EVAL catch die in eval { } G_KEEPERR .. and be nice to $@
Objects, globs, whatever • Maybe you’ll need them • Maybe you won’t • See perlapi, perlcall, perlguts
Embedding • You have some C • You want to add a bit of Perl • Config file dabbling • Scripting engine • Hook into Efficient / Legacy code • Prototype features
Config Parsing • Flexible configuration framework • C side factored into:void get_config(char* key, char* dst, int len); • Let Perl provide the intelligence • (We provide the glue)
Perl • A big C program • A really tiny main() • Constructs an intepreter • Tells it to parse your script • Tells it to run your script • Jumps between C and Perl a lot • Cleans up (sort of) • Exits
Config Parsing use strict; my %config = (); sub init { my($file) = @_; … # fill in %config } sub get_value { my($key) = @_; return $config{$key} || “”; }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(. . .); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL;ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP);XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key)));PUTBACK;call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}
void get_config(char* key, char* dst) {dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN;ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE;}