免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5002 | 回复: 13

求指导~~~~~~~~~~ 关于递归创建hash [复制链接]

论坛徽章:
0
发表于 2015-07-25 10:24 |显示全部楼层
本帖最后由 ljpdxj 于 2015-07-25 11:14 编辑

工作中很少很少写Perl代码(Perl算入门吧,Regex掌握还行),这次有需求:按照数据结构的Leaf(考虑PATH)做数据克隆(嵌入式平台,系统设置拷贝,同一客户的所有产品,不同型号的产品之间数据结构可能有差异)
我想到的方式就只能是先分析C源代码中指定Structure的树状组织关系,再通过其他方式算出每个Leaf在Top Structure中的Offset和Size
比如如下(项目里实际上这块数据有8K多,我们可以估计到其从Top Structure到Leaf的复杂度---->众多Leaf以及多级Structure定义):
  1. struct a
  2. {
  3.     struct b;
  4.     int c;
  5.     struct d;
  6. };

  7. struct b
  8. {
  9.    char e;
  10.    short f;
  11. };

  12. struct d
  13. {
  14.     int g;
  15.     int h;
  16. }
复制代码
以上共有5条PATH,分别是:
a/b/e
a/b/f
a/c
a/d/g
a/d/h
Source Platform和Dest Platform有各自文件,通过比对PATH,若相同,再使用PATH后面的Offset和Size来做数据Copy。

我用perl写了几个过程:
PreParsingInputFile()--->用于找出预处理过后的C代码头文件(该文件包含从Top Struct到Leaf的所有数据结构)
中所有Structure(struct&enum&union)定义在该文件的开始位置并记录于Hash{structname => linenum}
ParsingStruct() --->解析指定Structure,返回三个ARRAY,分别是基本类型的Member ARRAY,用户自定义类型的Member ARRAY以及这部分用户自定义类型Member的类型ARRAY
GenStructMapping() --->一个递归函数,参数为Structure Name和一个%hash,该Hash记录该Struct的所有Member信息,实现如下:
  1. #[in]structure name;
  2. #[out]hash stored the members of this struct
  3. sub GenStructMapping($\%)
  4. {
  5.         my ($Struct, $Hash) = @_;
  6.         my %TmpHash;
  7.         my @BasicTypeMember = ();
  8.         my @StructMember = ();
  9.         my @StructType = ();
  10.         my $basictypemember = undef;
  11.         my $structmember = undef;
  12.         my $iter = 0;

  13.         undef %$Hash;
  14.         if (defined $Struct)
  15.         {
  16.                 ParsingStruct($Struct, @BasicTypeMember, @StructMember, @StructType);
  17.         }
  18.         else
  19.         {
  20.                 return 1 ;
  21.         }
  22.        
  23.         if (@BasicTypeMember == 0 && @StructMember == 0)
  24.         {
  25.                 return 1;
  26.         }

  27.         foreach $basictypemember (@BasicTypeMember)
  28.         {
  29.                 print "3333\n";
  30.                 $$Hash{"$basictypemember"} = undef;
  31.         }

  32.         while ($iter < @StructMember)
  33.         {
  34.                 print "4444\n";
  35.                 #print "type:$StructType[$iter], name $StructMember[$iter]\n";
  36.                 if (&GenStructMapping($StructType[$iter], %TmpHash) == 0)
  37.                 {
  38.                         $$Hash{"$StructMember[$iter]"} = %TmpHash;
  39.                 }
  40.                 else
  41.                 {
  42.                         $$Hash{"$StructMember[$iter]"} = undef;
  43.                 }
  44.                 $iter++;
  45.         }

  46.         return 0;
  47. }
复制代码
以上API用hash记录Top Structure到所有Leaf的PATH。
我的问题是递归添加Hash的过程,该函数里面的%TmpHash是局部变量,我要如何做?

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
发表于 2015-07-25 10:55 |显示全部楼层
C 风格的 Perl 代码看着真碍眼呀

论坛徽章:
0
发表于 2015-07-25 11:01 |显示全部楼层
回复 2# MMMIX
工作性质的关系,能写算不错了
我做嵌入式Linux数字电视开发的。
   

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
发表于 2015-07-25 12:43 |显示全部楼层
看得有点迷糊,递归创建一个 Hash, 那么这个 Hash 不但是递归函数的参数之一,而且还是递归函数返回的值之一。注意设置跳出条件,否则就死循环了。按理说 C 语言支持递归,写 C 的对递归的应用应当很多吧。

论坛徽章:
0
发表于 2015-07-25 13:59 |显示全部楼层
我觉得我写得很清晰了呀
我的目的就是生成一个Hash
hash保存Top Struct到所有Leaf的PATH
比如
%Tree =
{
    b => {e => undef, f => undef},
    c => undef,
    d => {g => undef, h=> undef},
}

