- 论坛徽章:
- 0
|
名称
如何在C程序中嵌入Perl
描述
前言
你想不想
在Perl中使用C?
请阅读 perlxstut手册、perlxs手册、h2xs和 perlguts手册。
在Perl中使用一个Unix程序?
阅读有关反引号` 、system 和exec的部分,它们在 perlfunc手册中。
在Perl中使用Perl?
阅读有关do、eval、require 和 use的手册.
在C中使用C?
重新考虑你的设计。
在C中使用Perl?
继续……
编译你的C程序
如果你编译本文档中的脚本有困难。那么你不是一个人在战斗。记住重要原则: 以编译你的perl的方式,编译你的程序(不好意思)
并且,每一个使用了Perl的C程序都必须连接 perl 库. 你问,那是什么?Perl本身就是用C写的。Perl库是编译过的用来创建Perl可执行程序的C程序集合 (/usr/bin/perl或者类似的)。(结论:你不能在没有编译过或者正确安装过Perl的系统中编译嵌入了Perl的C程序。不正确安装指,只是复制了Perl的二进制可执行文件而没有复制perl的库目录。)
当你在C中使用Perl时, 你的C程序将要--通常--需要创建、执行,然后销毁一个 Perl解释器
如果你的Perl烤备足够新到包含本文档 (版本5.002或者更新), 则Perl库 (以及你将需要的EXTERN.h 和 perl.h) 将会在类似这样的目录中:
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能就直接是
/usr/local/lib/perl5/your_architecture_here/CORE
或者可能类似
/usr/opt/perl5/CORE
执行这个表达式可以定位这个目录:
perl -MConfig -e 'print $Config{archlib}'
这是如何编译下节的示例代码:往你的C程序中墙加一个Perl解释器的语句,在我的linux机器上是这样:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include
-I/usr/local/lib/perl5/i586-linux/5.003/CORE
-I/usr/local/lib/perl5/i586-linux/5.003/CORE
-o interp interp.c -lperl -lm
(那些是一行。) 在我跑着老版本perl 5.003_05的DEC Alpha机器上, 有一点点儿不一样:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include
-I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE
-L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib
-D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
你如何找出需要填加什么?如果你的Perl版本高于5.001, 执行 perl -V 命令,注意一下它的有关``cc'' 和 ``ccflags''的信息。
你将不得不根据你的系统选择适当的编译器。 (cc,gcc,等等。) : perl -MConfig -e 'print $Config{cc}' 将告诉你用什么。
你还得根据你的系统选择正确的Perl库目录 (/usr/local/lib/...) 如果你的编译器抱怨有函数未定义,或者它不能定位 -lperl,则你需要用-L手动指定库文件路径。如果它抱怨找不到EXTERN.h 和 perl.h,你需要用-I手动指定头文件路径。
你可能还需要如法增加其它库哪些?可能包括这行指令打印出的这些:
perl -MConfig -e 'print $Config{archlib}'
如果你的perl配置安装无误,则模块ExtUtils::Embed将为你检测出你需要的所有信息。
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
如果ExtUtils::Embed不包含在你的perl发行版中, 你可以从http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/.下载它 (如果本文档来自你的perl发行版,则你已经安装了perl 5.004或者更高的版本,并且你肯定有这个模块)
CPAN上的ExtUtils::Embed,包括了有关本文档的所有的源码、测试以及其它对你有用的示例程序。
往你的C程序中增加一个Perl解释器
通常, perl (C源程序) 是一个嵌入Perl(语言)的好例子,所以我将示范一个miniperlmain.c。当然,它不太标准,也不太精巧。
#include <EXTERN.h> /* from the Perl distribution */
#include <EXTERN.h> /* from the Perl distribution */
static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
int main(int argc, char **argv, char **env)
{
my_perl = perl_alloc();
perl_construct(my_perl);
perl_parse(my_perl, NULL, argc, argv, (char **)NULL);
perl_run(my_perl);
perl_destruct(my_perl);
perl_free(my_perl);
}
注意我们没有使用env指针。通常做为perl_parse的最后一个选项, env参数为NULL,代表使用当前的环境变量。
现在编译它 (我将叫它 interp.c)为可执行文件:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
经过成功的编译以后, 你将可以像使用perl一样地使用interp。
% interp
print "Pretty Good Perl \n";
print "10890 - 9801 is ", 10890 - 9801;
<CTRL-D>
Pretty Good Perl
10890 - 9801 is 1089
或者
% interp -e 'printf("%x", 3735928559)'
deadbeef
你也可以通过在调用perl_fun以前替换argv[1],在C程序里从一个文件中读取然后执行Perl代码。
在你的C程序中调用一个Perl子程序
为了调用独立的Perl子程序,你可以使用任何<al>perlcall手册</al>中的perl_call_*类型的函数。在此例中,我们将使用perl_call_argv。
它们将在下面这个我叫做showtime.c的程序中中展现。
#include <EXTERN.h>
#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env)
{
char *args[] = { NULL };
my_perl = perl_alloc();
perl_construct(my_perl);
perl_parse(my_perl, NULL, argc, argv, (char **)NULL);
/*** skipping perl_run() ***/
perl_call_argv("showtime", G_DISCARD | G_NOARGS, args);
perl_destruct(my_perl);
perl_free(my_perl);
}
showtime是一个Perl子程序,它没有参数。 (它是 G_NOARGS) 并且我将忽略它的返回值 (它是G_DISCARD). 那些标记,以及其它一些标记,在perlcall手册中。
我将在文件<el>showtime.pl</el>中定义showtime函数:
print "I shan't be printed.";
sub showtime {
print time;
}
足够简单。现在编译并运行:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% showtime showtime.pl
818284590
返回从1970年1月1日 (Unix epoch开始时间)到现在我正在执行程序语句的时间。
在这一部分,我们不需要调用perl_run,但是通常好的编程习惯来保证正确的使用库是好的,包括对所有的对象调用 DESTROY 方法以及块的END {}。
如果你想传递参数给Perl函数,你可以填加以NULL结尾的args表给perl_call_argv。为了其它数据类型或者测试返回值,你将需要操作Perl的栈。那将在本文档最后的章节进行讨论: 在你的C程序中操作Perl的栈。
在你的C程序中执行一个Perl表达式
Perl提供了两个API函数来执行Perl代码片断。它们是perl_eval_sv 和 perl_eval_pv。
经常的情况是,你只需要在程序中执行一块的Perl代码。它可以如你所愿的长:它可以包括 use、require和 do 用来包含其它的外部Perl文件。
perl_eval_pv 可以让我执行单独的Perl语句,然后把执行结果变量返回成C的形式。下面的程序 string.c,执行三个Perl语句, 从第一个取得int,从第二个取回float, 从第三个取回char *。
#include <EXTERN.h>
#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env)
{
STRLEN n_a;
char *embedding[] = { "", "-e", "0" };
my_perl = perl_alloc();
perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL);
perl_run(my_perl);
/** Treat $a as an integer **/
perl_eval_pv("$a = 3; $a **= 2", TRUE);
printf("a = %d\n", SvIV(perl_get_sv("a", FALSE)));
/** Treat $a as a float **/
perl_eval_pv("$a = 3; $a **= 2", TRUE);
printf("a = %f\n", SvNV(perl_get_sv("a", FALSE)));
/** Treat $a as a float **/
perl_eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);", TRUE);
printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), n_a));
perl_destruct(my_perl);
perl_free(my_perl);
}
所有这些名字中含有 sv 的这些怪函数都帮助把Perl的标量返回成C的类型。它们在 perlguts手册里有描述。
如果你编译并运行string.c,你将看到 SvIV()创建整数,SvNV()创建浮点数,以及SvPV()创建一个字符串:
a = 9
a = 9
a = Just Another Perl Hacker
在上例中,我们创建了一个全局的变量来保存我们表达式执行的结果。在很多情形下,通过perl_eval_pv()的执行结果来取回返回值,也不错。如:
...
STRLEN n_a;
SV *val = perl_eval_pv("reverse 'rekcaH lreP rehtonA tsuJ'", TRUE);
printf("%s\n", SvPV(val,n_a));
...
这种方法,我们通过不创建全局变量以及简化我们的化码,避免了名字空间污染。
在你的C程序中,提升正则匹配和替换的效率
函数perl_eval_sv() 让我们可以从Perl代码取得字符串,所以我们可以定义一些函数用来指定匹配或者替换: match(),substitute()和matches()。
I32 match(SV *string, char *pattern);
给定一个字符串和一个模式 (比如, m/clasp/或/\b\w*\b/, 在C程序中可能会形如``/\\b\\w*\\b/''), 如果匹配,match() 就返回1,否则返回0。
int substitute(SV **string, char *pattern);
给SV赋一个指针和一个操作=~(比如, s/bob/robert/g或者tr[A-Z][a-z]), substitute()根据表达式,改变AV中的值,返回改变了的子串个数。
int matches(SV *string, char *pattern, AV **matches);
给定一个字符串SV,一个正则表达式和一个指向为空的AV的指针, matches()在一个列表上下文中执行$string =~ $pattern,用列表元素填充matches,返回匹配的元素个数。
这有一个程序示例,match.c,使用了这三种操作 (过长的行被换行了):
#include <EXTERN.h>
#include <perl.h>
/** my_perl_eval_sv(code, error_check)
** kinda like perl_eval_sv(),
** but we pop the return value off the stack
**/
SV* my_perl_eval_sv(SV *sv, I32 croak_on_error)
{
dSP;
SV* retval;
STRLEN n_a;
PUSHMARK(SP);
perl_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_perl_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.
**/
int substitute(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_perl_eval_sv(command, TRUE);
SvREFCNT_dec(command);
*string = perl_get_sv("string", FALSE);
return SvIV(retval);
}
/** matches(string, pattern, matches)
**
** Used for matches in an array 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'; $string =~ %s",
SvPV(string,n_a), pattern);
my_perl_eval_sv(command, TRUE);
SvREFCNT_dec(command);
*match_list = perl_get_av("array", FALSE);
num_matches = av_len(*match_list) + 1; /** assume $[ is 0 **/
return num_matches;
}
int 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 contains the word 'quarter'.\n\n");
if (match(text, "m/eighth/")) /** Does text contain 'eighth'?**/
printf("match: Text contains the word 'quarter'.\n\n");
else
printf("match: Text contains the word 'quarter'.\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);
}
程序输出
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.
[ 本帖最后由 naihe2010 于 2009-12-15 09:01 编辑 ] |
|