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 }   

這裏就能看到程序中用到的變量。

 

 

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