⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlembed.pod

📁 MSYS在windows下模拟了一个类unix的终端
💻 POD
📖 第 1 页 / 共 3 页
字号:
The I<eval_sv()> function lets us evaluate strings of Perl code, so we candefine some functions that use it to "specialize" in matches andsubstitutions: I<match()>, I<substitute()>, and I<matches()>.   I32 match(SV *string, char *pattern);Given a string and a pattern (e.g., C<m/clasp/> or C</\b\w*\b/>, whichin your C program might appear as "/\\b\\w*\\b/"), match()returns 1 if the string matches the pattern and 0 otherwise.   int substitute(SV **string, char *pattern);Given a pointer to an C<SV> and an C<=~> operation (e.g.,C<s/bob/robert/g> or C<tr[A-Z][a-z]>), substitute() modifies the stringwithin the C<AV> at according to the operation, returning the number of substitutionsmade.   int matches(SV *string, char *pattern, AV **matches);Given an C<SV>, a pattern, and a pointer to an empty C<AV>,matches() evaluates C<$string =~ $pattern> in a list context, andfills in I<matches> with the array elements, returning the number of matches found.Here's a sample program, I<match.c>, that uses all three (long lines havebeen wrapped here): #include <EXTERN.h> #include <perl.h> /** my_eval_sv(code, error_check) ** kinda like eval_sv(),  ** but we pop the return value off the stack  **/ SV* my_eval_sv(SV *sv, I32 croak_on_error) {     dSP;     SV* retval;     STRLEN n_a;     PUSHMARK(SP);     eval_sv(sv, G_SCALAR);     SPAGAIN;     retval = POPs;     PUTBACK;     if (croak_on_error && SvTRUE(ERRSV)) 	croak(SvPVx(ERRSV, n_a));     return retval; } /** match(string, pattern) ** ** Used for matches in a scalar context. ** ** Returns 1 if the match was successful; 0 otherwise. **/ I32 match(SV *string, char *pattern) {     SV *command = NEWSV(1099, 0), *retval;     STRLEN n_a;     sv_setpvf(command, "my $string = '%s'; $string =~ %s", 	      SvPV(string,n_a), pattern);     retval = my_eval_sv(command, TRUE);     SvREFCNT_dec(command);     return SvIV(retval); } /** substitute(string, pattern) ** ** Used for =~ operations that modify their left-hand side (s/// and tr///) ** ** Returns the number of successful matches, and ** modifies the input string if there were any. **/ I32 substitute(SV **string, char *pattern) {     SV *command = NEWSV(1099, 0), *retval;     STRLEN n_a;     sv_setpvf(command, "$string = '%s'; ($string =~ %s)", 	      SvPV(*string,n_a), pattern);     retval = my_eval_sv(command, TRUE);     SvREFCNT_dec(command);     *string = get_sv("string", FALSE);     return SvIV(retval); } /** matches(string, pattern, matches) ** ** Used for matches in a list context. ** ** Returns the number of matches, ** and fills in **matches with the matching substrings **/ I32 matches(SV *string, char *pattern, AV **match_list) {     SV *command = NEWSV(1099, 0);     I32 num_matches;     STRLEN n_a;     sv_setpvf(command, "my $string = '%s'; @array = ($string =~ %s)", 	      SvPV(string,n_a), pattern);     my_eval_sv(command, TRUE);     SvREFCNT_dec(command);     *match_list = get_av("array", FALSE);     num_matches = av_len(*match_list) + 1; /** assume $[ is 0 **/     return num_matches; } main (int argc, char **argv, char **env) {     PerlInterpreter *my_perl = perl_alloc();     char *embedding[] = { "", "-e", "0" };     AV *match_list;     I32 num_matches, i;     SV *text = NEWSV(1099,0);     STRLEN n_a;     perl_construct(my_perl);     perl_parse(my_perl, NULL, 3, embedding, NULL);     sv_setpv(text, "When he is at a convenience store and the bill comes to some amount like 76 cents, Maynard is aware that there is something he *should* do, something that will enable him to get back a quarter, but he has no idea *what*.  He fumbles through his red squeezey changepurse and gives the boy three extra pennies with his dollar, hoping that he might luck into the correct amount.  The boy gives him back two of his own pennies and then the big shiny quarter that is his prize. -RICHH");     if (match(text, "m/quarter/")) /** Does text contain 'quarter'? **/ 	printf("match: Text contains the word 'quarter'.\n\n");     else 	printf("match: Text doesn't contain the word 'quarter'.\n\n");     if (match(text, "m/eighth/")) /** Does text contain 'eighth'? **/ 	printf("match: Text contains the word 'eighth'.\n\n");     else 	printf("match: Text doesn't contain the word 'eighth'.\n\n");     /** Match all occurrences of /wi../ **/     num_matches = matches(text, "m/(wi..)/g", &match_list);     printf("matches: m/(wi..)/g found %d matches...\n", num_matches);     for (i = 0; i < num_matches; i++) 	printf("match: %s\n", SvPV(*av_fetch(match_list, i, FALSE),n_a));     printf("\n");     /** Remove all vowels from text **/     num_matches = substitute(&text, "s/[aeiou]//gi");     if (num_matches) { 	printf("substitute: s/[aeiou]//gi...%d substitutions made.\n", 	       num_matches); 	printf("Now text is: %s\n\n", SvPV(text,n_a));     }     /** Attempt a substitution **/     if (!substitute(&text, "s/Perl/C/")) { 	printf("substitute: s/Perl/C...No substitution made.\n\n");     }     SvREFCNT_dec(text);     PL_perl_destruct_level = 1;     perl_destruct(my_perl);     perl_free(my_perl); }which produces the output (again, long lines have been wrapped here)   match: Text contains the word 'quarter'.   match: Text doesn't contain the word 'eighth'.   matches: m/(wi..)/g found 2 matches...   match: will   match: with   substitute: s/[aeiou]//gi...139 substitutions made.   Now text is: Whn h s t  cnvnnc str nd th bll cms t sm mnt lk 76 cnts,   Mynrd s wr tht thr s smthng h *shld* d, smthng tht wll nbl hm t gt bck   qrtr, bt h hs n d *wht*.  H fmbls thrgh hs rd sqzy chngprs nd gvs th by   thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct mnt.  Th by gvs   hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s hs prz. -RCHH   substitute: s/Perl/C...No substitution made.=head2 Fiddling with the Perl stack from your C programWhen trying to explain stacks, most computer science textbooks mumblesomething about spring-loaded columns of cafeteria plates: the lastthing you pushed on the stack is the first thing you pop off.  That'lldo for our purposes: your C program will push some arguments onto "the Perlstack", shut its eyes while some magic happens, and then pop theresults--the return value of your Perl subroutine--off the stack.First you'll need to know how to convert between C types and Perltypes, with newSViv() and sv_setnv() and newAV() and all theirfriends.  They're described in L<perlguts> and L<perlapi>.Then you'll need to know how to manipulate the Perl stack.  That'sdescribed in L<perlcall>.Once you've understood those, embedding Perl in C is easy.Because C has no builtin function for integer exponentiation, let'smake Perl's ** operator available to it (this is less useful than itsounds, because Perl implements ** with C's I<pow()> function).  FirstI'll create a stub exponentiation function in I<power.pl>:    sub expo {        my ($a, $b) = @_;        return $a ** $b;    }Now I'll create a C program, I<power.c>, with a functionI<PerlPower()> that contains all the perlguts necessary to push thetwo arguments into I<expo()> and to pop the return value out.  Take adeep breath...    #include <EXTERN.h>    #include <perl.h>    static PerlInterpreter *my_perl;    static void    PerlPower(int a, int b)    {      dSP;                            /* initialize stack pointer      */      ENTER;                          /* everything created after here */      SAVETMPS;                       /* ...is a temporary variable.   */      PUSHMARK(SP);                   /* remember the stack pointer    */      XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack  */      XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack  */      PUTBACK;                      /* make local stack pointer global */      call_pv("expo", G_SCALAR);      /* call the function             */      SPAGAIN;                        /* refresh stack pointer         */                                    /* pop the return value from stack */      printf ("%d to the %dth power is %d.\n", a, b, POPi);      PUTBACK;      FREETMPS;                       /* free that return value        */      LEAVE;                       /* ...and the XPUSHed "mortal" args.*/    }    int main (int argc, char **argv, char **env)    {      char *my_argv[] = { "", "power.pl" };      my_perl = perl_alloc();      perl_construct( my_perl );      perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL);      perl_run(my_perl);      PerlPower(3, 4);                      /*** Compute 3 ** 4 ***/      perl_destruct(my_perl);      perl_free(my_perl);    }Compile and run:    % cc -o power power.c `perl -MExtUtils::Embed -e ccopts -e ldopts`    % power    3 to the 4th power is 81.=head2 Maintaining a persistent interpreterWhen developing interactive and/or potentially long-runningapplications, it's a good idea to maintain a persistent interpreterrather than allocating and constructing a new interpreter multipletimes.  The major reason is speed: since Perl will only be loaded intomemory once.However, you have to be more cautious with namespace and variablescoping when using a persistent interpreter.  In previous exampleswe've been using global variables in the default package C<main>.  Weknew exactly what code would be run, and assumed we could avoidvariable collisions and outrageous symbol table growth.Let's say your application is a server that will occasionally run Perlcode from some arbitrary file.  Your server has no way of knowing whatcode it's going to run.  Very dangerous.If the file is pulled in by C<perl_parse()>, compiled into a newlyconstructed interpreter, and subsequently cleaned out withC<perl_destruct()> afterwards, you're shielded from most namespacetroubles.One way to avoid namespace collisions in this scenario is to translatethe filename into a guaranteed-unique package name, and then compilethe code into that package using L<perlfunc/eval>.  In the examplebelow, each file will only be compiled once.  Or, the applicationmight choose to clean out the symbol table associated with the fileafter it's no longer needed.  Using L<perlapi/call_argv>, We'llcall the subroutine C<Embed::Persistent::eval_file> which lives in thefile C<persistent.pl> and pass the filename and boolean cleanup/cacheflag as arguments.Note that the process will continue to grow for each file that ituses.  In addition, there might be C<AUTOLOAD>ed subroutines and otherconditions that cause Perl's symbol table to grow.  You might want toadd some logic that keeps track of the process size, or restartsitself after a certain number of requests, to ensure that memoryconsumption is minimized.  You'll also want to scope your variableswith L<perlfunc/my> whenever possible. package Embed::Persistent; #persistent.pl use strict; our %Cache; use Symbol qw(delete_package); sub valid_package_name {     my($string) = @_;     $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;     # second pass only for words starting with a digit     $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;     # Dress it up as a real package name     $string =~ s|/|::|g;     return "Embed" . $string; } sub eval_file {     my($filename, $delete) = @_;     my $package = valid_package_name($filename);     my $mtime = -M $filename;     if(defined $Cache{$package}{mtime}        &&        $Cache{$package}{mtime} <= $mtime)     {        # we have compiled this subroutine already,        # it has not been updated on disk, nothing left to do        print STDERR "already compiled $package->handler\n";     }     else {        local *FH;        open FH, $filename or die "open '$filename' $!";        local($/) = undef;        my $sub = <FH>;        close FH;        #wrap the code into a subroutine inside our unique package        my $eval = qq{package $package; sub handler { $sub; }};        {            # hide our variables within this block

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -