home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / grammar.pm < prev    next >
Encoding:
Perl POD Document  |  2002-06-12  |  11.6 KB  |  482 lines

  1. package ExtUtils::XSBuilder::C::grammar;
  2.  
  3. # initial grammar is taken from Inline::C::grammar & Inline::Struct::grammar
  4.  
  5. use strict;
  6. use vars qw{$VERSION @EXPORT @ISA} ;
  7. use Exporter ;
  8. use Data::Dumper ;
  9.  
  10.  
  11. $VERSION = '0.30';
  12.  
  13. @ISA = qw{Exporter} ;
  14. @EXPORT = qw{cdef_define cdef_enum cdef_struct cdef_function_declaration} ;
  15.  
  16.  
  17. # ============================================================================
  18.  
  19. sub cdef_define
  20.     {
  21.     my ($thisparser, $name, $comment) = @_ ;
  22.  
  23.     my $elem = { name => $name, $comment?(comment => $comment):() } ;
  24.     if ($thisparser->{srcobj}->handle_define($elem)) 
  25.         {
  26.         push @{$thisparser->{data}{constants}}, $elem ;
  27.         print "constant: $name\n" ;
  28.         }
  29.     else
  30.         {
  31.         print "constant: $name (ignore because handle_define returned false)\n" ;
  32.         }
  33.     }
  34.     
  35. # ============================================================================
  36.  
  37. sub cdef_enum
  38.     {
  39.     my ($thisparser, $names) = @_ ;
  40.  
  41.     for (@{$names})
  42.         {
  43.         if (ref $_) 
  44.             {
  45.         my $elem = { name => $_ -> [0], $_->[1] && @{$_->[1]}?('comment' => join (' ', @{$_->[1]})):() } ;
  46.             push @{$thisparser->{data}{constants}}, $elem if ($thisparser->{srcobj}->handle_enum($elem)) ; 
  47.             }
  48.         }
  49.     1 ;
  50.     }
  51.  
  52. # ============================================================================
  53.  
  54. sub cdef_struct
  55.     {
  56.     my ($thisparser, $perlname, $cname, $fields, $type) = @_;
  57.     my $seen = \$thisparser->{data}{structure}{$cname || $type} ;
  58.     my $s = $$seen ;
  59.     return 0 if ($s && ($s -> {elts} && !$type)) ;
  60.     #print "cdef $cname $type\n" ;
  61.     $s ||= {} ;
  62.     $s -> {type} ||= $cname ;
  63.     $s -> {type} = $type if ($type) ;
  64.     if ($fields)
  65.         {
  66.         my @fields;
  67.         my @comment ;
  68.         for (@$fields)
  69.             {
  70.             if (ref $_) 
  71.                 {
  72.                 push @fields, { 
  73.                     'type' => $_->[0], 
  74.                     'name' => $_->[1], 
  75.                     ($_->[2] && @{$_->[2]}) || @comment?('comment' => join (' ', @{$_->[2]}, @comment)):(), 
  76.                     $_->[3] && @{$_->[3]}?('args' => $_->[3]):(), 
  77.                     } ; 
  78.                 @comment = () ;
  79.                 }
  80.             else
  81.                 {
  82.                 push @comment, $_ ;
  83.                 }
  84.             }
  85.         $s -> {elts} = \@fields ;
  86.         }
  87.     $s -> {stype} = $cname if ($cname) ; 
  88.     if ($fields)
  89.         {
  90.         if ($thisparser->{srcobj}->handle_struct($s)) 
  91.             {
  92.             push @{$thisparser->{data}{structures}}, $s ;
  93.             print "struct:   $cname (type=$type)\n" ;
  94.             }
  95.         else
  96.             {
  97.             print "struct:   $cname (ignore because handle_struct returned false)\n" ;
  98.             }
  99.         }
  100.     $$seen = $s ;
  101.     return $s ;
  102.     }
  103.  
  104.  
  105. # ============================================================================
  106.  
  107. sub cdef_function_declaration
  108.     {
  109.     my ($thisparser, $function, $rettype, $args) = @_ ;
  110.     return 0 if (!$function) ;
  111.     return 0 if ($thisparser->{data}{function}{$function}++) ;
  112.     my $s = { 'name' => $function } ;
  113.     my $dummy = 'arg0' ;
  114.     $s -> {return_type} = $rettype ;
  115.     my @args ;
  116.     my $i = 0 ;
  117.     for (@{$args})
  118.         {
  119.         if (ref $_) 
  120.             {
  121.             push @args, { 
  122.                 'type' => $_->[0], 
  123.                 'name' => $_->[1] || "arg$i", 
  124.                 } if ($_->[0] ne 'void') ; 
  125.             }
  126.         $i++ ;
  127.         }
  128.     $s -> {args} = \@args ;
  129.      if ($thisparser->{srcobj}->handle_function($s)) 
  130.         {
  131.         push @{$thisparser->{data}{functions}}, $s ;
  132.         print "func:     $function\n" ;
  133.         }
  134.     else
  135.         {
  136.         print "func:     $function (ignore because handle_function returned false)\n" ;
  137.         }
  138.     return $s ;
  139.     }
  140.  
  141. # ============================================================================
  142.  
  143. sub grammar {
  144.     <<'END';
  145.  
  146. use ExtUtils::XSBuilder::C::grammar ; # import cdef_xxx functions 
  147. }
  148.  
  149. code:    comment_part(s) {1}
  150.  
  151. comment_part:
  152.     comment(s?) part
  153.         { 
  154.         #print "comment: ", Data::Dumper::Dumper(\@item) ;
  155.         $item[2] -> {comment} = "@{$item[1]}" if (ref $item[1] && @{$item[1]} && ref $item[2]) ;
  156.         1 ;
  157.         }
  158.     | comment
  159.  
  160. part:   
  161.     prepart 
  162.     | stdpart
  163.         {
  164.         if ($thisparser -> {my_neednewline}) 
  165.             {
  166.             print "\n" ;
  167.             $thisparser -> {my_neednewline} = 0 ;
  168.             }
  169.         $return = $item[1] ;
  170.         }
  171.  
  172. # prepart can be used to extent the parser (for default it always fails)
  173.  
  174. prepart:  '?' 
  175.         {0}
  176.  
  177.            
  178. stdpart:   
  179.     define
  180.         {
  181.         $return = cdef_define ($thisparser, $item[1][0], $item[1][1]) ;
  182.         }
  183.     | struct
  184.         {
  185.         $return = cdef_struct ($thisparser, @{$item[1]}) ;
  186.         }
  187.     | enum
  188.         {
  189.         $return = cdef_enum ($thisparser, $item[1][1]) ;
  190.         }
  191.     | function_declaration
  192.         {
  193.         $return = cdef_function_declaration ($thisparser, @{$item[1]}) ;
  194.         }
  195.     | struct_typedef
  196.         {
  197.         my ($type,$alias) = @{$item[1]}[0,1];
  198.         $return = cdef_struct ($thisparser, undef, $type, undef, $alias) ;
  199.         }
  200.     | comment
  201.     | anything_else
  202.  
  203. comment:
  204.     m{\s* // \s* ([^\n]*) \s*? \n }x
  205.         { $1 }
  206.     | m{\s* /\* \s* ([^*]+|\*(?!/))* \s*? \*/  ([ \t]*)? }x
  207.         { $item[1] =~ m#/\*\s*?(.*?)\s*?\*/#s ; $1 }
  208.  
  209. semi_linecomment:
  210.     m{;\s*\n}x
  211.         {
  212.         $return = [] ;
  213.         1 ;
  214.         }
  215.     | ';' comment(s?)
  216.         {
  217.         $item[2]
  218.         }
  219.  
  220. function_definition:
  221.     rtype IDENTIFIER '(' <leftop: arg ',' arg>(s?) ')' '{'
  222.         {[@item[2,1], $item[4]]}
  223.  
  224. pTHX:
  225.     'pTHX_'
  226.  
  227. function_declaration:
  228.     type_identifier '(' pTHX(?) <leftop: arg_decl ',' arg_decl>(s?) ')' function_declaration_attr ( ';' | '{' )
  229.         {
  230.         #print Data::Dumper::Dumper (\@item) ;
  231.             [
  232.             $item[1][1], 
  233.             $item[1][0], 
  234.             @{$item[3]}?[['pTHX', 'aTHX' ], @{$item[4]}]:$item[4] 
  235.             ]
  236.         }
  237.  
  238. define:
  239.     '#define' IDENTIFIER /.*?\n/
  240.         {
  241.         $item[3] =~ m{(?:/\*\s*(.*?)\s*\*/|//\s*(.*?)\s*$)} ; [$item[2], $1] 
  242.         }
  243.  
  244. ignore_cpp:
  245.     '#' /.*?\n/
  246.  
  247. struct: 
  248.     'struct' IDENTIFIER '{' field(s) '}' ';'
  249.         {
  250.         # [perlname, cname, fields]
  251.         [$item[2], "@item[1,2]", $item[4]]
  252.         }
  253.     | 'typedef' 'struct' '{' field(s) '}' IDENTIFIER ';'
  254.         {
  255.         # [perlname, cname, fields]
  256.         [$item[6], undef, $item[4], $item[6]]
  257.         }
  258.     | 'typedef' 'struct' IDENTIFIER '{' field(s) '}' IDENTIFIER ';'
  259.         {
  260.         # [perlname, cname, fields, alias]
  261.         [$item[3], "@item[2,3]", $item[5], $item[7]]
  262.         }
  263.  
  264. struct_typedef: 
  265.     'typedef' 'struct' IDENTIFIER IDENTIFIER ';'
  266.         {
  267.     ["@item[2,3]", $item[4]]
  268.     }
  269.  
  270. enum: 
  271.     'enum' IDENTIFIER '{' enumfield(s) '}' ';'
  272.         {
  273.         [$item[2], $item[4]]
  274.         }
  275.     | 'typedef' 'enum' '{' enumfield(s) '}' IDENTIFIER ';'
  276.         {
  277.         [undef, $item[4], $item[6]]
  278.         }
  279.     | 'typedef' 'enum' IDENTIFIER '{' enumfield(s) '}' IDENTIFIER ';'
  280.         {
  281.         [$item[3], $item[5], $item[7]]
  282.         }
  283.  
  284. field: 
  285.     comment 
  286.     | define
  287.     {
  288.         $return = cdef_define ($thisparser, $item[1][0], $item[1][1]) ;
  289.     }
  290.     | valuefield 
  291.     | callbackfield
  292.     | ignore_cpp
  293.  
  294. valuefield: 
  295.     type_identifier comment(s?) semi_linecomment
  296.         {
  297.         $thisparser -> {my_neednewline} = 1 ;
  298.         print "  valuefield: $item[1][0] : $item[1][1]\n" ;
  299.     [$item[1][0], $item[1][1], [$item[2]?@{$item[2]}:() , $item[3]?@{$item[3]}:()] ]
  300.         }
  301.  
  302.  
  303. callbackfield: 
  304.     rtype '(' '*' IDENTIFIER ')' '(' <leftop: arg_decl ',' arg_decl>(s?) ')' comment(s?) semi_linecomment
  305.         {
  306.         my $type = "$item[1](*)(" . join(',', map { "$_->[0] $_->[1]" } @{$item[7]}) . ')' ;
  307.         my $dummy = 'arg0' ;
  308.         my @args ;
  309.         for (@{$item[7]})
  310.             {
  311.             if (ref $_) 
  312.                 {
  313.                 push @args, { 
  314.                     'type' => $_->[0], 
  315.                     'name' => $_->[1], 
  316.                     } if ($_->[0] ne 'void') ; 
  317.                 }
  318.             }
  319.         my $s = { 'name' => $type, 'return_type' => $item[1], args => \@args } ;
  320.         push @{$thisparser->{data}{callbacks}}, $s  if ($thisparser->{srcobj}->handle_callback($s)) ;
  321.  
  322.         $thisparser -> {my_neednewline} = 1 ;
  323.         print "  callbackfield: $type : $item[4]\n" ;
  324.         [$type, $item[4], [$item[9]?@{$item[9]}:() , $item[10]?@{$item[10]}:()]] ;
  325.         }
  326.  
  327.  
  328. enumfield: 
  329.     comment
  330.     | IDENTIFIER  comment(s?) /,?/ comment(s?)
  331.         {
  332.         [$item[1], [$item[2]?@{$item[2]}:() , $item[4]?@{$item[4]}:()] ] ;
  333.         }
  334.  
  335. rtype:  
  336.     modmodifier(s) TYPE star(s?)
  337.         {
  338.         my @modifier = @{$item[1]} ;
  339.         shift @modifier if ($modifier[0] eq 'extern' || $modifier[0] eq 'static') ;
  340.  
  341.         $return = join ' ',@modifier, $item[2] ;
  342.         $return .= join '',' ',@{$item[3]} if @{$item[3]};
  343.         1 ;
  344.     }
  345.     | TYPE(s) star(s?)
  346.         {
  347.         $return = join (' ', @{$item[1]}) ;
  348.         $return .= join '',' ',@{$item[2]} if @{$item[2]};
  349.     #print "rtype $return \n" ;
  350.         1 ;
  351.         }
  352.     modifier(s)  star(s?)
  353.         {
  354.         join ' ',@{$item[1]}, @{$item[2]} ;
  355.     }
  356.  
  357. arg:
  358.     type_identifier 
  359.         {[$item[1][0],$item[1][1]]}
  360.     | '...'
  361.         {['...']}
  362.  
  363. arg_decl: 
  364.     rtype '(' '*' IDENTIFIER ')' '(' <leftop: arg_decl ',' arg_decl>(s?) ')'
  365.         {
  366.         my $type = "$item[1](*)(" . join(',', map { "$_->[0] $_->[1]" } @{$item[7]}) . ')' ;
  367.         my $dummy = 'arg0' ;
  368.         my @args ;
  369.         for (@{$item[7]})
  370.             {
  371.             if (ref $_) 
  372.                 {
  373.                 push @args, { 
  374.                     'type' => $_->[0], 
  375.                     'name' => $_->[1], 
  376.                     } if ($_->[0] ne 'void') ; 
  377.                 }
  378.             }
  379.         my $s = { 'name' => $type, 'return_type' => $item[1], args => \@args } ;
  380.         push @{$thisparser->{data}{callbacks}}, $s  if ($thisparser->{srcobj}->handle_callback($s)) ;
  381.  
  382.         [$type, $item[4], [$item[9]?@{$item[9]}:() , $item[11]?@{$item[11]}:()]] ;
  383.         }
  384.     | 'pTHX'
  385.     {
  386.     ['pTHX', 'aTHX' ]
  387.     }
  388.     | type_identifier
  389.     {
  390.     [$item[1][0], $item[1][1] ]
  391.     }
  392.     | '...'
  393.         {['...']}
  394.  
  395. function_declaration_attr:
  396.  
  397. type_identifier:
  398.     type_varname 
  399.         { 
  400.         my $r ;
  401.     my @type = @{$item[1]} ;
  402.     #print "type = @type\n" ;
  403.     my $name = pop @type ;
  404.     if (@type && ($name !~ /\*/)) 
  405.         {
  406.             $r = [join (' ', @type), $name] 
  407.         }
  408.     else
  409.         {
  410.         $r = [join (' ', @{$item[1]})] ;
  411.         }                
  412.     #print "r = @$r\n" ;
  413.         $r ;
  414.         }
  415.  
  416. type_varname:   
  417.     attribute(s?) TYPE(s) star(s) varname(?)
  418.         {
  419.     [@{$item[1]}, @{$item[2]}, @{$item[3]}, @{$item[4]}] ;    
  420.     }
  421.     | attribute(s?) varname(s)
  422.         {
  423.     $item[2] ;    
  424.     }
  425.  
  426.  
  427. varname:
  428.     ##IDENTIFIER '[' IDENTIFIER ']'
  429.     IDENTIFIER '[' /[^]]+/ ']'
  430.     {
  431.     "$item[1]\[$item[3]\]" ;
  432.     }
  433.     | IDENTIFIER ':' IDENTIFIER
  434.     {
  435.     $item[1]
  436.     }
  437.     | IDENTIFIER
  438.     {
  439.     $item[1]
  440.     }
  441.  
  442.  
  443. star: '*' | 'const' '*'
  444.         
  445. modifier: 'const' | 'struct' | 'enum' | 'unsigned' | 'long' | 'extern' | 'static' | 'short' | 'signed'
  446.  
  447. modmodifier: 'const' | 'struct' | 'enum' | 'extern' | 'static'
  448.  
  449. attribute: 'extern' | 'static' 
  450.  
  451. # IDENTIFIER: /[a-z]\w*/i
  452. IDENTIFIER: /\w+/
  453.  
  454. TYPE: /\w+/
  455.  
  456. anything_else: /.*/
  457.  
  458. END
  459. }
  460.  
  461. 1;
  462.  
  463. __END__
  464.  
  465.  
  466. =pod
  467.     | function_definition
  468.     {
  469.      my $function = $item[1][0];
  470.          $return = 1, last if $thisparser->{data}{done}{$function}++;
  471.      push @{$thisparser->{data}{functions}}, $function;
  472.      $thisparser->{data}{function}{$function}{return_type} = 
  473.              $item[1][1];
  474.      $thisparser->{data}{function}{$function}{arg_types} = 
  475.              [map {ref $_ ? $_->[0] : '...'} @{$item[1][2]}];
  476.      $thisparser->{data}{function}{$function}{arg_names} = 
  477.              [map {ref $_ ? $_->[1] : '...'} @{$item[1][2]}];
  478.     }
  479. =cut
  480.  
  481.