Verilog代码自动缩进和对齐Perl脚本(更新)

实验室做FPGA开发时经常用到Verilog,代码规范成为一个问题,于是乎写了一个Perl脚本对代码进行规范化,主要是进行自动缩进和对齐。

代码原理很简单,主要是使用了正则表达式进行匹配和替换。

(新更新的代码增加了增加了变量名长度检测, 增加了module名检测, 对未加begin...end的always进行添加的功能)

代码如下,初学Perl,请读者赐教:

use 5.010;
use File::Basename;

my $filename = 'C:\Users\CvCv\Desktop\Perl_tmp\code.v';#输入文件名
my $outfilename = 'C:\Users\CvCv\Desktop\Perl_tmp\out.v';#输出文件名
my $basename = basename($filename,".v");
#----------------------------------------------------------
#测试文件存在
die "文件$filename不存在!\n" unless -e $filename;
#打开文件
open(VFILE,"<",$filename) || die "打开文件失败!\n";
open(OFILE,">",$outfilename) || die "打开文件失败!\n";
#----------------------------------------------------------
#对文件预处理,begin...end if...else if...begin等在一行的改成两行
#未添加begin...end的always块进行添加
$always_cnt = 0;
my $last_line = "";
while(<VFILE>){
	chomp;#去除行尾的\n
	
	if(/(.*if.*)(begin.*)/i){
		push @content,$1;
		push @content,$2;
		$last_line = $2;
	}
	elsif(/(.*begin.*)(if.*)/i){
		push @content,$1;
		push @content,$2;
		$last_line = $2;
	}
	elsif(/\s*((input|output|reg|wire|(?:output\s+reg))\s*(\[.+\:.+\])?\s*)((?!reg|wire)(?:(\w+)\s*,\s*(\w+)))([,;]?)/){
		#对于单行定义多个变量进行换行处理
		push @content, $1." ".$5.";";
		push @content, $1." ".$6.";";
		$last_line = $2;
	}
	elsif(/^\s*$/){#空行
		#删除空行
		#say $last_line;
	}
	elsif(/always|module|endmodule|assign|initial/i){#匹配到always		
		if($last_line =~ /\s*\S+$/ or $last_line =~ /^$/){
			#上一行不是空格,就添加一个空行
			push @content,"";
		}
		push @content,$_;
		$last_line = $_;
	}
	elsif(/\bif\s*\(/i){#匹配到if
		if($last_line =~ /always/){
			#上一行是always
			$always_cnt = 1;
			push @content,"begin";
		}
		push @content,$_;
		$last_line = $_;
	}
	else{
		push @content,$_;
		$last_line = $_;
	}
}
$always_cnt = 0;
#print join("\n",@content);

#----------------------------------------------------------
#变量定义
$begin_cnt = 0;
$if_cnt = 0;
$autoindent_space = " "x4;#自动缩进的空格数(Tab宽度)
$last_line = "";
$assign_start = 0;
#模块定义开始
$module_def_start = 0;
my $module_cnt = 0;

#==========================================================
#读取并处理文件
#while(<VFILE>){
foreach (@content){
	#print $begin_cnt,$_,"\n";
	$line = $_;
	if($assign_start){
		if(/.*;/){
			$assign_start = 0;
		}
	}
	if(/\s*\b(input|output|reg|wire)\b/i){
		$line =~ s/^\s+//;
		my @result = ($line =~ /\s*(input|output|reg|wire|(?:output\s+reg))\s*(\[.+\:.+\])?\s*((?!reg|wire)\w+)\s*([,;]?)/ig);
		#print length($result[0]),"--@result\n";
		if($#result>0){
			$line = $autoindent_space;
			$line .= $result[0]." "x(20-length($result[0]));
			$line .= $result[1]." "x(20-length($result[1]));
			$line .= $result[2]." "x(20-length($result[2]));
			$line .= $result[3];
			if((my $len = length($result[2]))>20){
				print "变量名过长(实际长度$len>20字符):\t$result[2]\n";
			}
		}
	}
	elsif(/(parameter)?\s*(\w+)\s*\=\s*((?:\d+\'[hbHB][0-9a-fA-F_]+)|(?:\d+))\s*([,;]?)/i){
		$line =~ s/^\s+//;
		my @result = ($line =~ /(parameter)?\s*(\w+)\s*\=\s*((?:\d+\'[hbHB][0-9a-fA-F_]+)|(?:\d+))\s*([,;]?)/ig);
		#print $#result."--@result\n";
		if($#result>0){
			$line = $autoindent_space;
			$line .= $result[0]." "x(20-length($result[0]));
			$line .= $result[1]." "x(35-length($result[1]));
			$line .= "= ".$result[2]." "x(18-length($result[2]));
			$line .= $result[3];
		}
	}	
	elsif(/\s*\b(module|endmodule|assign|initial)\b/i){#匹配到module|always|assign
		$line =~ s/^\s+//;
		if(/\s*\b(assign|initial)\b\s+\w/i){#匹配到assign
			$line =~ s/\s*\b(assign|initial)\b\s+(\w)/$1  $2/i;
			$assign_start = 1;
			#print;
		}
		if(/module\s+(\w+)\s*\(/i){
			#未匹配到分号,表示module输入输出定义多行
			if(!/.*;/){
				$module_def_start = 1;
				$line = "\n//--------------start of module define--------------\n".$line;
			}
			$module_cnt++;
			if($module_cnt>1){
				print "文件存在多个module\n";
			}			
			if($basename ne $1){
				print "module名$1和文件名$basename不一致!\n";
			}
		}		
	}
	elsif(/\bbegin\b/i){#匹配到begin
		my $tmp_space = $autoindent_space x $begin_cnt;
		$begin_cnt++;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/\bend\b/i){#匹配到end
		if($if_cnt>0){
			$if_cnt--;
		}
		my $tmp_space = $autoindent_space x ($begin_cnt-1);
		$begin_cnt>0 && $begin_cnt--;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/if\s*\(/i){#匹配到if
		$if_cnt++;
		my $tmp_space = $autoindent_space x $begin_cnt;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/\belse\s*/i){#匹配到else
		my $tmp_space = $autoindent_space x $begin_cnt;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/always/){
		$always_cnt=1;
		$line =~ s/^\s*/$tmp_space/;
	}
	elsif(/^\s*$/){#匹配到空行
		#say "="x20;
		#always结束的空行(代码中间的空行已经删除)
		if($if_cnt==0 && $begin_cnt==1 && $always_cnt==1){
			#加入always的end
			$line = "end\n";
			$begin_cnt=0;
			$always_cnt=0;
		}
	}
	else{
		if($last_line =~ /(\s+if\s*\()|(\belse\s*)|(^\s*\w+\:\s*)/){#上一行是if/else/case分支
			$if_cnt>0 && $if_cnt--;
			my $tmp_space = $autoindent_space x ($begin_cnt+1);
			$line =~ s/^\s*/$tmp_space/;
		}
		else{
			my $tmp_space = $autoindent_space x $begin_cnt;
			$line =~ s/^\s*/$tmp_space/;
		}
		if($module_def_start)
		{
			if(/.*;/){
				#最后一行module定义
				$line = ($autoindent_space x 4).$line;
				$line .= "\n//--------------end of module define--------------\n";
				$module_def_start = 0;
			}
			else{
				$line = ($autoindent_space x 4).$line;
			}
		}
		if($assign_start){
			#print "*"x5;
			#$always_cnt=0;
			my $tmp_space = $autoindent_space x 2;
			$line =~ s/^\s*/$tmp_space/;
			if(/".*;\s*$"/){
				$assign_start = 0;
			}
			#say $line;
		}
		
	}
	$last_line = $line;
	#say $if_cnt."-".$begin_cnt."-".$always_cnt."--".$line;
	$text.=$line."\n";
}

#关闭文件
close VFILE;
select OFILE;
print $text;
close OFILE;
select STDOUT;
print "-"x40,"\n"."处理完毕,文件输出到$outfilename\n";


==================================================================================

效果预览:




相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页