oz grep源碼分析


oz grep源碼分析
今天在筆記本上折騰ubuntu18,真是很好玩。
配置低的本上,裝ubuntu,真划算。原來4G跑win10總是慢得不行,現在跑linux,感覺還是很快的。
我在本子上讀regex.c這個文件,一個地方卡住了。

    for (p = pat; *p; p++) {
        lp = mp;
        switch(*p) {

        case '.':               /* match any char..  */
            store(ANY);
            break;

        case '^':               /* match beginning.. */
            if (p == pat)
                store(BOL);
            else {
                store(CHR);
                store(*p);
            }
            break;

        case '$':               /* match endofline.. */
            if (!*(p+1))
                store(EOL);
            else {
                store(CHR);
                store(*p);
            }
            break;

        case '[':               /* match char class..*/
            store(CCL);

            if (*++p == '^') {
                mask = 0377;    
        //0377==11 111 111,與它異或,按位取反。:w
                p++;
            }
            else
                mask = 0;

            if (*p == '-')        /* real dash */
                chset(*p++);
            if (*p == ']')        /* real brac */
                chset(*p++);
            while (*p && *p != ']') {
                if (*p == '-' && *(p+1) && *(p+1) != ']') {
                    p++;
                    c1 = *(p-2) + 1;
                    c2 = *p++;
                    while (c1 <= c2)
                        chset((CHAR)c1++);
                }
#ifdef EXTEND
                else if (*p == '\\' && *(p+1)) {
                    p++;
                    chset(*p++);
                }
#endif
                else
                    chset(*p++);
            }
            if (!*p)
                return badpat("Missing ]");

            for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
                store(mask ^ bittab[n]);
    
            break;

這是在re_comp中進行編譯,把正則表達式翻譯成中間碼。此處,把'[1-9]'翻譯成
  '123456789',但你看呀,
如果p指向[,此時,先存儲“CCL”,接着,判斷
*++p,此時,p指向1,所以下面兩個判斷不用做,因爲不是-,也不是],那就來到了
            while (*p && *p != ']') {
                if (*p == '-' && *(p+1) && *(p+1) != ']') {
                    p++;
                    c1 = *(p-2) + 1;
                    c2 = *p++;
                    while (c1 <= c2)
                        chset((CHAR)c1++);
                }
#ifdef EXTEND
                else if (*p == '\\' && *(p+1)) {
                    p++;
                    chset(*p++);
                }
#endif
                else
                    chset(*p++);
            }
此時,p指向'[1-9]'中的1,所以執行循環中第三分支
                else
                    chset(*p++);
把1保存進去。接着p++,此時p指向-
  那好,接着循環,因爲*p=='-'所以執行第一分支
                if (*p == '-' && *(p+1) && *(p+1) != ']') {
                    p++;  //p指向'-',++後指向9
                    c1 = *(p-2) + 1;//c1指向1
                    c2 = *p++;   //p指向9,c2也指向9,但p++後指向]
                    while (c1 <= c2)
                        chset((CHAR)c1++);
                }
此分支,完成的是就是把23456789這幾個字符保存好。
  此時,用話不好說,請看代碼中註釋。這個分支做完後,p指向],因此,要跳出循環。
  做下一步處理
              for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
                store(mask ^ bittab[n]);
也就是把16字節的位置保存到中間代碼數組中去。
  此時,p指向],那程序如何處理]的呢?
  程序只有如下分支
case .
case $
case [
case *
case +
....
如果不是這些字符,它是:
        default :               /* an ordinary char  */
            store(CHR);
            store(*p);
            break;
可是,中間代碼編譯結果中根據沒有存儲]呀,況且存儲了也沒意義。你看:
yang@DESKTOP-V9HS3B6:~/grep$ echo "12345" | ./ogrep '[1-9]+'
pattern: [1-9]+
nfacode:
        CCL [123456789]
CLOSURE CCL [123456789]
看到沒,正則表達式翻譯的結果中根據沒有】
我想呀想,不停地翻代碼。總是不得勁。
後來,忽然想,不對,這裏有個break,就是
case [
   把[1-9]變成ccl 123456789保存到中間碼,此時p指向],
   break
結束本次循環後,到哪了?
    for (p = pat; *p; p++) {//此處有p++,哈哈,我明白了。原來在這裏!!!
        lp = mp;
        switch(*p) {

        case '.':         
看到我的註釋沒?p本來指向],這是沒錯的,但break後,p++,就跳過了]
  通過讀程序,發現自己的程序功底還是有欠缺。
同樣的錯誤犯了兩次。前一次,看代碼
            for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
                store(mask ^ bittab[n]);
這裏,是把16字節的位圖存儲到中間代碼結果中去。當時我曾想,你把bittab[]保存進去了,你下次使用是,要初始化吧,那在哪兒初始化呢???
  我找呀找!
  你肯定要初始化的,不然如果這樣寫正則表達式'[a-z'] hello [1-9]'那如何搞?
  前面使用的位置如果不初始化,後面且不是變成了[a-z1-9]。當時是用kindle讀代碼,想呀想,後來明白了。
        for (n = 0; n < BITBLK; bittab[n++] = (char) 0)//此處有bittab[n++] = (char)
                store(mask ^ bittab[n]);
作者在for的最後做了。
  代碼要經常讀,太好了。

 

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