improve CParser
[rofl0r-c-split.git] / CParser.pm
bloba2e5124242ecf30a5bd88cbff4a309b58a9ebd81
1 package CParser;
3 use strict;
4 use warnings;
6 sub file_ext {
7 my $x = shift;
8 my $l = length($x);
9 $l-- while($l && substr($x, $l, 1) ne ".");
10 return substr($x, $l) if($l);
11 return "";
15 sub new {
16 my ($pkg, @args) = @_;
17 die("need C file name as arg") if(scalar(@args) != 1);
18 my $isheader = file_ext($args[0]) eq ".h";
19 my $self = {
20 cfile => $args[0],
21 isheader => $isheader,
22 printerrors => 0,
24 openbraces => 0,
25 incomment => 0,
26 line => "",
28 includes => [],
29 statics => [],
30 extern => [],
31 typedefs => [],
32 macros => [],
33 funcs => undef,
35 bless $self, $pkg;
38 sub addfunc {
39 my ($self, $funcname, $code) = @_;
40 $self->{funcs}->{$funcname} = $code;
43 sub handlesub {
44 my $self = shift;
45 my $_ = shift;
46 my $name = "";
47 my $wasstatic = 0;
48 while(!$name) {
49 my $x = 0;
50 $x++ while(substr($_, $x, 1) !~ /\s/);
51 my $word = substr($_, 0, $x);
52 my $extern = 1 if($word eq "extern");
53 if($word eq "static" || $word eq "inline") {
54 $_ = substr($_, $x);
55 s/^\s+//;
56 $wasstatic = 1 unless $extern;
57 next;
58 } else {
59 if(/(.*?)([\w_]+)\s*\(([\w\s_,\*\[\]\.\(\)]*?)\)\s*\{/
60 || ($self->{isheader} &&
61 /(.*?)([\w_]+)\s*\((.*?)\)\s*;/)
62 ) {
63 $name = $2;
64 my $decl = $1 . $name . "(" . $3 . ");";
65 push @{$self->{statics}}, $decl if($wasstatic);
66 #print $name , "\n" if $wasstatic;
67 $self->addfunc($name, $_);
68 #print "function $name\n$_";
69 } elsif($self->{isheader}) {
70 return;
71 } else {
72 warn "ERROR: $_\n" if $self->{printerrors};
73 return;
79 sub scanbraces {
80 my $self = shift;
81 my $shit = shift;
82 my @chars = split //, $shit;
83 for my $c(@chars) {
84 if ($c eq "{") {
85 $self->{openbraces}++;
86 } elsif($c eq "}") {
87 $self->{openbraces}--;
92 sub strip_macro {
93 my $x = shift;
94 $x =~ s/^\s*//;
95 $x =~ s/\s*$//;
96 $x =~ s/\s+/ /g;
97 return $x;
100 sub parseline {
101 my $self = shift;
102 $_ = shift;
103 #printf "parse line: %s, is header: %d\n", $_, $self->{isheader};
104 #print "PL: length line: ". length($line) . "\n";
105 return unless defined $_;
106 return if $_ eq "";
107 if(/^\s*#\s*(\w+)/) {
108 my $kw = $1;
109 if($kw eq "if" || $kw eq "ifdef" || $kw eq "elif" || $kw eq "else" || $kw eq "endif") {
110 push @{$self->{macros}}, strip_macro($_);
111 return;
113 # $self->{line} = "" if $self->{isheader};
114 # return;
116 if($_ =~ /extern \"C\"/) {
117 # $self->{line} = "";
118 return;
120 #$self->{line} .= $_ . "\n" if(!$self->{openbraces} || $self->{line} ne "");
121 #printf "%d\n", $self->{openbraces};
122 $self->{line} .= $_ . "\n" if(!$self->{openbraces} || $self->{line} ne "");
123 $self->scanbraces($_) unless $self->{line} =~ /^\s*#define/;
125 #print "$_ , line is $self->{line}\n";
127 if($self->{line} ne "" && !$self->{openbraces}) {
128 #print "A $self->{line}\n";
129 if($self->{line} =~ /^\s*#/) {
130 if($self->{line} =~ /\\\s*$/) {
132 } else {
133 push @{$self->{macros}}, strip_macro($self->{line});
134 $self->{line} = ""
136 } elsif($self->{line} =~ /([;\}]{1})\s*\n*$/) {
137 if($1 eq ";") {
138 #print $self->{line};
139 if ($self->{line} =~ /=/ || $self->{line} =~ /^\s*static[\s\n]+/) {
140 #print "extern!\n";
141 $self->{line} =~ s/^\s*static\s*//;
142 push @{$self->{extern}}, $self->{line};
143 } elsif($self->{isheader}) {
145 $self->{line} =~ /^\s*typedef\s+/
146 || $self->{line} =~ /^\s*union\s+/
147 || $self->{line} =~ /^\s*struct\s+/
149 push @{$self->{typedefs}}, strip_macro($self->{line});
150 } else {
151 $self->handlesub($self->{line});
153 } else {
154 push @{$self->{typedefs}}, $self->{line};
156 $self->{line} = "";
157 return;
159 $self->handlesub($self->{line});
160 $self->{line} = "";
162 } #elsif($self->{isheader} && !$self->{openbraces} && $self->{line} eq "" &&
163 # /(extern\w){0, 1}
166 sub parse {
168 my $self = shift;
170 my $f;
171 open($f, "<", $self->{cfile});
173 while(<$f>) {
175 # print;
176 chomp;
177 # print "$openbraces, $incomment\n";
178 if (/^\s*#\s*include\s+[<\"]{1}[\w_\-\/\.]+[>\"]{1}/) {
179 push @{$self->{includes}}, $_;
180 } else {
181 next if(/^\s*$/); #skip empty lines
182 next if(/^\s*\/\//); #skip one line comments.
183 # normal source code line.
184 if (!$self->{incomment} && /(.*?)\/\*(.*?)$/) {
185 $self->parseline($1);
186 my $rest = $2;
187 $self->{incomment} = 1 unless $rest =~ /\*\//;
188 } elsif($self->{incomment}) {
189 if(/\*\/(.*?)$/) {
190 $self->parseline($2);
191 $self->{incomment} = 0;
193 } else {
194 $self->parseline($_);
198 close $f;