注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

结合几行代码看perl解析执行  

2012-06-03 17:41:22|  分类: 脚本语言 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、my关键字实现
my是perl的词法限制单位,也就是说和C语言中局部变量具有相同的形式,它只在包含它的词法作用域中生效,在bash中有local关键字和该功能对应。
[tsecer@Harry perltest]$ cat myimp.pl
my $var=hello;
print $var;
{
    my $var=world;
    print $var;

    {
        my $var=Iam;
        print $var;
        {
            my $var=back;
            print $var;
        }

        print $var;
    }

    print $var;
}

print $var;
[tsecer@Harry perltest]$ perl -DXv myimp.pl
Pad 0x82d7a54[0x82ecb3c] new:       compcv=0x82d7a24 name=0x82d7a44 flags=0x0
Pad 0x82d7a54[0x82ecb3c] alloc:   1 for padsv
Pad addname: 1 "$var" new lex=0x82f20f4
Pad intromy: 1 "$var", (0,2147483647)
Pad intromy: seq -> 1
Pad findlex cv=0x82d7a24 searching "$var" seq=1
Pad findlex cv=0x82d7a24 matched: offset=1 (0,2147483647)
Pad 0x82d7a54[0x82ecb3c] alloc:   2 for padsv
Pad addname: 2 "$var" new lex=0x82f2124
Pad intromy: 2 "$var", (1,2147483647)
Pad intromy: seq -> 2
Pad findlex cv=0x82d7a24 searching "$var" seq=2
Pad findlex cv=0x82d7a24 matched: offset=2 (1,2147483647)
Pad 0x82d7a54[0x82ecb3c] alloc:   3 for padsv
Pad addname: 3 "$var" new lex=0x82f2154
Pad intromy: 3 "$var", (2,2147483647)
Pad intromy: seq -> 3
Pad findlex cv=0x82d7a24 searching "$var" seq=3
Pad findlex cv=0x82d7a24 matched: offset=3 (2,2147483647)
Pad 0x82d7a54[0x82f7b8c] alloc:   4 for padsv
Pad addname: 4 "$var" new lex=0x82f2184
Pad intromy: 4 "$var", (3,2147483647)
Pad intromy: seq -> 4
Pad findlex cv=0x82d7a24 searching "$var" seq=4
Pad findlex cv=0x82d7a24 matched: offset=4 (3,2147483647)
Pad leavemy: 4 "$var", (3,4)
Pad leavemy: seq = 5
Pad findlex cv=0x82d7a24 searching "$var" seq=5
Pad findlex cv=0x82d7a24 matched: offset=3 (2,2147483647)
Pad leavemy: 3 "$var", (2,5)
Pad leavemy: seq = 6
Pad findlex cv=0x82d7a24 searching "$var" seq=6
Pad findlex cv=0x82d7a24 matched: offset=2 (1,2147483647)
Pad leavemy: 2 "$var", (1,6)
Pad leavemy: seq = 7
Pad findlex cv=0x82d7a24 searching "$var" seq=7
Pad findlex cv=0x82d7a24 matched: offset=1 (0,2147483647)
Pad leavemy: 1 "$var", (0,7)
Pad leavemy: seq = 8
Pad 0x82d7a54[0x82f7b8c] alloc:   5 for const
Pad 0x82d7a54[0x82f7b8c] setsv:   5 sv=0x82f2114
Pad 0x82d7a54[0x82f7b8c] alloc:   6 for const
Pad 0x82d7a54[0x82f7b8c] setsv:   6 sv=0x82f2144
Pad 0x82d7a54[0x82f7b8c] alloc:   7 for const
Pad 0x82d7a54[0x82f7b8c] setsv:   7 sv=0x82f2174
Pad 0x82d7a54[0x82f7b8c] alloc:   8 for const
Pad 0x82d7a54[0x82f7b8c] setsv:   8 sv=0x82f21a4
这里比较有意思的是它的实现方法,它为每个my变量都分配了一个作用域范围,也就是在
Pad intromy: 2 "$var", (1,2147483647)
中体现的一个范围,表示这个变量var是在1到2147483647(0x7ffffff)范围内有效,然后当一个变量离开它的作用域的时候,这个上限被修改为离开时系统的当前上限值,这个上限值在源代码中对应为PL_cop_seqmax全局变脸,每次需要查找一个$引用的时候,它都会传递系统当前的PL_cop_seqmax值给S_pad_findlex函数,作为定界符。这样做的好处在于不同的block中的my变量只有在整个所用域退出之后统一一次释放,而不是每离开一个作用域就释放所有的my变量,缺点是对于变量查找的时候可能有影响。这里比较有意思的是整个全局变量PL_cop_seqmax在my变量引入和剔除的过程中都会增加,关键点在于它当变量退出作用域之后,它的上限从原来的无限大变为当前PL_cop_seqmax,而下次搜索的my变量只能在PL_cop_seqmax++基础之上,而此时还没有退出的变量由于其上限为无限大,所以满足搜索条件
S_pad_findlex中搜索符号的实现代码,可见变量必须满足上限和下限两个条件,其中seq一般是当前系统中PL_cop_seqmax的当前值
    for (offset = AvFILLp(nameav); offset > 0; offset--) {
            const SV * const namesv = name_svp[offset];
        if (namesv && namesv != &PL_sv_undef
            && strEQ(SvPVX_const(namesv), name))
        {
        if (SvFAKE(namesv))
            fake_offset = offset; /* in case we don't find a real one */
        else if (  seq >  COP_SEQ_RANGE_LOW(namesv)    /* min */
            && seq <= COP_SEQ_RANGE_HIGH(namesv))    /* max */
            break;
        }
二、print参数
这个词法分析和我们常见的C语言词法分析相同,如果赋值的时候使用了"",那么认为是一个字符串类型,也可能有是数字类型,也即是Integer或者是Unsigned类型;如果没有加字符串,也不是数字,也不是类型变量(例如函数名或者变量名),则认为是字符串。特别地,对于print这种变参函数来说,具体如何格式化就是通过这些变量的字面类型来优先确定,如果是字符则原封不动打印,如果是数值常量则首先字符串化然后输出。
但是这里有一点,那就是对于变参类型的变量来说,一个非正统类型的单词(不是变量引用,不是字符串也不是数值浮点等基本类型)是作为一个文件IO描述符来处理的,例如
print  nodef ;
指令,如果nodef没有定义那么它会优先作为一个File handle来处理,但是事实上它并不是通过open返回的句柄,所以这个打印是没有任何输出的。这个特殊转换调用链为
(gdb) bt
#0  Perl_ck_rvconst (o=0x8364360) at op.c:6710
#1  0x0806540f in Perl_newUNOP (type=14, flags=16, first=0x8364308)
    at op.c:3057
#2  0x08075c2d in Perl_ck_listiob (o=0x8364328) at op.c:7298
#3  0x08064d58 in Perl_convert (type=220, flags=0, o=0x8364328) at op.c:2615
#4  0x080d5645 in Perl_yyparse () at perly.y:747
#5  0x08080240 in S_parse_body (env=0x0, xsinit=0x805e80f <xs_init>)
    at perl.c:2274
#6  0x0807ea9b in perl_parse (my_perl=0x834b008, xsinit=0x805e80f <xs_init>,
    argc=2, argv=0xbffff3a4, env=0x0) at perl.c:1687
