5 xsubpp - compiler to convert Perl XS code into C code
9 B<xsubpp> [B<-C++>] [B<-except>] [B<-typemap typemap>] file.xs
13 I<xsubpp> will compile XS code into C code by embedding the constructs
14 necessary to let C functions manipulate Perl values and creates the glue
15 necessary to let Perl access those functions. The compiler uses typemaps to
16 determine how to map C function parameters and variables to Perl values.
18 The compiler will search for typemap files called I<typemap>. It will use
19 the following search path to find default typemaps, with the rightmost
20 typemap taking precedence.
22 ../../../typemap:../../typemap:../typemap:typemap
30 Adds ``extern "C"'' to the C code.
35 Adds exception handling stubs to the C code.
37 =item B<-typemap typemap>
39 Indicates that a user-supplied typemap should take precedence over the
40 default typemaps. This option may be used multiple times, with the last
41 typemap having the highest precedence.
47 No environment variables are used.
53 =head1 MODIFICATION HISTORY
57 I<xsubpp> as released with Perl 5.000
61 I<xsubpp> as released with Perl 5.001
65 Changes by Paul Marquess <pmarquess@bfsec.bt.co.uk>, 22 May 1995.
71 Added I<xsubpp> version number for the first time. As previous releases
72 of I<xsubpp> did not have a formal version number, a numbering scheme
73 has been applied retrospectively.
77 If OUTPUT: is being used to specify output parameters and RETVAL is
78 also to be returned, it is now no longer necessary for the user to
79 ensure that RETVAL is specified last.
83 The I<xsubpp> version number, the .xs filename and a time stamp are
84 written to the generated .c file as a comment.
88 When I<xsubpp> is parsing the definition of both the input parameters
89 and the OUTPUT parameters, any duplicate definitions will be noted and
94 I<xsubpp> is slightly more forgiving with extra whitespace.
100 Changes by Paul Marquess <pmarquess@bfsec.bt.co.uk>, 23 May 1995.
106 More whitespace restrictions have been relaxed. In particular some
107 cases where a tab character was used to delimit fields has been
108 removed. In these cases any whitespace will now suffice.
110 The specific places where changes have been made are in the TYPEMAP
111 section of a typemap file and the input and OUTPUT: parameter
112 declarations sections in a .xs file.
116 More error checking added.
118 Before processing each typemap file I<xsubpp> now checks that it is a
119 text file. If not an warning will be displayed. In addition, a warning
120 will be displayed if it is not possible to open the typemap file.
122 In the TYPEMAP section of a typemap file, an error will be raised if
123 the line does not have 2 columns.
125 When parsing input parameter declarations check that there is at least
126 a type and name pair.
132 When parsing the OUTPUT arguments check that they are all present in
133 the corresponding input argument definitions.
137 Changes by Paul Marquess <pmarquess@bfsec.bt.co.uk>, 1 June 1995.
139 Started tidy up to allow clean run using C<-w> flag.
141 Added some more error checking.
143 The CASE: functionality now works.
147 Changes by Paul Marquess <pmarquess@bfsec.bt.co.uk>, 3 June 1995.
149 Added some more error checking.
153 Changes by Paul Marquess <pmarquess@bfsec.bt.co.uk>, 5 June 1995.
155 When an error or warning message is printed C<xsubpp> will now attempt
156 to identify the exact line in the C<.xs> file where the fault occurs.
157 This can be achieved in the majority of cases.
168 $XSUBPP_version = "1.7" ;
170 $usage = "Usage: xsubpp [-C++] [-except] [-typemap typemap] file.xs\n";
172 SWITCH: while ($ARGV[0] =~ s/^-//) {
174 $spat = shift, next SWITCH if $flag eq 's';
175 $cplusplus = 1, next SWITCH if $flag eq 'C++';
176 $except = 1, next SWITCH if $flag eq 'except';
177 push(@tm,shift), next SWITCH if $flag eq 'typemap';
180 @ARGV == 1 or die $usage;
182 # Check for error message from VMS
183 if ($pwd =~ /unrecognized command verb/) { $Is_VMS = 1; $pwd = $ENV{DEFAULT} }
184 ($dir, $filename) = $ARGV[0] =~ m#(.*)/(.*)#
185 or ($dir, $filename) = $ARGV[0] =~ m#(.*[>\]])(.*)#
186 or ($dir, $filename) = ('.', $ARGV[0]);
191 $_[0] =~ s/^\s+|\s+$//go ;
198 # rationalise any '*' by joining them into bunches and removing whitespace
201 # change multiple whitespace into a single space
204 # trim leading & trailing whitespace
210 $typemap = shift @ARGV;
211 foreach $typemap (@tm) {
212 die "Can't find $typemap in $pwd\n" unless -r $typemap;
214 unshift @tm, qw(../../../../lib/ExtUtils/typemap ../../../lib/ExtUtils/typemap
215 ../../lib/ExtUtils/typemap ../../../typemap ../../typemap
217 foreach $typemap (@tm) {
218 next unless -e $typemap ;
219 # skip directories, binary files etc.
220 warn("Warning: ignoring non-text typemap file '$typemap'\n"), next
222 open(TYPEMAP, $typemap)
223 or warn ("Warning: could not open typemap file '$typemap': $!\n"), next;
229 if (/^INPUT\s*$/) { $mode = Input, next }
230 if (/^OUTPUT\s*$/) { $mode = Output, next }
231 if (/^TYPEMAP\s*$/) { $mode = Typemap, next }
232 if ($mode eq Typemap) {
236 # skip blank lines and comment lines
237 next if /^$/ or /^#/ ;
238 my @words = split (' ') ;
239 warn("Warning: File '$typemap' Line $. '$line' TYPEMAP entry needs 2 columns\n"), next
241 my $kind = pop @words ;
242 TrimWhitespace($kind) ;
243 $type_kind{TidyType("@words")} = $kind ;
245 elsif ($mode eq Input) {
251 $input_expr{$_} = '';
252 $current = \$input_expr{$_};
261 $output_expr{$_} = '';
262 $current = \$output_expr{$_};
269 foreach $key (keys %input_expr) {
270 $input_expr{$key} =~ s/\n+$//;
281 open(F, $filename) or die "cannot open $filename: $!\n";
283 # Identify the version of xsubpp used
284 $TimeStamp = localtime ;
287 * This file was generated automatically by xsubpp version $XSUBPP_version
288 * from $filename on $TimeStamp
296 last if ($Module, $foo, $Package, $foo1, $Prefix) =
297 /^MODULE\s*=\s*([\w:]+)(\s+PACKAGE\s*=\s*([\w:]+))?(\s+PREFIX\s*=\s*(\S+))?\s*$/;
307 if ($lastline ne "") {
309 /^MODULE\s*=\s*([\w:]+)(\s+PACKAGE\s*=\s*([\w:]+))?(\s+PREFIX\s*=\s*(\S+))?\s*$/) {
315 ($Module_cname = $Module) =~ s/\W/_/g;
316 ($Packid = $Package) =~ s/:/_/g;
317 $Packprefix = $Package;
318 $Packprefix .= "::" if defined $Packprefix && $Packprefix ne "";
322 !/^#[ \t]*(if|ifdef|ifndef|else|elif|endif|define|undef)\b/;
325 push(@line, $_), push(@line_no, input_line_number F) if $_ ne "";
328 push(@line, $lastline);
329 push(@line_no, $lastline_no) ;
334 !/^#[ \t]*(if|ifdef|ifndef|else|elif|endif|define|undef)\b/;
336 if (/^\S/ && @line && $line[-1] eq "") {
338 $lastline_no = input_line_number F ;
343 push(@line_no, input_line_number F) ;
346 pop(@line), pop(@line_no) while @line && $line[-1] =~ /^\s*$/;
348 $PPCODE = grep(/PPCODE:/, @line);
353 while (&fetch_para) {
354 # initialize info arrays
365 # extract return type, function name and arguments
366 $ret_type = TidyType(shift(@line));
368 if ($ret_type =~ /^BOOT:/) {
369 push (@BootCode, @line, "", "") ;
373 # a function definition needs at least 2 lines
374 blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
377 if ($ret_type =~ /^static\s+(.*)$/) {
381 $func_header = shift(@line);
382 blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
383 unless $func_header =~ /^([\w:]+)\s*\((.*)\)$/;
385 ($func_name, $orig_args) = ($1, $2) ;
386 if ($func_name =~ /(.*)::(.*)/) {
390 $Prefix = '' unless defined $Prefix ; # keep -w happy
391 ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
393 # Check for duplicate function definition
394 blurt("Error: ignoring duplicate function definition '$func_name'"), next PARAGRAPH
395 if defined $Func_name{"${Packid}_$func_name"} ;
396 $Func_name{"${Packid}_$func_name"} ++ ;
398 push(@Func_name, "${Packid}_$func_name");
399 push(@Func_pname, $pname);
400 @args = split(/\s*,\s*/, $orig_args);
401 if (defined($class)) {
402 if (defined($static)) {
403 unshift(@args, "CLASS");
404 $orig_args = "CLASS, $orig_args";
405 $orig_args =~ s/^CLASS, $/CLASS/;
408 unshift(@args, "THIS");
409 $orig_args = "THIS, $orig_args";
410 $orig_args =~ s/^THIS, $/THIS/;
413 $orig_args =~ s/"/\\"/g;
414 $min_args = $num_args = @args;
415 foreach $i (0..$num_args-1) {
416 if ($args[$i] =~ s/\.\.\.//) {
419 if ($args[$i] eq '' && $i == $num_args - 1) {
424 if ($args[$i] =~ /([^=]*\S)\s*=\s*(.*)/) {
427 $defaults{$args[$i]} = $2;
428 $defaults{$args[$i]} =~ s/"/\\"/g;
431 if (defined($class)) {
432 $func_args = join(", ", @args[1..$#args]);
434 $func_args = join(", ", @args);
436 @args_match{@args} = 1..@args;
438 # print function header
440 #XS(XS_${Packid}_$func_name)
445 $cond = qq(items < $min_args);
447 elsif ($min_args == $num_args) {
448 $cond = qq(items != $min_args);
451 $cond = qq(items < $min_args || items > $num_args);
454 print Q<<"EOF" if $except;
461 # croak("Usage: $pname($orig_args)");
465 print Q<<"EOF" if $PPCODE;
469 # Now do a block of some sort.
477 if ($line[0] =~ s/^\s*CASE\s*:\s*//) {
478 $cond = shift(@line);
479 TrimWhitespace($cond) ;
481 # Check $cond is not blank
482 blurt("Error: First CASE: needs a condition")
484 print " if ($cond)\n"
486 elsif ($cond ne '') {
487 print " else if ($cond)\n";
490 blurt ("Error: Too many CASE: statements without a condition")
510 # do initialization of input variables
518 last if /^\s*NOT_IMPLEMENTED_YET/;
519 last if /^\s*(PPCODE|CODE|OUTPUT|CLEANUP|CASE)\s*:/;
526 # remove trailing semicolon if no initialisation
527 s/\s*;+\s*$//g unless /=/ ;
529 # check for optional initialisation code
531 $var_init = $1 if s/\s*(=.*)$// ;
533 my @words = split (' ') ;
534 blurt("Error: invalid argument declaration '$line'"), next
536 my $var_name = pop @words ;
537 my $var_type = "@words" ;
539 # catch many errors similar to: SV<tab>* name
540 blurt("Error: invalid $pname argument name '$var_name' (type '$var_type')\n")
541 unless ($var_name =~ m/^&?\w+$/);
542 if ($var_name =~ /^&/) {
544 $var_addr{$var_name} = 1;
547 # Check for duplicate definitions
548 blurt ("Error: duplicate definition of argument '$var_name' ignored"), next
549 if $arg_list{$var_name} ++ ;
551 $thisdone |= $var_name eq "THIS";
552 $retvaldone |= $var_name eq "RETVAL";
553 $var_types{$var_name} = $var_type;
554 print "\t" . &map_type($var_type);
555 $var_num = $args_match{$var_name};
556 if ($var_addr{$var_name}) {
557 $func_args =~ s/\b($var_name)\b/&$1/;
559 if ($var_init !~ /^=\s*NO_INIT\s*$/) {
560 if ($var_init !~ /^\s*$/) {
561 &output_init($var_type, $var_num,
562 "$var_name $var_init");
564 # generate initialization code
565 &generate_init($var_type, $var_num, $var_name);
570 print "\t$var_name;\n";
573 if (!$thisdone && defined($class)) {
574 if (defined($static)) {
576 $var_types{"CLASS"} = "char *";
577 &generate_init("char *", 1, "CLASS");
581 $var_types{"THIS"} = "$class *";
582 &generate_init("$class *", 1, "THIS");
587 if (/^\s*NOT_IMPLEMENTED_YET/) {
588 print "\ncroak(\"$pname: not implemented yet\");\n";
590 if ($ret_type ne "void") {
591 print "\t" . &map_type($ret_type) . "\tRETVAL;\n"
593 $args_match{"RETVAL"} = 0;
594 $var_types{"RETVAL"} = $ret_type;
600 death ("PPCODE must be last thing")
601 if /^\s*(OUTPUT|CLEANUP|CASE)\s*:/;
604 print "\tPUTBACK;\n\treturn;\n";
605 } elsif (/^\s*CODE:/) {
609 last if /^\s*(OUTPUT|CLEANUP|CASE)\s*:/;
612 } elsif ($func_name eq "DESTROY") {
615 print "delete THIS;\n"
619 if ($ret_type ne "void") {
622 if (defined($static)) {
623 if ($func_name =~ /^new/) {
624 $func_name = "$class";
629 } elsif (defined($class)) {
632 if (defined($spat) && $func_name =~ /^($spat)(.*)$/) {
635 print "$func_name($func_args);\n";
636 $wantRETVAL = 1 unless $ret_type eq "void";
640 # do output variables
641 if (/^\s*OUTPUT\s*:/) {
647 last if /^\s*CLEANUP|CASE\s*:/;
650 my ($outarg, $outcode) = /^(\S+)\s*(.*)/ ;
651 if (!$gotRETVAL and $outarg eq 'RETVAL') {
652 # deal with RETVAL last
653 $RETVAL_code = $outcode ;
657 blurt ("Error: duplicate OUTPUT argument '$outarg' ignored"), next
658 if $outargs{$outarg} ++ ;
659 blurt ("Error: OUTPUT $outarg not an argument"), next
660 unless defined($args_match{$outarg});
661 blurt("Error: No input definition for OUTPUT argument '$outarg' - ignored"), next
662 unless defined $var_types{$outarg} ;
664 print "\t$outcode\n";
666 $var_num = $args_match{$outarg};
667 &generate_output($var_types{$outarg}, $var_num,
674 { print "\t$RETVAL_code\n" }
676 { &generate_output($ret_type, 0, 'RETVAL') }
680 # all OUTPUT done, so now push the return value on the stack
681 &generate_output($ret_type, 0, "RETVAL")
682 if $wantRETVAL and ! $gotRETVAL ;
685 if (/^\s*CLEANUP\s*:/) {
688 last if /^\s*CASE\s*:/;
692 # print function trailer
698 # sprintf(errbuf, "%s: %s\\tpropagated", Xname, Xreason);
707 if (/^\s*CASE\s*:/) {
712 print Q<<EOF if $except;
717 print Q<<EOF unless $PPCODE;
727 # print initialization routine
728 print qq/extern "C"\n/ if $cplusplus;
730 #XS(boot_$Module_cname)
733 # char* file = __FILE__;
738 $pname = shift(@Func_pname);
739 print " newXS(\"$pname\", XS_$_, file);\n";
744 print "\n /* Initialisation Section */\n\n" ;
745 print grep (s/$/\n/, @BootCode) ;
746 print " /* End of Initialisation Section */\n\n" ;
749 print " ST(0) = &sv_yes;\n";
750 print " XSRETURN(1);\n";
754 local($type, $num, $init) = @_;
755 local($arg) = "ST(" . ($num - 1) . ")";
757 eval qq/print " $init\\\n"/;
762 # work out the line number
763 my $line_no = $line_no[@line_no - @line -1] ;
765 print STDERR "@_ in $filename, line $line_no\n" ;
781 local($type, $num, $var) = @_;
782 local($arg) = "ST(" . ($num - 1) . ")";
783 local($argoff) = $num - 1;
787 $type = TidyType($type) ;
788 blurt("Error: '$type' not in typemap"), return
789 unless defined($type_kind{$type});
791 ($ntype = $type) =~ s/\s*\*/Ptr/g;
793 $subtype =~ s/Ptr$//;
794 $subtype =~ s/Array$//;
795 $tk = $type_kind{$type};
796 $tk =~ s/OBJ$/REF/ if $func_name =~ /DESTROY$/;
798 blurt("Error: No INPUT definition for type '$type' found"), return
799 unless defined $input_expr{$tk} ;
800 $expr = $input_expr{$tk};
801 if ($expr =~ /DO_ARRAY_ELEM/) {
802 blurt("Error: '$subtype' not in typemap"), return
803 unless defined($type_kind{$subtype});
804 blurt("Error: No INPUT definition for type '$subtype' found"), return
805 unless defined $input_expr{$type_kind{$subtype}} ;
806 $subexpr = $input_expr{$type_kind{$subtype}};
807 $subexpr =~ s/ntype/subtype/g;
808 $subexpr =~ s/\$arg/ST(ix_$var)/g;
809 $subexpr =~ s/\n\t/\n\t\t/g;
810 $subexpr =~ s/is not of (.*")/[arg %d] is not of $1, ix_$var + 1/g;
811 $subexpr =~ s/\$var/${var}[ix_$var - $argoff]/;
812 $expr =~ s/DO_ARRAY_ELEM/$subexpr/;
814 if (defined($defaults{$var})) {
815 $expr =~ s/(\t+)/$1 /g;
817 eval qq/print "\\t$var;\\n"/;
818 $deferred .= eval qq/"\\n\\tif (items < $num)\\n\\t $var = $defaults{$var};\\n\\telse {\\n$expr;\\n\\t}\\n"/;
819 } elsif ($expr !~ /^\t\$var =/) {
820 eval qq/print "\\t$var;\\n"/;
821 $deferred .= eval qq/"\\n$expr;\\n"/;
823 eval qq/print "$expr;\\n"/;
827 sub generate_output {
828 local($type, $num, $var) = @_;
829 local($arg) = "ST(" . ($num - ($num != 0)) . ")";
830 local($argoff) = $num - 1;
833 $type = TidyType($type) ;
834 if ($type =~ /^array\(([^,]*),(.*)\)/) {
835 print "\tsv_setpvn($arg, (char *)$var, $2 * sizeof($1)), XFree((char *)$var);\n";
837 blurt("Error: '$type' not in typemap"), return
838 unless defined($type_kind{$type});
839 blurt("Error: No OUTPUT definition for type '$type' found"), return
840 unless defined $output_expr{$type_kind{$type}} ;
841 ($ntype = $type) =~ s/\s*\*/Ptr/g;
844 $subtype =~ s/Ptr$//;
845 $subtype =~ s/Array$//;
846 $expr = $output_expr{$type_kind{$type}};
847 if ($expr =~ /DO_ARRAY_ELEM/) {
848 blurt("Error: '$subtype' not in typemap"), return
849 unless defined($type_kind{$subtype});
850 blurt("Error: No OUTPUT definition for type '$subtype' found"), return
851 unless defined $output_expr{$type_kind{$subtype}} ;
852 $subexpr = $output_expr{$type_kind{$subtype}};
853 $subexpr =~ s/ntype/subtype/g;
854 $subexpr =~ s/\$arg/ST(ix_$var)/g;
855 $subexpr =~ s/\$var/${var}[ix_$var]/g;
856 $subexpr =~ s/\n\t/\n\t\t/g;
857 $expr =~ s/DO_ARRAY_ELEM\n/$subexpr/;
858 eval "print qq\a$expr\a";
860 elsif ($var eq 'RETVAL') {
861 if ($expr =~ /^\t\$arg = /) {
862 eval "print qq\a$expr\a";
863 print "\tsv_2mortal(ST(0));\n";
866 print "\tST(0) = sv_newmortal();\n";
867 eval "print qq\a$expr\a";
870 elsif ($arg =~ /^ST\(\d+\)$/) {
871 eval "print qq\a$expr\a";
880 if ($type =~ /^array\(([^,]*),(.*)\)/) {
887 # If this is VMS, the exit status has meaning to the shell, so we
888 # use a predictable value (SS$_Abort) rather than an arbitrary
890 exit ($Is_VMS ? 44 : $errors) ;