gawk1.01源码分析——进行调试

gawk1.01源码分析——进行调试
因为疫情之故,天天在家。前段天天读小说,后来,觉得,还是读源码,至少让精力有地方发泄。于是,又重新读源码。
虽然很久没读,但发现,以前读过,现在再读,还是有种熟悉的感觉。但,发现光读代码,而代码跑不起来,没有感觉。还是要把代码编译,测试,再修改,再编译,执行后看修改是否产生的效果。因此,又捡起原来曾编译通过的代码。再开始。
 ./gawk --version
./gawk: Segmentation fault (core dumped)
我原来以为gawk1.01也能看版本号,报这个错误,因为我是在win10下,wsl弄个ubuntu18进行调试。不能生成那个dump文件,于是就让我放弃。我后来才发现,其实是因为gawk1.01没有实现--version参数处理,于是再改个最简单的程序。
./gawk 'BEGIN {print "haha"}'
haha

果然程序就能运行了。我进行修改awk1.c文件,在main中加一句,再
sudo make
./gawk 'BEGIN {print "haha"}'
就能看到我所修改的效果。
现在最困难的是不理解gawk生成的那个解析树
awk.h头文件中那个复杂的数据结构。于是我想,能否进行调试呢?于是再读代码。
在awk1.c中,有一段
  for(;*argv && **argv=='-';argc--,argv++) {
576     switch(argv[0][1]) {
577 #ifndef FAST
578     case 'd':
579       debugging++;
580       dotree++;
581       break;
582
583     case 'D':
584       debugging++;
585       yydebug=2;
586       break;
587 #endif
我想,先测试一下-D先项,如下所示:
 ./gawk -D 'BEGIN {print "haha"}'
 输入结果太长了。如下所示:
Starting parse
Entering state 0
Reducing stack 0 by rule 51 (line 264):
-> $$ = nterm optional_newlines ()
Entering state 2
看来,是把bison进行解析的过程打印出来了。
再测试-d先项。如下:
 ./gawk -d 'BEGIN {print "haha"}'
test001_yang
(0)0xfd34cc = left<--(0xfd34e4 Rule_list.35)
(1) 0xfd346c = left<--(0xfd34cc Rule_node.36)-->right = 0xfd34b4
(2)  (0xfd346c BEGIN.40)
(2)  0xfd349c = left<--(0xfd34b4 State_list.37)
(3)   0xfd3484 = left<--(0xfd349c PRINT.48)
(4)    0xfd6440 = left<--(0xfd3484 Exp_list.39)
(5)     [(0xfd6440 String "haha")]
Statements:16594076
PRINT:16594076
DATA:16606272
haha
这个结果较短了。
如果你仔细看,上面就是语法树。
                     34e4[Rule_list]
                 34cc[Rule_node]    
              346c  34b4[State_list]
           BEGIN   349c
于是重点分析debug.c文件。
以前,没有仔细的读debug.c文件,现在为了理解,只能认真读。
这里重点介绍一个函数
print_parse_tree(ptr)
{
  depth表深度。
  根据ptr->type进行处理
    如果是字串,直接打印
    如果是数字,直接打印
    如果是数组,直接打印
  打印当前结点的左子树,当前结点,及右子树的地址
  depth++
  如果ptr->lnode
    递归print_parse_tree(ptr->lnode)
  根据ptr->type再进行处理
    几种处理没看懂
    默认情况,如果ptr->rnode不空,调print_parse_tree(ptr->rnode)
  depth--
}
实际上就是先根遍历一棵二叉树的算法。
所以我接着想知道
'BEGIN {a=2+3; print
  a}'的语法树,就又调试了一次。我想,如果能用图的方式显示就好了。

另外,告诉你一个秘密,我当时想,如果打印出某个结点,到处搜索,发现在awk.y中有一个函数,  
#ifndef FAST
405 NODE    *do_prvars(),   *do_bp();
406 #endif


 #ifndef FAST
434   {"prvars",    Node_builtin,           LEX_BUILTIN,    do_prvars},
435 #endif
也就是说,在gawk外面,可以调用do_prvars函数,结果如下:
 ./gawk -d 'BEGIN {a=2+3;print a; prvars }' > test3_gawk.txt
结果很让人意外,如下:
Fields:30 fields
$0 is ''
$1 is ''
$2 is ''
$3 is ''
$4 is ''
$5 is ''
$6 is ''
$7 is ''
$8 is ''
$9 is ''
$10 is ''
$11 is ''
$12 is ''
$13 is ''
$14 is ''
$15 is ''
$16 is ''
$17 is ''
$18 is ''
$19 is ''
$20 is ''
$21 is ''
$22 is ''
$23 is ''
$24 is ''
$25 is ''
$26 is ''
$27 is ''
$28 is ''
$29 is ''
Vars:
'FS':  :(0)[(0x12502c0 String " ")]
'NF': var_type ref:19199020
DATA:19202816
0:(0)(0x1250300 Number 0)
'OFS':  :(0)[(0x1250380 String " ")]
'NR': var_type ref:19199020
DATA:19202912
0:(0)(0x1250360 Number 0)
'OFMT': %.6g:(0)[(0x1250400 String "%.6g")]
'RS':
还有很长,于是接着在awk3.c中找到函数
 dump_vars()                                                                               148 {                                                                                         149   register int n;                                                                         150   register HASHNODE *buc;                                                                 151                                                                                           152   printf("Fields:");                                                                      153   dump_fields();                                                                          154   printf("Vars:\n");                                                                      155   for(n=0;n<HASHSIZE;n++) {                                                               156     for(buc=variables[n];buc;buc=buc->next) {                                             157       printf("'%.*s': ",buc->length,buc->name);                                           158       print_simple(buc->value->var_value,stdout);
159       printf(":");                                                                        160       print_parse_tree(buc->value->lnode);
161       /* print_parse_tree(buc->value); */
162     }                                                                                     163   }                                                                                       164   printf("End\n");
165 }   

这里就能看到程序中用到的变量。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章