Perl 脚本都是内部编译为语法树,然后根据语法树解析执行每一步。察看一个脚本的语法树用模块B::Concise,简单说明如下:
B::Concise - 遍历语法树,打印每一个执行码(ops)的内容
用法:perl -MO=Concise[,OPTIONS] script
常用OPTIONS:
-basic: 默认模式,打印内存树状结构OPs
-exec: 根据执行顺序打印OPs,可同默认basic作比较
C:\>perl -MO=Concise -e "$a = 43 / 20; print $a"
a <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
5 <2> sassign vKS/2 ->6
3 <$> const[NV 2.15] s ->4
- <1> ex-rv2sv sKRM*/1 ->5
4 <#> gvsv[*a] s ->5
6 <;> nextstate(main 1 -e:1) v:{ ->7
9 <@> print vK ->a
7 <0> pushmark s ->8
- <1> ex-rv2sv sK/1 ->9
8 <#> gvsv[*a] s ->9
-e syntax OK
C:\>perl -MO=Concise,-exec -e "$a = 43 / 20; print $a"
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <$> const[NV 2.15] s
4 <#> gvsv[*a] s
5 <2> sassign vKS/2
6 <;> nextstate(main 1 -e:1) v:{
7 <0> pushmark s
8 <#> gvsv[*a] s
9 <@> print vK
a <@> leave[1 ref] vKP/REFC
-e syntax OK
-terse: 以上都是打印OPs缩略,并不明显,用此参数显示OPs更加明显。用此参数实际等同于perl -MO=Terse ......
C:\>perl -MO=Concise,-terse -e "$a = 43 / 20; print $a"
LISTOP (0x2918118) leave [1]
OP (0x291801c) enter
COP (0x291813c) nextstate
BINOP (0x2918178) sassign
SVOP (0x291819c) const [4] NV (0x285a864) 2.15
UNOP (0x2918220) null [15]
PADOP (0x2918240) gvsv GV (0x285a814) *a
COP (0x291805c) nextstate
LISTOP (0x29180b4) print
OP (0x2918098) pushmark
UNOP (0x29180d8) null [15]
PADOP (0x29180f8) gvsv GV (0x285a814) *a
-e syntax OK
C:\>perl -MO=Concise,-terse,-exec -e "$a = 43 / 20; print $a"
OP (0x2918274) enter
COP (0x2918394) nextstate
SVOP (0x29183f4) const [4] NV (0x285a86c) 2.15
PADOP (0x2918498) gvsv GV (0x285a81c) *a
BINOP (0x29183d0) sassign
COP (0x29182b4) nextstate
OP (0x29182f0) pushmark
PADOP (0x2918350) gvsv GV (0x285a81c) *a
LISTOP (0x291830c) print
LISTOP (0x2918370) leave [1]
-e syntax OK
-src: 以上都是整体语法树,加此参数可以显示每一行对应编译后的语法树,不过此参数只能对文件起作用,对-e 执行的单行程序不能很好的支持。
对于perl 的一些简写,如果想知道内部是如何处理的,可以反编译语法树,从执行码推导脚本,用B::Deparse模块。
C:\>perl -MO=Deparse -ne "print if /test/" stock.pl
LINE: while (defined($_ = <ARGV>)) {
print $_ if /test/;
}
-e syntax OK
使用以上的模块,参考OPs的定义,可以帮助更好地了解perl的内部实现。