枚举变量扩展
在很多配置文件中,都会牵涉到变量扩展,一个变量会有多少种可能的扩展结果,这在静态分析中非常重要。这里给出一个算法,使用 perl 来表达(expand.pl),变量引用使用统一的形式:${varname}。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#!/usr/bin/env perl use strict; my %vars = (); # cross array array sub cross_aa($$) { my ($tx, $ty) = @_; my @res = (); for my $x (@$tx) { for my $y (@$ty) { push @res, $x.$y; } } return \@res; } sub expandexpr($) { my ($expr) = @_; my $res1 = [ "" ]; print "expand('$expr')/n"; while ($expr =~ m/(\$\{([/w.-]+)\})|([^\$]+)/g) { if ($3) { # join array scalar for (my $i = 0; $i < @$res1; ++$i) { $res1->[$i] .= $3; } } elsif ($1) { my @res2 = (); my $ty = $vars{$2}; for my $y (@$ty) { my $xy = cross_aa($res1, expandexpr($y)); push @res2, @$xy; } $res1 = \@res2; } else { print STDERR "bad expr=$expr, remain=$'\n"; } } return $res1; } |
程序主控逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
my @toExpand = (); for (my $i = 0; $i < @ARGV; ++$i) { if ($ARGV[$i] eq "-v") { push @toExpand, $ARGV[++$i]; } } while (<STDIN>) { if (m/([\w.-]+)/s*=(.*)$/g) { my $name = $1; my $val = $2; push @{$vars{$name}}, $val; } } for my $expr (@toExpand) { my $res = expandexpr("$expr"); print "expr:$expr\n"; for my $z (@$res) { print "\t:$z/n"; } } |
使用一个简单的例子来测试一下(var.txt):
1 2 3 4 5 6 |
a=AA_ a=11_ b=BB_${a}${a} b=22_${a}${a} x=XX_${b}${a}${b} y=YY_${a}${x} |
命令: ./expand.pl -v ‘$y’ < var.txt
输出结果:
1 2 3 4 5 6 7 8 9 |
:YY_AA_XX_BB_AA_AA_AA_BB_AA_AA_ :YY_AA_XX_BB_AA_AA_AA_BB_11_AA_ :YY_AA_XX_BB_AA_AA_AA_BB_AA_11_ :YY_AA_XX_BB_AA_AA_AA_BB_11_11_ :YY_AA_XX_BB_11_AA_AA_BB_AA_AA_ :YY_AA_XX_BB_11_AA_AA_BB_11_AA_ :YY_AA_XX_BB_11_AA_AA_BB_AA_11_ ..................................... too long, 256 lines, you know why it is. :) |