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

📄 xsubpp

📁 ARM上的如果你对底层感兴趣
💻
📖 第 1 页 / 共 3 页
字号:
    }
}

sub REQUIRE_handler ()
{
    # the rest of the current line should contain a version number
    my ($Ver) = $_ ;

    TrimWhitespace($Ver) ;

    death ("Error: REQUIRE expects a version number")
	unless $Ver ;

    # check that the version number is of the form n.n
    death ("Error: REQUIRE: expected a number, got '$Ver'")
	unless $Ver =~ /^\d+(\.\d*)?/ ;

    death ("Error: xsubpp $Ver (or better) required--this is only $XSUBPP_version.")
        unless $XSUBPP_version >= $Ver ; 
}

sub VERSIONCHECK_handler ()
{
    # the rest of the current line should contain either ENABLE or
    # DISABLE
 
    TrimWhitespace($_) ;
 
    # check for ENABLE/DISABLE
    death ("Error: VERSIONCHECK: ENABLE/DISABLE")
        unless /^(ENABLE|DISABLE)/i ;
 
    $WantVersionChk = 1 if $1 eq 'ENABLE' ;
    $WantVersionChk = 0 if $1 eq 'DISABLE' ;
 
}

sub PROTOTYPE_handler ()
{
    my $specified ;

    death("Error: Only 1 PROTOTYPE definition allowed per xsub") 
        if $proto_in_this_xsub ++ ;

    for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
	next unless /\S/;
	$specified = 1 ;
	TrimWhitespace($_) ;
        if ($_ eq 'DISABLE') {
	   $ProtoThisXSUB = 0 
        }
        elsif ($_ eq 'ENABLE') {
	   $ProtoThisXSUB = 1 
        }
        else {
            # remove any whitespace
            s/\s+//g ;
            death("Error: Invalid prototype '$_'")
                unless ValidProtoString($_) ;
            $ProtoThisXSUB = C_string($_) ;
        }
    }

    # If no prototype specified, then assume empty prototype ""
    $ProtoThisXSUB = 2 unless $specified ;

    $ProtoUsed = 1 ;

}

sub SCOPE_handler ()
{
    death("Error: Only 1 SCOPE declaration allowed per xsub") 
        if $scope_in_this_xsub ++ ;

    for (;  !/^$BLOCK_re/o;  $_ = shift(@line)) {
		next unless /\S/;
		TrimWhitespace($_) ;
        if ($_ =~ /^DISABLE/i) {
		   $ScopeThisXSUB = 0 
        }
        elsif ($_ =~ /^ENABLE/i) {
		   $ScopeThisXSUB = 1 
        }
    }

}

sub PROTOTYPES_handler ()
{
    # the rest of the current line should contain either ENABLE or
    # DISABLE 

    TrimWhitespace($_) ;

    # check for ENABLE/DISABLE
    death ("Error: PROTOTYPES: ENABLE/DISABLE")
        unless /^(ENABLE|DISABLE)/i ;

    $WantPrototypes = 1 if $1 eq 'ENABLE' ;
    $WantPrototypes = 0 if $1 eq 'DISABLE' ;
    $ProtoUsed = 1 ;

}

sub INCLUDE_handler ()
{
    # the rest of the current line should contain a valid filename
 
    TrimWhitespace($_) ;
 
    death("INCLUDE: filename missing")
        unless $_ ;

    death("INCLUDE: output pipe is illegal")
        if /^\s*\|/ ;

    # simple minded recursion detector
    death("INCLUDE loop detected")
        if $IncludedFiles{$_} ;

    ++ $IncludedFiles{$_} unless /\|\s*$/ ;

    # Save the current file context.
    push(@XSStack, {
	type		=> 'file',
        LastLine        => $lastline,
        LastLineNo      => $lastline_no,
        Line            => \@line,
        LineNo          => \@line_no,
        Filename        => $filename,
        Handle          => $FH,
        }) ;
 
    ++ $FH ;

    # open the new file
    open ($FH, "$_") or death("Cannot open '$_': $!") ;
 
    print Q<<"EOF" ;
#
#/* INCLUDE:  Including '$_' from '$filename' */
#
EOF

    $filename = $_ ;

    # Prime the pump by reading the first 
    # non-blank line

    # skip leading blank lines
    while (<$FH>) {
        last unless /^\s*$/ ;
    }

    $lastline = $_ ;
    $lastline_no = $. ;
 
}
 
sub PopFile()
{
    return 0 unless $XSStack[-1]{type} eq 'file' ;

    my $data     = pop @XSStack ;
    my $ThisFile = $filename ;
    my $isPipe   = ($filename =~ /\|\s*$/) ;
 
    -- $IncludedFiles{$filename}
        unless $isPipe ;

    close $FH ;

    $FH         = $data->{Handle} ;
    $filename   = $data->{Filename} ;
    $lastline   = $data->{LastLine} ;
    $lastline_no = $data->{LastLineNo} ;
    @line       = @{ $data->{Line} } ;
    @line_no    = @{ $data->{LineNo} } ;

    if ($isPipe and $? ) {
        -- $lastline_no ;
        print STDERR "Error reading from pipe '$ThisFile': $! in $filename, line $lastline_no\n"  ;
        exit 1 ;
    }

    print Q<<"EOF" ;
#
#/* INCLUDE: Returning to '$filename' from '$ThisFile' */
#
EOF

    return 1 ;
}

sub ValidProtoString ($)
{
    my($string) = @_ ;

    if ( $string =~ /^$proto_re+$/ ) {
        return $string ;
    }

    return 0 ;
}

sub C_string ($)
{
    my($string) = @_ ;

    $string =~ s[\\][\\\\]g ;
    $string ;
}

sub ProtoString ($)
{
    my ($type) = @_ ;

    $proto_letter{$type} or "\$" ;
}

sub check_cpp {
    my @cpp = grep(/^\#\s*(?:if|e\w+)/, @line);
    if (@cpp) {
	my ($cpp, $cpplevel);
	for $cpp (@cpp) {
	    if ($cpp =~ /^\#\s*if/) {
		$cpplevel++;
	    } elsif (!$cpplevel) {
		Warn("Warning: #else/elif/endif without #if in this function");
		print STDERR "    (precede it with a blank line if the matching #if is outside the function)\n"
		    if $XSStack[-1]{type} eq 'if';
		return;
	    } elsif ($cpp =~ /^\#\s*endif/) {
		$cpplevel--;
	    }
	}
	Warn("Warning: #if without #endif in this function") if $cpplevel;
    }
}


sub Q {
    my($text) = @_;
    $text =~ s/^#//gm;
    $text =~ s/\[\[/{/g;
    $text =~ s/\]\]/}/g;
    $text;
}

open($FH, $filename) or die "cannot open $filename: $!\n";

# Identify the version of xsubpp used
print <<EOM ;
/*
 * This file was generated automatically by xsubpp version $XSUBPP_version from the 
 * contents of $filename. Do not edit this file, edit $filename instead.
 *
 *	ANY CHANGES MADE HERE WILL BE LOST! 
 *
 */

EOM
 

print("#line 1 \"$filename\"\n")
    if $WantLineNumbers;

while (<$FH>) {
    last if ($Module, $Package, $Prefix) =
	/^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/;

    if ($OBJ) {
        s/#if(?:def|\s+defined)\s+(\(__cplusplus\)|__cplusplus)/#if defined(__cplusplus) && !defined(PERL_OBJECT)/;
    }
    print $_;
}
&Exit unless defined $_;

print "$xsubpp::counter::SECTION_END_MARKER\n" if $WantLineNumbers;

$lastline    = $_;
$lastline_no = $.;

# Read next xsub into @line from ($lastline, <$FH>).
sub fetch_para {
    # parse paragraph
    death ("Error: Unterminated `#if/#ifdef/#ifndef'")
	if !defined $lastline && $XSStack[-1]{type} eq 'if';
    @line = ();
    @line_no = () ;
    return PopFile() if !defined $lastline;

    if ($lastline =~
	/^MODULE\s*=\s*([\w:]+)(?:\s+PACKAGE\s*=\s*([\w:]+))?(?:\s+PREFIX\s*=\s*(\S+))?\s*$/) {
	$Module = $1;
	$Package = defined($2) ? $2 : '';	# keep -w happy
	$Prefix  = defined($3) ? $3 : '';	# keep -w happy
	$Prefix = quotemeta $Prefix ;
	($Module_cname = $Module) =~ s/\W/_/g;
	($Packid = $Package) =~ tr/:/_/;
	$Packprefix = $Package;
	$Packprefix .= "::" if $Packprefix ne "";
	$lastline = "";
    }

    for(;;) {
	if ($lastline !~ /^\s*#/ ||
	    # CPP directives:
	    #	ANSI:	if ifdef ifndef elif else endif define undef
	    #		line error pragma
	    #	gcc:	warning include_next
	    #   obj-c:	import
	    #   others:	ident (gcc notes that some cpps have this one)
	    $lastline =~ /^#[ \t]*(?:(?:if|ifn?def|elif|else|endif|define|undef|pragma|error|warning|line\s+\d+|ident)\b|(?:include(?:_next)?|import)\s*["<].*[>"])/) {
	    last if $lastline =~ /^\S/ && @line && $line[-1] eq "";
	    push(@line, $lastline);
	    push(@line_no, $lastline_no) ;
	}

	# Read next line and continuation lines
	last unless defined($lastline = <$FH>);
	$lastline_no = $.;
	my $tmp_line;
	$lastline .= $tmp_line
	    while ($lastline =~ /\\$/ && defined($tmp_line = <$FH>));
	    
	chomp $lastline;
	$lastline =~ s/^\s+$//;
    }
    pop(@line), pop(@line_no) while @line && $line[-1] eq "";
    1;
}

PARAGRAPH:
while (fetch_para()) {
    # Print initial preprocessor statements and blank lines
    while (@line && $line[0] !~ /^[^\#]/) {
	my $line = shift(@line);
	print $line, "\n";
	next unless $line =~ /^\#\s*((if)(?:n?def)?|elsif|else|endif)\b/;
	my $statement = $+;
	if ($statement eq 'if') {
	    $XSS_work_idx = @XSStack;
	    push(@XSStack, {type => 'if'});
	} else {
	    death ("Error: `$statement' with no matching `if'")
		if $XSStack[-1]{type} ne 'if';
	    if ($XSStack[-1]{varname}) {
		push(@InitFileCode, "#endif\n");
		push(@BootCode,     "#endif");
	    }

	    my(@fns) = keys %{$XSStack[-1]{functions}};
	    if ($statement ne 'endif') {
		# Hide the functions defined in other #if branches, and reset.
		@{$XSStack[-1]{other_functions}}{@fns} = (1) x @fns;
		@{$XSStack[-1]}{qw(varname functions)} = ('', {});
	    } else {
		my($tmp) = pop(@XSStack);
		0 while (--$XSS_work_idx
			 && $XSStack[$XSS_work_idx]{type} ne 'if');
		# Keep all new defined functions
		push(@fns, keys %{$tmp->{other_functions}});
		@{$XSStack[$XSS_work_idx]{functions}}{@fns} = (1) x @fns;
	    }
	}
    }

    next PARAGRAPH unless @line;

    if ($XSS_work_idx && !$XSStack[$XSS_work_idx]{varname}) {
	# We are inside an #if, but have not yet #defined its xsubpp variable.
	print "#define $cpp_next_tmp 1\n\n";
	push(@InitFileCode, "#if $cpp_next_tmp\n");
	push(@BootCode,     "#if $cpp_next_tmp");
	$XSStack[$XSS_work_idx]{varname} = $cpp_next_tmp++;
    }

    death ("Code is not inside a function"
	   ." (maybe last function was ended by a blank line "
	   ." followed by a a statement on column one?)")
	if $line[0] =~ /^\s/;

    # initialize info arrays
    undef(%args_match);
    undef(%var_types);
    undef(%var_addr);
    undef(%defaults);
    undef($class);
    undef($static);
    undef($elipsis);
    undef($wantRETVAL) ;
    undef(%arg_list) ;
    undef(@proto_arg) ;
    undef($proto_in_this_xsub) ;
    undef($scope_in_this_xsub) ;
    undef($interface);
    $interface_macro = 'XSINTERFACE_FUNC' ;
    $interface_macro_set = 'XSINTERFACE_FUNC_SET' ;
    $ProtoThisXSUB = $WantPrototypes ;
    $ScopeThisXSUB = 0;

    $_ = shift(@line);
    while ($kwd = check_keyword("REQUIRE|PROTOTYPES|VERSIONCHECK|INCLUDE")) {
        &{"${kwd}_handler"}() ;
        next PARAGRAPH unless @line ;
        $_ = shift(@line);
    }

    if (check_keyword("BOOT")) {
	&check_cpp;
	push (@BootCode, "#line $line_no[@line_no - @line] \"$filename\"")
	  if $WantLineNumbers && $line[0] !~ /^\s*#\s*line\b/;
        push (@BootCode, @line, "") ;
        next PARAGRAPH ;
    }


    # extract return type, function name and arguments
    ($ret_type) = TidyType($_);

    # a function definition needs at least 2 lines
    blurt ("Error: Function definition too short '$ret_type'"), next PARAGRAPH
	unless @line ;

    $static = 1 if $ret_type =~ s/^static\s+//;

    $func_header = shift(@line);
    blurt ("Error: Cannot parse function definition from '$func_header'"), next PARAGRAPH
	unless $func_header =~ /^(?:([\w:]*)::)?(\w+)\s*\(\s*(.*?)\s*\)\s*(const)?\s*$/s;

    ($class, $func_name, $orig_args) =  ($1, $2, $3) ;
    $class = "$4 $class" if $4;
    ($pname = $func_name) =~ s/^($Prefix)?/$Packprefix/;
    ($clean_func_name = $func_name) =~ s/^$Prefix//;
    $Full_func_name = "${Packid}_$clean_func_name";
    if ($Is_VMS) { $Full_func_name = $SymSet->addsym($Full_func_name); }

    # Check for duplicate function definition
    for $tmp (@XSStack) {
	next unless defined $tmp->{functions}{$Full_func_name};
	Warn("Warning: duplicate function definition '$clean_func_name' detected");
	last;
    }
    $XSStack[$XSS_work_idx]{functions}{$Full_func_name} ++ ;
    %XsubAliases = %XsubAliasValues = %Interfaces = ();
    $DoSetMagic = 1;

    @args = split(/\s*,\s*/, $orig_args);
    if (defined($class)) {
	my $arg0 = ((defined($static) or $func_name eq 'new')
		    ? "CLASS" : "THIS");
	unshift(@args, $arg0);
	($orig_args = "$arg0, $orig_args") =~ s/^$arg0, $/$arg0/;
    }
    $orig_args =~ s/"/\\"/g;
    $min_args = $num_args = @args;
    foreach $i (0..$num_args-1) {
	    if ($args[$i] =~ s/\.\.\.//) {
		    $elipsis = 1;
		    $min_args--;
		    if ($args[$i] eq '' && $i == $num_args - 1) {
			pop(@args);
			last;
		    }
	    }
	    if ($args[$i] =~ /^([^=]*[^\s=])\s*=\s*(.*)/s) {
		    $min_args--;
		    $args[$i] = $1;
		    $defaults{$args[$i]} = $2;
		    $defaults{$args[$i]} =~ s/"/\\"/g;
	    }
	    $proto_arg[$i+1] = "\$" ;
    }
    if (defined($class)) {
	    $func_args = join(", ", @args[1..$#args]);
    } else {
	    $func_args = join(", ", @args);
    }
    @args_match{@args} = 1..@args;

    $PPCODE = grep(/^\s*PPCODE\s*:/, @line);
    $CODE = grep(/^\s*CODE\s*:/, @line);
    # Detect CODE: blocks which use ST(n)= or XST_m*(n,v)
    #   to set explicit return values.
    $EXPLICIT_RETURN = ($CODE &&
		("@line" =~ /(\bST\s*\([^;]*=) | (\bXST_m\w+\s*\()/x ));
    $ALIAS  = grep(/^\s*ALIAS\s*:/,  @line);
    $INTERFACE  = grep(/^\s*INTERFACE\s*:/,  @line);

    # print function header
    print Q<<"EOF";
#XS(XS_${Full_func_name})
#[[
#    dXSARGS;
EOF
    print Q<<"EOF" if $ALIAS ;
#    dXSI32;
EOF
    print Q<<"EOF" if $INTERFACE ;
#    dXSFUNCTION($ret_type);
EOF
    if ($elipsis) {
	$cond = ($min_args ? qq(items < $min_args) : 0);

⌨️ 快捷键说明

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