File Coverage

blib/lib/Hardware/Verilog/Parser.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             ##################################################################
2             # Copyright (C) 2000 Greg London All Rights Reserved.
3             # This program is free software; you can redistribute it and/or
4             # modify it under the same terms as Perl itself.
5             ##################################################################
6              
7              
8             ##################################################################
9             package Hardware::Verilog::Parser;
10 1     1   17273 use PrecompiledParser;
  0            
  0            
11             use Parse::RecDescent;
12             use vars qw ( $VERSION @ISA);
13             @ISA = ( 'PrecompiledParser' , 'Parse::RecDescent' );
14             ##################################################################
15             $VERSION = '0.13';
16             ##################################################################
17              
18             ##################################################################
19             ##################################################################
20             ##################################################################
21             ##################################################################
22              
23             use Benchmark;
24              
25             ##################################################################
26             sub new
27             ##################################################################
28             {
29             my ($pkg) = @_;
30              
31             my $parser = PrecompiledParser->new();
32              
33             # bless it as a verilog_parser object
34             bless $parser, $pkg;
35             return $parser;
36             }
37              
38              
39              
40              
41             #########################################################################
42             sub decomment_given_text
43             #########################################################################
44             {
45             my ($obj,$text)=@_;
46              
47             my $filtered_text='';
48              
49             my $state = 'code';
50              
51             my ( $string_prior_to_line_comment, $string_after_line_comment);
52             my ( $string_prior_to_block_comment, $string_after_block_comment);
53             my ( $string_prior_to_quote, $string_after_quote);
54             my ( $comment_string, $string_after_comment);
55             my ( $quoted_string, $string_after_quoted_string);
56              
57             my $index_to_line_comment=0;
58             my $index_to_block_comment=0;
59             my $index_to_quote =0;
60             my $lc_lt_bc;
61             my $lc_lt_q;
62             my $bc_lt_q;
63             my $bc_lt_lc;
64             my $q_lt_lc;
65             my $q_lt_bc;
66              
67             my $could_be_line_comment;
68             my $could_be_block_comment;
69             my $could_be_quote;
70              
71             while (1)
72             {
73             #print "#################################################### \n";
74             #print "state = $state \n";
75             if ($state eq 'code')
76             {
77              
78             unless ( ($text =~ /\/\*/) or ($text =~ /\/\//) or ($text =~ /\"/) )
79             {
80             $filtered_text .= $text ;
81             last;
82             }
83              
84              
85             # look for comment or quoted string
86             ( $string_prior_to_line_comment, $string_after_line_comment)
87             = split( '//' , $text, 2 );
88              
89             ( $string_prior_to_block_comment, $string_after_block_comment)
90             = split( /\/\*/ , $text, 2 );
91              
92             ( $string_prior_to_quote, $string_after_quote)
93             = split( /\"/ , $text, 2 );
94              
95             $index_to_line_comment = length($string_prior_to_line_comment);
96             $index_to_block_comment = length($string_prior_to_block_comment);
97             $index_to_quote = length($string_prior_to_quote );
98              
99             $lc_lt_bc = ($index_to_line_comment < $index_to_block_comment);
100             $lc_lt_q = ($index_to_line_comment < $index_to_quote);
101              
102             $bc_lt_q = ($index_to_block_comment < $index_to_quote);
103             $bc_lt_lc = ($index_to_block_comment < $index_to_line_comment);
104              
105             $q_lt_lc = ($index_to_quote < $index_to_line_comment);
106             $q_lt_bc = ($index_to_quote < $index_to_block_comment);
107            
108            
109              
110             #print "length_remaining_text = $length_of_entire_text \n";
111             #print " line_comment index=$index_to_line_comment ". "text= $string_prior_to_line_comment \n";
112             #print "block_comment index=$index_to_block_comment "."text= $string_prior_to_block_comment \n";
113             #print "quote index=$index_to_quote ". "text= $string_prior_to_quote \n";
114             #print "\n";
115              
116             if($lc_lt_bc and $lc_lt_q)
117             {
118             $state = 'linecomment';
119             $filtered_text .= $string_prior_to_line_comment;
120             $text = '//' . $string_after_line_comment;
121             }
122              
123             elsif($bc_lt_q and $bc_lt_lc)
124             {
125             $state = 'blockcomment';
126             $filtered_text .= $string_prior_to_block_comment;
127             $text = '/*' . $string_after_block_comment;
128             }
129              
130             elsif($q_lt_lc and $q_lt_bc)
131             {
132             $state = 'quote';
133             $filtered_text .= $string_prior_to_quote;
134             $text = $string_after_quote;
135             $filtered_text .= '"' ;
136             }
137             }
138              
139             elsif ($state eq 'linecomment')
140             {
141             # strip out everything from here to the next \n charater
142             ( $comment_string, $string_after_comment)
143             = split( /\n/ , $text, 2 );
144              
145             $text = "\n" . $string_after_comment;
146              
147             $state = 'code';
148             }
149              
150             elsif ($state eq 'blockcomment')
151             {
152             # strip out everything from here to the next */ pattern
153             ( $comment_string, $string_after_comment)
154             = split( /\*\// , $text, 2 );
155              
156             $comment_string =~ s/[^\n]//g;
157              
158             $text = $comment_string . $string_after_comment;
159              
160             $state = 'code';
161             }
162              
163             elsif ($state eq 'quote')
164             {
165             # get the text until the next quote mark and keep it as a string
166             ( $quoted_string, $string_after_quoted_string)
167             = split( /"/ , $text, 2 );
168              
169             $filtered_text .= $quoted_string . '"' ;
170             $text = $string_after_quoted_string;
171              
172             $state = 'code';
173             }
174             }
175              
176              
177             return $filtered_text;
178              
179             }
180              
181              
182             #########################################################################
183             #
184             # the %define_hash variable keeps track of all `define values.
185             # it is class level variable because it needs to keep track of
186             # `defines that may cross file boundaries due to `includes.
187             # i.e.
188             # main.v
189             # `include "defines.inc"
190             # wire [`width:1] mywire;
191             #
192             # defines.inc
193             # `define width 8
194             #
195             # since each included file calls filename_to_text, which in turn
196             # calls convert_compiler_directives_in_text, the %define_hash cannot
197             # be declared inside convert_compiler_directives_in_text because it
198             # will cease to exist once the included file is spliced in.
199             # for `defines to exists after the included file, the define_hash
200             # must be class level data.
201             # it could be stored in $obj->{'define_hash'}, but that seems overkill.
202             #
203             #########################################################################
204             my %define_hash;
205              
206             #########################################################################
207             sub convert_compiler_directives_in_text
208             #########################################################################
209             {
210             my ($obj,$text)=@_;
211              
212             return $text unless ($text=~/`/);
213              
214             my $filtered_text='';
215              
216             my ( $string_prior_to_tick, $string_after_tick);
217              
218             my $temp_string;
219             my ($key, $value);
220             my $sub_string;
221              
222             while(1)
223             {
224             unless ($text =~ /`/)
225             {
226             $filtered_text .= $text ;
227             last;
228             }
229              
230              
231             ( $string_prior_to_tick, $string_after_tick)
232             = split( '`' , $text, 2 );
233              
234             $filtered_text .= $string_prior_to_tick;
235              
236             # if define
237             if ($string_after_tick =~ /^define/)
238             {
239             $string_after_tick =~ /^define\s+(.*)\n/;
240             $temp_string = $1;
241             ($key, $value) = split(/\s+/, $temp_string, 2);
242             $define_hash{$key}=$value;
243              
244             #print "defining key=$key value=$value \n";############
245              
246             $sub_string = '^define\s+'.$temp_string;
247              
248             $string_after_tick =~ s/$sub_string//;
249             $text = $string_after_tick;
250             }
251              
252             # else if `undef
253             elsif ($string_after_tick =~ /^undef/)
254             {
255             $string_after_tick =~ /^undef\s+(\w+)\n/;
256             $key = $1;
257             $temp_string = '^undef\s+'.$key;
258             $string_after_tick =~ s/$temp_string//;
259              
260             $define_hash{$key}=undef;
261             $text = $string_after_tick;
262              
263             #print "undefining key=$key \n";#########
264             }
265              
266             # else if `include
267             elsif ($string_after_tick =~ /^include/)
268             {
269             $string_after_tick =~ /^include\s+(.*)\n/;
270             $temp_string = $1;
271              
272             $sub_string = '^include\s+'.$temp_string;
273             $string_after_tick =~ s/$sub_string//;
274              
275             $temp_string =~ s/"//g;
276             # print "including file $temp_string\n";
277             $string_after_tick =
278             $obj->filename_to_text($temp_string) .
279             $string_after_tick;
280              
281             $text = $string_after_tick;
282             }
283              
284             # else if `timescale
285             elsif ($string_after_tick =~ /^timescale/)
286             {
287             $string_after_tick =~ s/^timescale.*//;
288              
289             $text = $string_after_tick;
290             }
291              
292             # else if `celldefine
293             elsif ($string_after_tick =~ /^celldefine/)
294             {
295             $string_after_tick =~ s/^celldefine.*//;
296              
297             $text = $string_after_tick;
298             }
299              
300             # else if `endcelldefine
301             elsif ($string_after_tick =~ /^endcelldefine/)
302             {
303             $string_after_tick =~ s/^endcelldefine.*//;
304              
305             $text = $string_after_tick;
306             }
307              
308             # else if `suppress_faults
309             elsif ($string_after_tick =~ /^suppress_faults/)
310             {
311             $string_after_tick =~ s/^suppress_faults.*//;
312              
313             $text = $string_after_tick;
314             }
315              
316             # else if `enable_portfaults
317             elsif ($string_after_tick =~ /^enable_portfaults/)
318             {
319             $string_after_tick =~ s/^enable_portfaults.*//;
320              
321             $text = $string_after_tick;
322             }
323              
324             # else if `disable_portfaults
325             elsif ($string_after_tick =~ /^disable_portfaults/)
326             {
327             $string_after_tick =~ s/^disable_portfaults.*//;
328              
329             $text = $string_after_tick;
330             }
331              
332             # else if `suppress_faults
333             elsif ($string_after_tick =~ /^suppress_faults/)
334             {
335             $string_after_tick =~ s/^suppress_faults.*//;
336              
337             $text = $string_after_tick;
338             }
339              
340             # else if `nosuppress_faults
341             elsif ($string_after_tick =~ /^nosuppress_faults/)
342             {
343             $string_after_tick =~ s/^nosuppress_faults.*//;
344              
345             $text = $string_after_tick;
346             }
347              
348             # else if `ifdef
349             elsif ($string_after_tick =~ /^ifdef/)
350             {
351             $string_after_tick =~ /^ifdef\s+(.*)\n/;
352             $key = $1;
353             $string_after_tick =~ s/^ifdef\s+(.*)\n//;
354             $text = $string_after_tick;
355              
356             my ($conditional_text,$text_after_conditional)
357             = split( '`endif' , $text, 2 );
358              
359             my ($true_text, $false_text);
360              
361             if( $conditional_text =~ /`else/ )
362             {
363             ($true_text, $false_text) =
364             split('`else', $conditional_text, 2);
365              
366             }
367             else
368             {
369             $true_text = $conditional_text;
370             $false_text = '';
371              
372             }
373              
374              
375              
376              
377             if(defined($define_hash{$key}))
378             {
379             $text = $true_text . $text_after_conditional;
380             }
381             else
382             {
383             $text = $false_text . $text_after_conditional;
384             }
385             }
386              
387              
388             # else must be a defined constant, replace `NAME with $value
389             else
390             {
391             $string_after_tick =~ /^(\w+)/;
392             my $key = $1;
393             unless( defined($define_hash{$key}) )
394             {die "undefined macro `$key\n";}
395             $string_after_tick =~ s/$key//;
396             $value = $define_hash{$key};
397            
398             $filtered_text .= $value;
399              
400             $text = $string_after_tick;
401             #print "replacing key=$key value=$value\n";#######
402              
403             }
404             }
405              
406             return $filtered_text;
407             }
408              
409             #########################################################################
410             sub Filename
411             #########################################################################
412             {
413             my $obj = shift;
414              
415             while(@_)
416             {
417             my $filename = shift;
418             print "\n\nparsing filename $filename \n\n\n";
419             print STDERR "\n\nparsing filename $filename \n\n\n";
420             my $text = $obj->filename_to_text($filename);
421              
422             #print "\n\n\ntext to parse is \n$text\n\n\n\n";
423              
424              
425             my $tstart = new Benchmark;
426             $obj->design_file($text);
427             my $tstop = new Benchmark;
428              
429             if(1)
430             {
431             my $line_count = $obj->count_number_of_lines($text);
432             print "line count is $line_count\n";
433            
434             $t = timediff($tstop,$tstart);
435             my $time_string = timestr($t);
436             print "timit result is ", $time_string , "\n";
437              
438             my $cpu_sec;
439             $time_string =~ /(\d+\.\d+) usr/;
440             $cpu_sec = $1;
441             if(defined($cpu_sec))
442             {
443             if($cpu_sec<0.99)
444             {$cpu_sec = 1;}
445              
446             print "using $cpu_sec seconds parse time\n";
447             $lines_per_second = $line_count / $cpu_sec ;
448             $lines_per_second_two_dec_places =
449             sprintf("%10.2f", $lines_per_second);
450             print "parse_rate is $lines_per_second_two_dec_places lines/sec ";
451             print sprintf (" ( %12d / %10.2f ) ", $line_count, $cpu_sec);
452             print " $filename ";
453             print "\n";
454             }
455             else
456             {
457             warn "could not extract cpu time\n";
458             $cpu_sec = 10000000;
459             }
460             }
461             }
462             }
463              
464             #########################################################################
465             sub count_number_of_lines
466             #########################################################################
467             #
468             {
469             my ($obj,$text)=@_;
470             my @list = split(/\n/,$text);
471             my $val = @list;
472             return $val;
473             }
474              
475              
476             #########################################################################
477             sub SearchPath
478             #########################################################################
479             {
480             my $obj = shift;
481             my @path;
482             if(@_)
483             {
484             while(@_)
485             {
486             push(@path,shift(@_));
487             }
488             $obj->{'SearchPath'} = \@path;
489             }
490             @path = @{$obj->{'SearchPath'}};
491             return @path;
492             }
493              
494             #########################################################################
495             sub search_paths_for_filename
496             #########################################################################
497             {
498             my ($obj,$filename)=@_;
499              
500             # if filename contains any '/' or '\' characters,
501             # assume it already contains a path. dont bother with search.
502             if ( ($filename =~ /\//) or ($filename =~ /\\/) )
503             {
504             return $filename;
505             }
506              
507             # if no search path specified, dont bother looking.
508             unless(defined($obj->{'SearchPath'}))
509             {
510             return $filename;
511             }
512              
513             # get search path, go through each entry,
514             # see if file exists in that area.
515             my @paths = @{$obj->{'SearchPath'}};
516             foreach my $path (@paths)
517             {
518             if(-e $path.$filename)
519             {
520             print "found $filename in path $path \n";
521             return $path.$filename;
522             }
523             }
524              
525             # couldn't find it, report error
526             my $string = "Could not find $filename in search path: ";
527             foreach my $path (@paths)
528             {
529             $string .= " $path, ";
530             }
531             $string .= "\n";
532             die $string;
533            
534             }
535              
536             #########################################################################
537             sub filename_to_text
538             #########################################################################
539             #
540             {
541             my ($obj,$filename)=@_;
542             my $full_path_name = $obj->search_paths_for_filename($filename);
543             open (FILE, $full_path_name) or
544             die "Cannot open file for reading: $full_path_name\n";
545             my $text;
546             while()
547             {
548             $text .= $_;
549             }
550              
551             $text = $obj->decomment_given_text($text);
552             $text = $obj->convert_compiler_directives_in_text($text);
553              
554             return $text;
555             }
556              
557              
558             ##################################################################
559             ##################################################################
560             ##################################################################
561             ##################################################################
562              
563              
564              
565              
566             ##################################################################
567             ##################################################################
568             ##################################################################
569             ##################################################################
570              
571             1;
572              
573             ##################################################################
574             ##################################################################
575             ##################################################################
576             ##################################################################
577              
578             __END__