论坛徽章:
26
2015亚冠之胡齐斯坦钢铁
日期:2015-06-25 21:40:202015亚冠之柏斯波利斯
日期:2015-08-31 17:03:192015亚冠之柏斯波利斯
日期:2015-11-07 13:10:00程序设计版块每日发帖之星
日期:2015-11-10 06:20:00每日论坛发贴之星
日期:2015-11-10 06:20:00程序设计版块每日发帖之星
日期:2015-11-26 06:20:00程序设计版块每日发帖之星
日期:2015-12-02 06:20:00黄金圣斗士
日期:2015-12-07 17:57:4615-16赛季CBA联赛之天津
日期:2015-12-23 18:34:14程序设计版块每日发帖之星
日期:2016-01-02 06:20:00程序设计版块每日发帖之星
日期:2016-01-06 06:20:00每日论坛发贴之星
日期:2016-01-06 06:20:00
发表于 2015-07-25 19:29 |显示全部楼层
回复 5# ljpdxj
%Tree =
{
    b => {e => undef, f => undef},
    c => undef,
    d => {g => undef, h=> undef},
}


写得很清晰
多谢!学习了!

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
发表于 2015-07-25 22:27 |显示全部楼层
本帖最后由 104359176 于 2015-07-25 22:36 编辑

一大堆专业术语,不知道你要说什么。你只要把你想要的说出来就好了。解决你的问题,没必要了解你 C 语言的程序是做什么的。
  1. struct a
  2. {
  3.     struct b;
  4.     int c;
  5.     struct d;
  6. };

  7. struct b
  8. {
  9.    char e;
  10.    short f;
  11. };

  12. struct d
  13. {
  14.     int g;
  15.     int h;
  16. }
复制代码
To ->
  1. %Tree =
  2. {
  3.     b => {e => undef, f => undef},
  4.     c => undef,
  5.     d => {g => undef, h=> undef},
  6. }
复制代码
其实就是把 C 代码解析成数据结构:
  1. struct b
  2. {
  3.    char e;
  4.    short f;
  5. };
复制代码
=>
  1. my $data = {
  2.     b => {
  3.         char => 'e'.
  4.         short => 'f',
  5.     },
  6. };
复制代码
剩下的问题用遍历就可以了。代码看不到你解析文本的部分,不知道你的数据结构,怎么设计算法呢?

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
发表于 2015-07-26 03:08 |显示全部楼层
shibushi:
  1. #!/usr/bin/perl

  2. sub gimme(\@) {
  3.     my %h;
  4.     for ( @{ +shift } ) {
  5.         my $t = \%h;
  6.         $t = $t->{$_} ||= {} for @$_[ 1 .. $#$_ - 1 ];
  7.         $t->{ $_->[-1] } = undef;
  8.     }
  9.     %h;
  10. }

  11. my @path = map [ split /\/|\n/ ], <DATA>;
  12. my %tree = gimme @path;

  13. # b => { e => undef, f => undef }, c => undef, d => { g => undef, h => undef }

  14. __DATA__
  15. a/b/e
  16. a/b/f
  17. a/c
  18. a/d/g
  19. a/d/h
复制代码
or:
  1. #!/usr/bin/perl

  2. sub gimme {
  3.     my ( $k, %h );
  4.     for (@_) {
  5.         $k = $1, next if /^struct\s+(\S+)/;
  6.         my ( $type, $field ) = /(\w+)\s+(\w+)/ or next;
  7.         $type eq 'struct' ? ( $h{$field}     = {} )
  8.           : exists $h{$k} ? ( $h{$k}{$field} = undef )
  9.           :                 ( $h{$field}     = undef );
  10.     }
  11.     %h;
  12. }

  13. my %tree = gimme <DATA>;

  14. # d => { h => undef, g => undef }, c => undef, b => { f => undef, e => undef }

  15. __DATA__
  16. struct a
  17. {
  18.     struct b;
  19.     int c;
  20.     struct d;
  21. };

  22. struct b
  23. {
  24.    char e;
  25.    short f;
  26. };

  27. struct d
  28. {
  29.     int g;
  30.     int h;
  31. }
复制代码

论坛徽章:
0
发表于 2015-07-26 11:00 |显示全部楼层
回复 8# rubyish
谢谢楼上,我上面abcdefgh只是举例,这个是工程应用,并不是学习,所以实际情况中Structure的定义要复杂得多,
我们可以想象到的:比如有无typedef;是否使用GNU C扩展的功能;结构体定义断行位置不同等,以上我都可以处理。
同时也不会仅仅是两层结构体包含,而是可能很多层。
我的问题是GenStructMapping() 参数使用hash,递归调用时hash不能正常返回

GenStructMapping(结构体,结构体 Mapping Hash)
{
    1.解析结构体
    2.对该结构体,若Member是基本类型(char, int, short, long etc.),添加{Member => undef}到Hash中
   3.若该结构体的Member是结构体,调用GenStructMapping()返回SubHash之后,添加{Member => %Subhash}到Hash中
}
   

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
发表于 2015-07-26 13:04 |显示全部楼层
回复 9# ljpdxj


    看起来使用引用就行了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP