factor out parser code into a standalone, reusable module
[rofl0r-c-split.git] / CParser.pm
blob395c266fec09372320360df36ab35ab61ea7a6ff
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_macros => [],
32 funcs => undef,
34 bless $self, $pkg;
37 sub addfunc {
38 my ($self, $funcname, $code) = @_;
39 $self->{funcs}->{$funcname} = $code;
42 sub handlesub {
43 my $self = shift;
44 my $_ = shift;
45 my $name = "";
46 my $wasstatic = 0;
47 while(!$name) {
48 my $x = 0;
49 $x++ while(substr($_, $x, 1) !~ /\s/);
50 my $word = substr($_, 0, $x);
51 my $extern = 1 if($word eq "extern");
52 if($word eq "static" || $word eq "inline") {
53 $_ = substr($_, $x);
54 s/^\s+//;
55 $wasstatic = 1 unless $extern;
56 next;
57 } else {
58 if(/(.*?)([\w_]+)\s*\(([\w\s_,\*\[\]\.\(\)]*?)\)\s*\{/
59 || ($self->{isheader} &&
60 /(.*?)([\w_]+)\s*\((.*?)\)\s*;/)
61 ) {
62 $name = $2;
63 my $decl = $1 . $name . "(" . $3 . ");";
64 push @{$self->{statics}}, $decl if($wasstatic);
65 #print $name , "\n" if $wasstatic;
66 $self->addfunc($name, $_);
67 #print "function $name\n$_";
68 } elsif($self->{isheader}) {
69 return;
70 } else {
71 warn "ERROR: $_\n" if $self->{printerrors};
72 return;
78 sub scanbraces {
79 my $self = shift;
80 my $shit = shift;
81 my @chars = split //, $shit;
82 for my $c(@chars) {
83 if ($c eq "{") {
84 $self->{openbraces}++;
85 } elsif($c eq "}") {
86 $self->{openbraces}--;
91 sub parseline {
92 my $self = shift;
93 $_ = shift;
94 #printf "parse line: %s, is header: %d\n", $_, $self->{isheader};
95 #print "PL: length line: ". length($line) . "\n";
96 return unless defined $_;
97 return if $_ eq "";
98 if(/^\s*#\s*(\w+)/) {
99 my $kw = $1;
100 if($kw eq "if" || $kw eq "ifdef" || $kw eq "elif" || $kw eq "else" || $kw eq "endif") {
101 push @{$self->{typedefs_macros}}, $_;
102 return;
104 # $self->{line} = "" if $self->{isheader};
105 # return;
107 if($_ =~ /extern \"C\"/) {
108 # $self->{line} = "";
109 return;
111 #$self->{line} .= $_ . "\n" if(!$self->{openbraces} || $self->{line} ne "");
112 #printf "%d\n", $self->{openbraces};
113 $self->{line} .= $_ . "\n" if(!$self->{openbraces} || $self->{line} ne "");
114 $self->scanbraces($_) unless $self->{line} =~ /^\s*#define/;
116 #print "$_ , line is $self->{line}\n";
118 if($self->{line} ne "" && !$self->{openbraces}) {
119 #print "A $self->{line}\n";
120 if($self->{line} =~ /^\s*#/) {
121 if($self->{line} =~ /\\\s*$/) {
123 } else {
124 push @{$self->{typedefs_macros}}, $self->{line};
125 $self->{line} = ""
127 } elsif($self->{line} =~ /([;\}]{1})\s*\n*$/) {
128 if($1 eq ";") {
129 #print $self->{line};
130 if ($self->{line} =~ /=/ || $self->{line} =~ /^\s*static[\s\n]+/) {
131 #print "extern!\n";
132 $self->{line} =~ s/^\s*static\s*//;
133 push @{$self->{extern}}, $self->{line};
134 } elsif($self->{isheader}) {
135 $self->handlesub($self->{line});
136 } else {
137 push @{$self->{typedefs_macros}}, $self->{line};
139 $self->{line} = "";
140 return;
142 $self->handlesub($self->{line});
143 $self->{line} = "";
145 } #elsif($self->{isheader} && !$self->{openbraces} && $self->{line} eq "" &&
146 # /(extern\w){0, 1}
149 sub parse {
151 my $self = shift;
153 my $f;
154 open($f, "<", $self->{cfile});
156 while(<$f>) {
158 # print;
159 chomp;
160 # print "$openbraces, $incomment\n";
161 if (/^\s*#\s*include\s+[<\"]{1}[\w_\-\/\.]+[>\"]{1}/) {
162 push @{$self->{includes}}, $_;
163 } else {
164 next if(/^\s*$/); #skip empty lines
165 next if(/^\s*\/\//); #skip one line comments.
166 # normal source code line.
167 if (!$self->{incomment} && /(.*?)\/\*(.*?)$/) {
168 $self->parseline($1);
169 my $rest = $2;
170 $self->{incomment} = 1 unless $rest =~ /\*\//;
171 } elsif($self->{incomment}) {
172 if(/\*\/(.*?)$/) {
173 $self->parseline($2);
174 $self->{incomment} = 0;
176 } else {
177 $self->parseline($_);
181 close $f;