#7  0x0805e7c8 in main (argc=2, argv=0xbffff3a4, env=0xbffff3b0)
    at perlmain.c:115
在Perl_ck_rvconst函数中,BARE类型的nodef将会被转换为SVt_PVGV类型,从而在Perl_pp_print中满足下面的GvIO条件
  if (!(io = GvIO(gv))) {
        if ((GvEGV(gv)) && (io = GvIO(GvEGV(gv)))
        && (mg = SvTIED_mg((const SV *)io, PERL_MAGIC_tiedscalar)))
            goto had_magic;
    if (ckWARN2(WARN_UNOPENED,WARN_CLOSED))
        report_evil_fh(gv, io, PL_op->op_type);
    SETERRNO(EBADF,RMS_IFI);
    goto just_say_no;
    }
三、eq和==区别
简单来说,前者是字符串比较,而后者是数值比较,它们分别由Perl_pp_seq和Perl_pp_eq来实现,根据动态语言特征,比较时两者各自向自己希望的类型将参数进行转换后执行。如果说 $str1="hello"; $str2="world";如果使用==比较,它们是相等的,因为两者都不是数值,无法转换为浮点数或者整数,所以最终的结果是两者都变为整数0,由于0==0成立,所以$str1==$str2.。另一个例子是对于
$var1="0x1234";
$var2=0x1234;
使用eq比较并不相等,因为$var2转换为字符串为10进制的4660,所以0x1234和4600字符串并不相等。

[tsecer@Harry perltest]$ cat equal.pl
$str1="hello";
$str2="world";
$str1==$str2&&print "$str1==$str2\n";
$var1="0x1234";
$var2=0x1234;
$var1 eq $var2 && print "$var1 eq $var2";
[tsecer@Harry perltest]$ perl equal.pl
hello==world
[tsecer@Harry perltest]$
  评论这张
 
阅读(701)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017