- Continued on the new C parser.
[wine/hacks.git] / tools / winapi / c_parser.pm
blob87c880c6d5f5f437b12ac6b05e9f1d5b9cdb0463
1 package c_parser;
3 use strict;
5 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
6 require Exporter;
8 @ISA = qw(Exporter);
9 @EXPORT = qw();
10 @EXPORT_OK = qw();
12 use options qw($options);
13 use output qw($output);
15 use c_function;
17 ########################################################################
18 # new
20 sub new {
21 my $proto = shift;
22 my $class = ref($proto) || $proto;
23 my $self = {};
24 bless ($self, $class);
26 my $file = \${$self->{FILE}};
27 my $found_comment = \${$self->{FOUND_COMMENT}};
28 my $found_declaration = \${$self->{FOUND_DECLARATION}};
29 my $create_function = \${$self->{CREATE_FUNCTION}};
30 my $found_function = \${$self->{FOUND_FUNCTION}};
31 my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
32 my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
33 my $found_statement = \${$self->{FOUND_STATEMENT}};
34 my $found_variable = \${$self->{FOUND_VARIABLE}};
36 $$file = shift;
38 $$found_comment = sub { return 1; };
39 $$found_declaration = sub { return 1; };
40 $$create_function = sub { return new c_function; };
41 $$found_function = sub { return 1; };
42 $$found_function_call = sub { return 1; };
43 $$found_preprocessor = sub { return 1; };
44 $$found_statement = sub { return 1; };
45 $$found_variable = sub { return 1; };
47 return $self;
50 ########################################################################
51 # set_found_comment_callback
53 sub set_found_comment_callback {
54 my $self = shift;
56 my $found_comment = \${$self->{FOUND_COMMENT}};
58 $$found_comment = shift;
61 ########################################################################
62 # set_found_declaration_callback
64 sub set_found_declaration_callback {
65 my $self = shift;
67 my $found_declaration = \${$self->{FOUND_DECLARATION}};
69 $$found_declaration = shift;
72 ########################################################################
73 # set_found_function_callback
75 sub set_found_function_callback {
76 my $self = shift;
78 my $found_function = \${$self->{FOUND_FUNCTION}};
80 $$found_function = shift;
83 ########################################################################
84 # set_found_function_call_callback
86 sub set_found_function_call_callback {
87 my $self = shift;
89 my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
91 $$found_function_call = shift;
94 ########################################################################
95 # set_found_preprocessor_callback
97 sub set_found_preprocessor_callback {
98 my $self = shift;
100 my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
102 $$found_preprocessor = shift;
105 ########################################################################
106 # set_found_statement_callback
108 sub set_found_statement_callback {
109 my $self = shift;
111 my $found_statement = \${$self->{FOUND_STATEMENT}};
113 $$found_statement = shift;
116 ########################################################################
117 # set_found_variable_callback
119 sub set_found_variable_callback {
120 my $self = shift;
122 my $found_variable = \${$self->{FOUND_VARIABLE}};
124 $$found_variable = shift;
127 ########################################################################
128 # _parse_c
130 sub _parse_c {
131 my $self = shift;
133 my $pattern = shift;
134 my $refcurrent = shift;
135 my $refline = shift;
136 my $refcolumn = shift;
138 my $refmatch = shift;
140 local $_ = $$refcurrent;
141 my $line = $$refline;
142 my $column = $$refcolumn;
144 my $match;
145 if(s/^(?:$pattern)//s) {
146 $self->_update_c_position($&, \$line, \$column);
147 $match = $&;
148 } else {
149 return 0;
152 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
154 $$refcurrent = $_;
155 $$refline = $line;
156 $$refcolumn = $column;
158 $$refmatch = $match;
160 return 1;
163 ########################################################################
164 # _parse_c_error
166 sub _parse_c_error {
167 my $self = shift;
169 my $file = \${$self->{FILE}};
171 local $_ = shift;
172 my $line = shift;
173 my $column = shift;
174 my $context = shift;
176 my @lines = split(/\n/, $_);
178 my $current = "\n";
179 $current .= $lines[0] . "\n" || "";
180 $current .= $lines[1] . "\n" || "";
182 if($output->prefix) {
183 $output->write("\n");
184 $output->prefix("");
186 $output->write("$$file:$line." . ($column + 1) . ": $context: parse error: \\$current");
188 exit 1;
191 ########################################################################
192 # _parse_c_output
194 sub _parse_c_output {
195 my $self = shift;
197 local $_ = shift;
198 my $line = shift;
199 my $column = shift;
200 my $message = shift;
202 my @lines = split(/\n/, $_);
204 my $current = "\n";
205 $current .= $lines[0] . "\n" || "";
206 $current .= $lines[1] . "\n" || "";
208 $output->write("$line." . ($column + 1) . ": $message: \\$current");
211 ########################################################################
212 # _parse_c_until_one_of
214 sub _parse_c_until_one_of {
215 my $self = shift;
217 my $characters = shift;
218 my $refcurrent = shift;
219 my $refline = shift;
220 my $refcolumn = shift;
221 my $match = shift;
223 local $_ = $$refcurrent;
224 my $line = $$refline;
225 my $column = $$refcolumn;
227 if(!defined($match)) {
228 my $blackhole;
229 $match = \$blackhole;
232 $$match = "";
233 while(/^[^$characters]/s) {
234 my $submatch = "";
236 if(s/^[^$characters\n\t\'\"]*//s) {
237 $submatch .= $&;
240 if(s/^\'//) {
241 $submatch .= "\'";
242 while(/^./ && !s/^\'//) {
243 s/^([^\'\\]*)//s;
244 $submatch .= $1;
245 if(s/^\\//) {
246 $submatch .= "\\";
247 if(s/^(.)//s) {
248 $submatch .= $1;
249 if($1 eq "0") {
250 s/^(\d{0,3})//s;
251 $submatch .= $1;
256 $submatch .= "\'";
258 $$match .= $submatch;
259 $column += length($submatch);
260 } elsif(s/^\"//) {
261 $submatch .= "\"";
262 while(/^./ && !s/^\"//) {
263 s/^([^\"\\]*)//s;
264 $submatch .= $1;
265 if(s/^\\//) {
266 $submatch .= "\\";
267 if(s/^(.)//s) {
268 $submatch .= $1;
269 if($1 eq "0") {
270 s/^(\d{0,3})//s;
271 $submatch .= $1;
276 $submatch .= "\"";
278 $$match .= $submatch;
279 $column += length($submatch);
280 } elsif(s/^\n//) {
281 $submatch .= "\n";
283 $$match .= $submatch;
284 $line++;
285 $column = 0;
286 } elsif(s/^\t//) {
287 $submatch .= "\t";
289 $$match .= $submatch;
290 $column = $column + 8 - $column % 8;
291 } else {
292 $$match .= $submatch;
293 $column += length($submatch);
297 $$refcurrent = $_;
298 $$refline = $line;
299 $$refcolumn = $column;
300 return 1;
303 ########################################################################
304 # _update_c_position
306 sub _update_c_position {
307 my $self = shift;
309 local $_ = shift;
310 my $refline = shift;
311 my $refcolumn = shift;
313 my $line = $$refline;
314 my $column = $$refcolumn;
316 while($_) {
317 if(s/^[^\n\t\'\"]*//s) {
318 $column += length($&);
321 if(s/^\'//) {
322 $column++;
323 while(/^./ && !s/^\'//) {
324 s/^([^\'\\]*)//s;
325 $column += length($1);
326 if(s/^\\//) {
327 $column++;
328 if(s/^(.)//s) {
329 $column += length($1);
330 if($1 eq "0") {
331 s/^(\d{0,3})//s;
332 $column += length($1);
337 $column++;
338 } elsif(s/^\"//) {
339 $column++;
340 while(/^./ && !s/^\"//) {
341 s/^([^\"\\]*)//s;
342 $column += length($1);
343 if(s/^\\//) {
344 $column++;
345 if(s/^(.)//s) {
346 $column += length($1);
347 if($1 eq "0") {
348 s/^(\d{0,3})//s;
349 $column += length($1);
354 $column++;
355 } elsif(s/^\n//) {
356 $line++;
357 $column = 0;
358 } elsif(s/^\t//) {
359 $column = $column + 8 - $column % 8;
363 $$refline = $line;
364 $$refcolumn = $column;
367 ########################################################################
368 # parse_c_block
370 sub parse_c_block {
371 my $self = shift;
373 my $refcurrent = shift;
374 my $refline = shift;
375 my $refcolumn = shift;
377 my $refstatements = shift;
378 my $refstatements_line = shift;
379 my $refstatements_column = shift;
381 local $_ = $$refcurrent;
382 my $line = $$refline;
383 my $column = $$refcolumn;
385 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
387 my $statements;
388 if(s/^\{//) {
389 $column++;
390 $statements = "";
391 } else {
392 return 0;
395 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
397 my $statements_line = $line;
398 my $statements_column = $column;
400 my $plevel = 1;
401 while($plevel > 0) {
402 my $match;
403 $self->_parse_c_until_one_of("\\{\\}", \$_, \$line, \$column, \$match);
405 $column++;
407 $statements .= $match;
408 if(s/^\}//) {
409 $plevel--;
410 if($plevel > 0) {
411 $statements .= "}";
413 } elsif(s/^\{//) {
414 $plevel++;
415 $statements .= "{";
416 } else {
417 return 0;
421 $$refcurrent = $_;
422 $$refline = $line;
423 $$refcolumn = $column;
424 $$refstatements = $statements;
425 $$refstatements_line = $statements_line;
426 $$refstatements_column = $statements_column;
428 return 1;
431 ########################################################################
432 # parse_c_declaration
434 sub parse_c_declaration {
435 my $self = shift;
437 my $found_declaration = \${$self->{FOUND_DECLARATION}};
438 my $found_function = \${$self->{FOUND_FUNCTION}};
440 my $refcurrent = shift;
441 my $refline = shift;
442 my $refcolumn = shift;
444 local $_ = $$refcurrent;
445 my $line = $$refline;
446 my $column = $$refcolumn;
448 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
450 my $begin_line = $line;
451 my $begin_column = $column + 1;
453 my $end_line = $begin_line;
454 my $end_column = $begin_column;
455 $self->_update_c_position($_, \$end_line, \$end_column);
457 if(!&$$found_declaration($begin_line, $begin_column, $end_line, $end_column, $_)) {
458 return 1;
461 # Function
462 my $function = shift;
464 my $linkage = shift;
465 my $calling_convention = shift;
466 my $return_type = shift;
467 my $name = shift;
468 my @arguments = shift;
469 my @argument_lines = shift;
470 my @argument_columns = shift;
472 # Variable
473 my $type;
475 # $self->_parse_c_output($_, $line, $column, "declaration");
477 if(0) {
478 # Nothing
479 } elsif(s/^(?:DEFAULT|DECLARE)_DEBUG_CHANNEL\s*\(\s*(\w+)\s*\)\s*//s) { # FIXME: Wine specific kludge
480 $self->_update_c_position($&, \$line, \$column);
481 } elsif(s/^extern\s*\"(.*?)\"\s*//s) {
482 $self->_update_c_position($&, \$line, \$column);
483 my $declarations;
484 my $declarations_line;
485 my $declarations_column;
486 if(!$self->parse_c_block(\$_, \$line, \$column, \$declarations, \$declarations_line, \$declarations_column)) {
487 return 0;
489 if(!$self->parse_c_declarations(\$declarations, \$declarations_line, \$declarations_column)) {
490 return 0;
492 } elsif($self->parse_c_function(\$_, \$line, \$column, \$function)) {
493 if(&$$found_function($function))
495 my $statements = $function->statements;
496 my $statements_line = $function->statements_line;
497 my $statements_column = $function->statements_column;
499 if(defined($statements)) {
500 if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
501 return 0;
505 } elsif($self->parse_c_typedef(\$_, \$line, \$column)) {
506 # Nothing
507 } elsif($self->parse_c_variable(\$_, \$line, \$column, \$linkage, \$type, \$name)) {
508 # Nothing
509 } else {
510 $self->_parse_c_error($_, $line, $column, "declaration");
513 $$refcurrent = $_;
514 $$refline = $line;
515 $$refcolumn = $column;
517 return 1;
520 ########################################################################
521 # parse_c_declarations
523 sub parse_c_declarations {
524 my $self = shift;
526 my $refcurrent = shift;
527 my $refline = shift;
528 my $refcolumn = shift;
530 return 1;
533 ########################################################################
534 # parse_c_expression
536 sub parse_c_expression {
537 my $self = shift;
539 my $refcurrent = shift;
540 my $refline = shift;
541 my $refcolumn = shift;
543 my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
545 local $_ = $$refcurrent;
546 my $line = $$refline;
547 my $column = $$refcolumn;
549 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
551 if(s/^(.*?)(\w+\s*\()/$2/s) {
552 $column += length($1);
554 my $begin_line = $line;
555 my $begin_column = $column + 1;
557 my $name;
558 my @arguments;
559 my @argument_lines;
560 my @argument_columns;
561 if(!$self->parse_c_function_call(\$_, \$line, \$column, \$name, \@arguments, \@argument_lines, \@argument_columns)) {
562 return 0;
565 if($name =~ /^sizeof$/ ||
566 &$$found_function_call($begin_line, $begin_column, $line, $column, $name, \@arguments))
568 while(defined(my $argument = shift @arguments) &&
569 defined(my $argument_line = shift @argument_lines) &&
570 defined(my $argument_column = shift @argument_columns))
572 $self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
575 } elsif(s/^return//) {
576 $column += length($&);
577 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
578 if(!$self->parse_c_expression(\$_, \$line, \$column)) {
579 return 0;
581 } else {
582 return 0;
585 $self->_update_c_position($_, \$line, \$column);
587 $$refcurrent = $_;
588 $$refline = $line;
589 $$refcolumn = $column;
591 return 1;
594 ########################################################################
595 # parse_c_file
597 sub parse_c_file {
598 my $self = shift;
600 my $found_comment = \${$self->{FOUND_COMMENT}};
602 my $refcurrent = shift;
603 my $refline = shift;
604 my $refcolumn = shift;
606 local $_ = $$refcurrent;
607 my $line = $$refline;
608 my $column = $$refcolumn;
610 my $declaration = "";
611 my $declaration_line = $line;
612 my $declaration_column = $column;
614 my $previous_line = 0;
615 my $previous_column = -1;
617 my $blevel = 1;
618 my $plevel = 1;
619 while($plevel > 0 || $blevel > 0) {
620 my $match;
621 $self->_parse_c_until_one_of("#/\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
623 if($line == $previous_line && $column == $previous_column) {
624 # $self->_parse_c_error($_, $line, $column, "file: no progress");
626 $previous_line = $line;
627 $previous_column = $column;
629 # $self->_parse_c_output($_, $line, $column, "'$match'");
631 if(!$declaration && $match =~ s/^\s+//s) {
632 $self->_update_c_position($&, \$declaration_line, \$declaration_column);
634 $declaration .= $match;
636 if(/^[\#\/]/) {
637 my $blank_lines = 0;
638 if(s/^\#\s*//) {
639 my $preprocessor_line = $line;
640 my $preprocessor_column = $column;
642 my $preprocessor = $&;
643 while(s/^(.*?)\\\s*\n//) {
644 $blank_lines++;
645 $preprocessor .= "$1\n";
647 if(s/^(.*?)(\/[\*\/].*)?\n//) {
648 if(defined($2)) {
649 $_ = "$2\n$_";
650 } else {
651 $blank_lines++;
653 $preprocessor .= $1;
656 if(!$self->parse_c_preprocessor(\$preprocessor, \$preprocessor_line, \$preprocessor_column)) {
657 return 0;
661 if(s/^\/\*(.*?)\*\///s) {
662 &$$found_comment($line, $column + 1, "/*$1*/");
663 my @lines = split(/\n/, $1);
664 if($#lines > 0) {
665 $blank_lines += $#lines;
666 } else {
667 $column += length($1);
669 } elsif(s/^\/\/(.*?)\n//) {
670 &$$found_comment($line, $column + 1, "//$1");
671 $blank_lines++;
672 } elsif(s/^\///) {
673 $declaration .= $&;
676 $line += $blank_lines;
677 if($blank_lines > 0) {
678 $column = 0;
681 if(!$declaration) {
682 $declaration_line = $line;
683 $declaration_column = $column;
684 } else {
685 $declaration .= "\n" x $blank_lines;
688 next;
691 $column++;
692 if(s/^[\(\[]//) {
693 $plevel++;
694 $declaration .= $&;
695 } elsif(s/^[\)\]]//) {
696 $plevel--;
697 $declaration .= $&;
698 } elsif(s/^\{//) {
699 $blevel++;
700 $declaration .= $&;
701 } elsif(s/^\}//) {
702 $blevel--;
703 $declaration .= $&;
704 if($plevel == 1 && $blevel == 1 && $declaration !~ /^typedef/) {
705 if(!$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
706 return 0;
708 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
709 $declaration = "";
710 $declaration_line = $line;
711 $declaration_column = $column;
713 } elsif(s/^;//) {
714 if($plevel == 1 && $blevel == 1) {
715 if($declaration && !$self->parse_c_declaration(\$declaration, \$declaration_line, \$declaration_column)) {
716 return 0;
718 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
719 $declaration = "";
720 $declaration_line = $line;
721 $declaration_column = $column;
722 } else {
723 $declaration .= $&;
725 } elsif(/^\s*$/ && $declaration =~ /^\s*$/ && $match =~ /^\s*$/) {
726 $plevel = 0;
727 $blevel = 0;
728 } else {
729 $self->_parse_c_error($_, $line, $column, "file");
733 $$refcurrent = $_;
734 $$refline = $line;
735 $$refcolumn = $column;
737 return 1;
740 ########################################################################
741 # parse_c_function
743 sub parse_c_function {
744 my $self = shift;
746 my $file = \${$self->{FILE}};
747 my $create_function = \${$self->{CREATE_FUNCTION}};
749 my $refcurrent = shift;
750 my $refline = shift;
751 my $refcolumn = shift;
753 my $reffunction = shift;
755 local $_ = $$refcurrent;
756 my $line = $$refline;
757 my $column = $$refcolumn;
759 my $linkage = "";
760 my $calling_convention = "";
761 my $return_type;
762 my $name;
763 my @arguments;
764 my @argument_lines;
765 my @argument_columns;
766 my $statements;
767 my $statements_line;
768 my $statements_column;
770 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
772 my $begin_line = $line;
773 my $begin_column = $column + 1;
775 $self->_parse_c("inline", \$_, \$line, \$column);
776 $self->_parse_c("extern|static", \$_, \$line, \$column, \$linkage);
777 $self->_parse_c("inline", \$_, \$line, \$column);
778 if(!$self->parse_c_type(\$_, \$line, \$column, \$return_type)) {
779 return 0;
782 $self->_parse_c("__cdecl|__stdcall|CDECL|VFWAPIV|VFWAPI|WINAPIV|WINAPI|CALLBACK",
783 \$_, \$line, \$column, \$calling_convention);
784 if(!$self->_parse_c("\\w+", \$_, \$line, \$column, \$name)) {
785 return 0;
787 if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
788 return 0;
790 if($_ && !$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
791 return 0;
794 my $end_line = $line;
795 my $end_column = $column;
797 $$refcurrent = $_;
798 $$refline = $line;
799 $$refcolumn = $column;
801 my $function = &$$create_function;
803 $function->file($$file);
804 $function->begin_line($begin_line);
805 $function->begin_column($begin_column);
806 $function->end_line($end_line);
807 $function->end_column($end_column);
808 $function->linkage($linkage);
809 $function->return_type($return_type);
810 $function->calling_convention($calling_convention);
811 $function->name($name);
812 # if(defined($argument_types)) {
813 # $function->argument_types([@$argument_types]);
815 # if(defined($argument_names)) {
816 # $function->argument_names([@$argument_names]);
818 $function->statements_line($statements_line);
819 $function->statements_column($statements_column);
820 $function->statements($statements);
822 $$reffunction = $function;
824 return 1;
827 ########################################################################
828 # parse_c_function_call
830 sub parse_c_function_call {
831 my $self = shift;
833 my $refcurrent = shift;
834 my $refline = shift;
835 my $refcolumn = shift;
837 my $refname = shift;
838 my $refarguments = shift;
839 my $refargument_lines = shift;
840 my $refargument_columns = shift;
842 local $_ = $$refcurrent;
843 my $line = $$refline;
844 my $column = $$refcolumn;
846 my $name;
847 my @arguments;
848 my @argument_lines;
849 my @argument_columns;
851 if(s/^(\w+)(\s*)\(/\(/s) {
852 $column += length("$1$2");
854 $name = $1;
856 if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
857 return 0;
859 } else {
860 return 0;
863 $$refcurrent = $_;
864 $$refline = $line;
865 $$refcolumn = $column;
867 $$refname = $name;
868 @$refarguments = @arguments;
869 @$refargument_lines = @argument_lines;
870 @$refargument_columns = @argument_columns;
872 return 1;
875 ########################################################################
876 # parse_c_preprocessor
878 sub parse_c_preprocessor {
879 my $self = shift;
881 my $found_preprocessor = \${$self->{FOUND_PREPROCESSOR}};
883 my $refcurrent = shift;
884 my $refline = shift;
885 my $refcolumn = shift;
887 local $_ = $$refcurrent;
888 my $line = $$refline;
889 my $column = $$refcolumn;
891 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
893 my $begin_line = $line;
894 my $begin_column = $column + 1;
896 if(!&$$found_preprocessor($begin_line, $begin_column, "$_")) {
897 return 1;
900 if(0) {
901 # Nothing
902 } elsif(/^\#\s*define\s+(.*?)$/s) {
903 $self->_update_c_position($_, \$line, \$column);
904 } elsif(/^\#\s*else/s) {
905 $self->_update_c_position($_, \$line, \$column);
906 } elsif(/^\#\s*endif/s) {
907 $self->_update_c_position($_, \$line, \$column);
908 } elsif(/^\#\s*(?:if|ifdef|ifndef)?\s+(.*?)$/s) {
909 $self->_update_c_position($_, \$line, \$column);
910 } elsif(/^\#\s*include\s+(.*?)$/s) {
911 $self->_update_c_position($_, \$line, \$column);
912 } elsif(/^\#\s*undef\s+(.*?)$/s) {
913 $self->_update_c_position($_, \$line, \$column);
914 } else {
915 $self->_parse_c_error($_, $line, $column, "preprocessor");
918 $$refcurrent = $_;
919 $$refline = $line;
920 $$refcolumn = $column;
922 return 1;
925 ########################################################################
926 # parse_c_statement
928 sub parse_c_statement {
929 my $self = shift;
931 my $refcurrent = shift;
932 my $refline = shift;
933 my $refcolumn = shift;
935 my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
937 local $_ = $$refcurrent;
938 my $line = $$refline;
939 my $column = $$refcolumn;
941 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
943 if(s/^(?:case\s+)?(\w+)\s*://) {
944 $column += length($&);
945 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
948 # $output->write("$line.$column: '$_'\n");
950 if(/^$/) {
951 # Nothing
952 } elsif(/^\{/) {
953 my $statements;
954 my $statements_line;
955 my $statements_column;
956 if(!$self->parse_c_block(\$_, \$line, \$column, \$statements, \$statements_line, \$statements_column)) {
957 return 0;
959 if(!$self->parse_c_statements(\$statements, \$statements_line, \$statements_column)) {
960 return 0;
962 } elsif(/^(for|if|switch|while)(\s*)\(/) {
963 $column += length("$1$2");
964 my $name = $1;
966 $_ = "($'";
968 my @arguments;
969 my @argument_lines;
970 my @argument_columns;
971 if(!$self->parse_c_tuple(\$_, \$line, \$column, \@arguments, \@argument_lines, \@argument_columns)) {
972 return 0;
975 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
976 if(!$self->parse_c_statement(\$_, \$line, \$column)) {
977 return 0;
979 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
981 while(defined(my $argument = shift @arguments) &&
982 defined(my $argument_line = shift @argument_lines) &&
983 defined(my $argument_column = shift @argument_columns))
985 $self->parse_c_expression(\$argument, \$argument_line, \$argument_column);
987 } elsif(s/^else//) {
988 $column += length($&);
989 if(!$self->parse_c_statement(\$_, \$line, \$column)) {
990 return 0;
992 } elsif($self->parse_c_expression(\$_, \$line, \$column)) {
993 # Nothing
994 } else {
995 # $self->_parse_c_error($_, $line, $column, "statement");
998 $self->_update_c_position($_, \$line, \$column);
1000 $$refcurrent = $_;
1001 $$refline = $line;
1002 $$refcolumn = $column;
1004 return 1;
1007 ########################################################################
1008 # parse_c_statements
1010 sub parse_c_statements {
1011 my $self = shift;
1013 my $refcurrent = shift;
1014 my $refline = shift;
1015 my $refcolumn = shift;
1017 my $found_function_call = \${$self->{FOUND_FUNCTION_CALL}};
1019 local $_ = $$refcurrent;
1020 my $line = $$refline;
1021 my $column = $$refcolumn;
1023 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1025 my $statement = "";
1026 my $statement_line = $line;
1027 my $statement_column = $column;
1029 my $blevel = 1;
1030 my $plevel = 1;
1031 while($plevel > 0 || $blevel > 0) {
1032 my $match;
1033 $self->_parse_c_until_one_of("\\(\\)\\[\\]\\{\\};", \$_, \$line, \$column, \$match);
1035 # $output->write("'$match' '$_'\n");
1037 $column++;
1038 $statement .= $match;
1039 if(s/^[\(\[]//) {
1040 $plevel++;
1041 $statement .= $&;
1042 } elsif(s/^[\)\]]//) {
1043 $plevel--;
1044 if($plevel <= 0) {
1045 $self->_parse_c_error($_, $line, $column, "statements");
1047 $statement .= $&;
1048 } elsif(s/^\{//) {
1049 $blevel++;
1050 $statement .= $&;
1051 } elsif(s/^\}//) {
1052 $blevel--;
1053 $statement .= $&;
1054 if($blevel == 1) {
1055 if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
1056 return 0;
1058 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1059 $statement = "";
1060 $statement_line = $line;
1061 $statement_column = $column;
1063 } elsif(s/^;//) {
1064 if($plevel == 1 && $blevel == 1) {
1065 if(!$self->parse_c_statement(\$statement, \$statement_line, \$statement_column)) {
1066 return 0;
1069 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1070 $statement = "";
1071 $statement_line = $line;
1072 $statement_column = $column;
1073 } else {
1074 $statement .= $&;
1076 } elsif(/^\s*$/ && $statement =~ /^\s*$/ && $match =~ /^\s*$/) {
1077 $plevel = 0;
1078 $blevel = 0;
1079 } else {
1080 $self->_parse_c_error($_, $line, $column, "statements");
1084 $self->_update_c_position($_, \$line, \$column);
1086 $$refcurrent = $_;
1087 $$refline = $line;
1088 $$refcolumn = $column;
1090 return 1;
1093 ########################################################################
1094 # parse_c_tuple
1096 sub parse_c_tuple {
1097 my $self = shift;
1099 my $refcurrent = shift;
1100 my $refline = shift;
1101 my $refcolumn = shift;
1103 # FIXME: Should not write directly
1104 my $items = shift;
1105 my $item_lines = shift;
1106 my $item_columns = shift;
1108 local $_ = $$refcurrent;
1110 my $line = $$refline;
1111 my $column = $$refcolumn;
1113 my $item;
1114 if(s/^\(//) {
1115 $column++;
1116 $item = "";
1117 } else {
1118 return 0;
1121 my $item_line = $line;
1122 my $item_column = $column + 1;
1124 my $plevel = 1;
1125 while($plevel > 0) {
1126 my $match;
1127 $self->_parse_c_until_one_of("\\(,\\)", \$_, \$line, \$column, \$match);
1129 $column++;
1131 $item .= $match;
1132 if(s/^\)//) {
1133 $plevel--;
1134 if($plevel == 0) {
1135 push @$item_lines, $item_line;
1136 push @$item_columns, $item_column;
1137 push @$items, $item;
1138 $item = "";
1139 } else {
1140 $item .= ")";
1142 } elsif(s/^\(//) {
1143 $plevel++;
1144 $item .= "(";
1145 } elsif(s/^,//) {
1146 if($plevel == 1) {
1147 push @$item_lines, $item_line;
1148 push @$item_columns, $item_column;
1149 push @$items, $item;
1150 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1151 $item_line = $line;
1152 $item_column = $column + 1;
1153 $item = "";
1154 } else {
1155 $item .= ",";
1157 } else {
1158 return 0;
1162 $$refcurrent = $_;
1163 $$refline = $line;
1164 $$refcolumn = $column;
1166 return 1;
1169 ########################################################################
1170 # parse_c_type
1172 sub parse_c_type {
1173 my $self = shift;
1175 my $refcurrent = shift;
1176 my $refline = shift;
1177 my $refcolumn = shift;
1179 my $reftype = shift;
1181 local $_ = $$refcurrent;
1182 my $line = $$refline;
1183 my $column = $$refcolumn;
1185 my $type;
1187 $self->_parse_c("const", \$_, \$line, \$column);
1190 if(0) {
1191 # Nothing
1192 } elsif($self->_parse_c('ICOM_VTABLE\(.*?\)', \$_, \$line, \$column, \$type)) {
1193 # Nothing
1194 } elsif($self->_parse_c('\w+\s*(\*\s*)*', \$_, \$line, \$column, \$type)) {
1195 # Nothing
1196 } else {
1197 return 0;
1199 $type =~ s/\s//g;
1201 $$refcurrent = $_;
1202 $$refline = $line;
1203 $$refcolumn = $column;
1205 $$reftype = $type;
1207 return 1;
1210 ########################################################################
1211 # parse_c_typedef
1213 sub parse_c_typedef {
1214 my $self = shift;
1216 my $refcurrent = shift;
1217 my $refline = shift;
1218 my $refcolumn = shift;
1220 my $reftype = shift;
1222 local $_ = $$refcurrent;
1223 my $line = $$refline;
1224 my $column = $$refcolumn;
1226 my $type;
1228 if(!$self->_parse_c("typedef", \$_, \$line, \$column)) {
1229 return 0;
1232 $$refcurrent = $_;
1233 $$refline = $line;
1234 $$refcolumn = $column;
1236 $$reftype = $type;
1238 return 1;
1241 ########################################################################
1242 # parse_c_variable
1244 sub parse_c_variable {
1245 my $self = shift;
1247 my $found_variable = \${$self->{FOUND_VARIABLE}};
1249 my $refcurrent = shift;
1250 my $refline = shift;
1251 my $refcolumn = shift;
1253 my $reflinkage = shift;
1254 my $reftype = shift;
1255 my $refname = shift;
1257 local $_ = $$refcurrent;
1258 my $line = $$refline;
1259 my $column = $$refcolumn;
1261 $self->_parse_c_until_one_of("\\S", \$_, \$line, \$column);
1263 my $begin_line = $line;
1264 my $begin_column = $column + 1;
1266 my $linkage = "";
1267 my $type;
1268 my $name;
1270 $self->_parse_c("extern|static", \$_, \$line, \$column, \$linkage);
1271 if(!$self->parse_c_type(\$_, \$line, \$column, \$type)) { return 0; }
1272 if(!$self->_parse_c("\\w+", \$_, \$line, \$column, \$name)) { return 0; }
1274 $$refcurrent = $_;
1275 $$refline = $line;
1276 $$refcolumn = $column;
1278 $$reflinkage = $linkage;
1279 $$reftype = $type;
1280 $$refname = $name;
1282 if(&$$found_variable($begin_line, $begin_column, $linkage, $type, $name))
1284 # Nothing
1287 return 1;