アットウィキロゴ

perll

#!/usr/bin/perl

use strict;
use FileHandle;


my $file = $ARGV[0];
my $lines=[];
my $num;
{
my $line="\r";
my $fh = FileHandle->new($file);
(chomp, $line .= "$_\r") while <$fh>;
$fh->close;
$_ = $line;

s {/\*.*?\*/} [\r]gsx;		# コメント
s/\/\/.*\r/\r/gsm;			# コメント(C++)
s/\r\s*([^\r])/\r$1/gsm;	# ブランク削除
s/([^\r])\s*\r/$1\r/gsm;	# ブランク削除
s/[\t ]*\\\r//gsm;			# \cr を消す

# インクルードを消す
s/\#(include|undef)[^\r]*//gsm;
# print("$_\n") foreach(/(\#define[^\r]*)/gsm);
# print("$_\n") foreach(/\#define[^\r]*\{[^\r]*\}/gsm);
s/\#define([^\r]*)\{([^\r]*)\}/define$1\{\r$2\r\}/gsm;
s/\#define[^\r]*//gsm;

# 変数宣言を消す
s/\r\w+(?:\s+\w+)*(?:\s+|\s*\*\s*)[\w\[\]]+;//gsm;
# キャストを消す
s/(?:\*\s*)?\([\w\s\*&]*\)\s*&//gs;
# 変数宣言+初期化
s/\r\w+\s+([\w\[\]]+\s*=\s*[\w\{\}]+\s*[\w\[\]]*\s*;)/\r$1/gsm;
s/(?:\*\s*)?\([\w\s\*&]*\)\s*([\(&a-zA-Z])/$1/gsm;

s/\r\}\s*([^\r])/\r\}\r$1/gsm;

#ifマクロの後ろに{をつける
s/\r(\#if[^\r]*)/\r;\r$1\r\{\r/gsm;
#endifマクロを}に変換
s/\r(\#endif[^\r]*)/\r\;\r}\r/gsm;
#elseマクロの前後に{}をつける
s/\r\#else/\r\}\r;\r\#else\r\{\r/gsm;

# 行末文字で分割
foreach(/.*?[\:\;\{\}]\r/gsm) {
	s/\r//gsm;
	s/^\s+//gsm;	s/\s+$//gsm;	# ブランク削除
	s/^\;$//gsm;	#先頭;の削除
	push(@$lines, $_) if length;
}
}
#{
# my $fh = FileHandle->new(">l1.txt");
# $fh->print(join"\n", @$lines);
# $fh->close;
#
# my $fh = FileHandle->new(">l2.txt");
# $fh->print($line);
# $fh->close;
#}
#print
join"\n", split "\r", $line;
#push
if length $line;
#foreach
my $i(0..10){
# print "$lines->[$i]\n";
#}

{
# ネスト解析
my $func = stack();

# ステートメント解析
my $l = fnc($func->{data});

# ファイル出力
my $fh = FileHandle->new(">$file.ss.txt");
$fh->print(join "\n", @$l);
$fh->close;

exit;

view($func);

exit;
}

sub view{
my $dat = shift;
my $l   = shift;

if( 'ARRAY' eq ref $dat ) {
	for(my $i=0; $i<=$#{$dat}; $i++){
		print(' ' x $l) if $i > 0;
		my $n = "[$i]->";
		print $n;
		view($dat->[$i], $l + length $n);
	}
	print("\n") if($#{$dat} < 0);
}
elsif( 'HASH' eq ref $dat ) {
	my $f = 0;
	foreach my $k (keys %$dat) {
		print(' ' x $l) if $f;
		my $n = "{$k}->";
		print $n;
		view($dat->{$k}, $l + length $n);
		$f = 1;
	}
}
else{
	print "'$dat'\n";
}
}

sub fnc {
my $dat = shift;
my $ret = [];

return $ret unless 'ARRAY' eq ref $dat;

# ヘッダ
my $hedder = '+------------------';
my $fieldn = '| @@@@@@@@@@@@ |   ';
my $field0 = '|              |   ';
my $fotter = '+--------------    ';
# フッダ追加処理
my $fotterchg = sub {
	my ($ary, $sch, $chg) = @_;
	my ($a, $s) = ($#{$ary}, length $sch);
	return 0 unless $sch eq substr $ary->[$a], 0, $s;
	pop(@$ary) if $sch eq $ary->[$a];
	substr($ary->[$a], 0, $s) = $chg;
	return 1;
};
my $last;

foreach my $d (@$dat) {
	$_ = $d->{method};

	next if 0 == length;

	my $line = [];
	my $l = {};
	my $flag = 0;

	my $openclose;		# 括弧の正規表現
	$openclose = qr/\(([^()]*(?:(??{$openclose})[^()]*)*)\)/;
	my ($dep) = /$openclose/;	# 最初の一つの括弧を取得
	my $aft = $';	#'			# 括弧の後の文字列取得
	$dep =~ s/^\s+//gs;	$dep =~ s/\s+$//gs;	# ブランク削除
	$aft =~ s/^\s+//gs;	$aft =~ s/\s+$//gs;	# ブランク削除
	$aft = "" unless $dep;
	my $hed = $dep ? '@' : 'o';
	my $status;

	if(/^(\#if\S*)\s+(\w+)/) {			# #if マクロ
		($hed, $dep, $flag) = ($1, $2, 1);
	}

	if(/^((if)|(for)|(switch))\s*\(/) {	# if/for/switch文
		($hed, $status) = ($1, $aft);
		$flag = 1 if $2;
		$flag = 2 if $3;
		$flag = 3 if $4;
	}
	elsif(/^(\#?else)/) {				# else(#elseマクロ込み)
		($hed, $flag) = ($1, 1);
		$fotterchg->($ret, $fotter, $field0);
		if(/if\s*\(/) {	$hed .= " if";	$status = $aft;	}
		else {	undef $dep;	}
	}
	elsif(/^(while|until)\s*\(/) {		# while/until文
		($hed, $flag) = ($1, 3);
		($status, $flag) = ($aft, 2) unless $last =~ /^do/;
	}
	elsif(/^do/) {						# do~while/until文
		($hed, $flag) = ('do', 2);
		undef $dep;
	}

	# ライン追加
	my $lineadd = sub {
		return unless @$ret;
		return if '|' eq $ret->[$#{$ret}];
		push @$ret, '|';
	};

	$lineadd->() if $ret->[$#{$ret}] =~ /^[^o]/;
	if('@' eq $hed && @{$d->{data}} > 0) {
		push(@$ret, "[ $_ ]");
		$lineadd->();
		$hed = $hedder;
	}

	# ステートメントだったら判定内容を展開
	if($flag) {
		my $h = $hedder;
		substr($h, 2, length $hed) = $hed;
		substr($h, -3, 1) = '>' if $flag == 1;
		substr($h, -4, 1) = '+' if $flag == 2;
		substr($h, -4) = '    ' if $flag == 3;
		push @$line, $h;

		if(defined $dep) {	# 判定内容を展開
			my $l = 0;		# @の文字数カウント
			$l++ while($fieldn =~ /\@/g);
			foreach my $b (unpack "a$l" x (1+ int(length($dep) / $l)), $dep) {
				my $a = $fieldn;
				$b = sprintf "%-${l}s", $b;
				$a =~ s/\@+/$b/;
				push @$line, $a;
			}
		}
		else {				# 判定無しなら空フィールド追加
			push @$line, $field0;
		}
	}
	elsif(1 == length $hed) {
		# 変数代入、関数呼出の追加
		push @$line, "$hed $_";
	}
	else {
		# サブフィールドあり
		push @$line, $hed, $field0;
		$flag = 1;
	}

	# 階層下の処理呼出
	my $n = fnc(length $status ? [ { method => $status, data => [] } ] : $d->{data});

	# 階層下と本体の結合処理
	if(@$n > 0) {
		$flag = 1;
		if(@$line > @$n) {	# 階層下のほうが少ない
			$line->[$_] = "$line->[$_]$n->[$_]" foreach 0..$#{$n};
		}
		else {				# 階層下の方が多い
			$line->[$_] = "$line->[$_]$n->[$_]" foreach 0..$#{$line};
			# 空フィールド+階層下を追加
			push(@$line, "$field0$n->[$_]") foreach @$line..$#{$n};
			# フッダ追加処理
			$flag = 0 if $fotterchg->($line, $field0, $fotter);
		}
	}

	# フッタ追加
	push(@$line, $fotter) if $flag;

	push(@$ret, @$line);

	$last = $_;
}
return($ret);
}

# ネスト解析処理
sub stack {
my ($method) = @_;
my $dat = {data =>[]};

$dat->{method} = $method if $method;

while($num <= $#{$lines}) {
	my $line = $lines->[$num];
	($num++, next) unless length $line;
	if($line =~ s/^\}//) {	# ネスト減
		$lines->[$num] = $line;
		last;
	}elsif($line =~ s/\{$//) {	# ネスト
		$lines->[$num] = $line;
		$num++;
		push(@{$dat->{data}}, stack($line));
	}
	else {
		$num++;
		push(@{$dat->{data}}, {method => $line, data =>[]});
	}
}
return $dat;
}

#■ エスケープされていないダブルクォート
#$reg = qr/(?<!\\)(?:\\\\)*\"/;
#my
@define = qw/__DEBUG __WRITELOG/; # define を指定する
# $src にソースを丸ごとつっこむ
# #if-#endif
#$src =~ s|^#if\s+(\w+)(.*?)^(#else(.*?))?^#endif|($1)?$2:$4|emsg;
# #ifdef-#endif
#$src =~ s|^#ifdef\s+(\w+)(.*?)^(#else(.*?))?^#endif|(grep {$_ eq $1 } @define)?$2:$4|emsg;
# #ifndef-#endif
#$src =~ s|^#ifndef\s+(\w+)(.*?)^(#else(.*?))?^#endif|(grep {$_ eq $1 } @define)?$4:$2|emsg;
最終更新:2009年03月24日 00:43