安卓啟動流程(三) - tokenizer分詞器

tokenizer分詞器众雷,是Parser解析工具的核心邏輯工具,主要工作是將rc文件的字符串分解出令牌和單詞坐求。

/system/core/init/tokenizer.h
/system/core/init/tokenizer.cpp


token 令牌

token令牌是調(diào)用tokenizer.next_token()的返回值奸笤,表示解析到需要調(diào)用者處理的新事件。

#define T_EOF 0
#define T_TEXT 1
#define T_NEWLINE 2
  • T_EOF
    解析完成
    字符串已解析到末端霎槐。end-of-file,rc文件完成解析梦谜。

  • T_TEXT
    解析到新單詞
    tokenizer解析到一個單詞栽燕。單詞的地址保存在傳入的parse_state結(jié)構(gòu)體中。

  • T_NEWLINE
    解析完成一行
    tokenizer解析到換行符改淑。表示當(dāng)前行解析結(jié)束碍岔,準(zhǔn)備解析下一行。


parse_state 解析數(shù)據(jù)結(jié)構(gòu)體

parse_state結(jié)構(gòu)體用于存放 解析過程的狀態(tài) 和 產(chǎn)生的臨時數(shù)據(jù)朵夏。

struct parse_state
{
    char *ptr;
    char *text;
    int line; 
    int nexttoken; 
};
  • char *ptr
    正在解析字符的指針
    tokenizer當(dāng)前正在解析的字符指針蔼啦,相當(dāng)于解析進(jìn)度。

  • char *text
    詞文本指針
    tokenizer檢出的單詞的首字符指針仰猖。

  • int line
    文本行號
    tokenizer當(dāng)前正在解析的數(shù)據(jù)的行號捏肢。

  • int nexttoken
    令牌緩存
    優(yōu)化解析速度。在檢出一個單詞的過程中饥侵,解析到了換行符鸵赫,意味著單詞結(jié)束并產(chǎn)生換行,需要輸出T_TEXTT_NEWLINE躏升。把后者緩存到nexttoken辩棒,在下一次next_token()函數(shù)的早段邏輯中直接返回。


next_token() 執(zhí)行解析

/system/core/init/tokenizer.cpp

next_token()函數(shù)有兩個關(guān)鍵的局部變量

int next_token(struct parse_state *state) {
    char *x = state->ptr;
    char *s;
    ...
}
  • char *x
    當(dāng)前正在解析的字符指針
    在調(diào)用函數(shù)時,從傳入結(jié)構(gòu)體中獲取一睁,在產(chǎn)生令牌時钻弄,儲存回結(jié)構(gòu)體。

  • char *s
    當(dāng)前檢出中的單詞的尾部字符指針
    指向檢出中單詞的最后一個字符的字符指針者吁。檢出過程中窘俺,tokenizer認(rèn)為*x是當(dāng)前檢出單詞的一部分時,通過*s++ = *x++复凳,把*x覆蓋到*s瘤泪,然后各自自增指向下一數(shù)據(jù)地址。


next_token()函數(shù)邏輯分為非單詞檢出和單詞檢出兩個部分育八,由于內(nèi)容比較緊湊均芽,邏輯解析直接寫到源碼注釋。

非單詞檢出流程:
int next_token(struct parse_state *state) {
    
    // 當(dāng)前識別位置
    char *x = state->ptr;
    // 單詞末端位置
    char *s;

    // 緩存令牌, 用于優(yōu)化效率
    if (state->nexttoken) {
        int t = state->nexttoken;
        state->nexttoken = 0;
        return t;
    }

    // 非單詞檢出階段
    for (;;) {
        switch (*x) {

            // '\0', 即NULL字符
            // :字符串結(jié)尾
            // :當(dāng)前識別位置(+1)(記錄), 返回T_EOF
            case 0:
                state->ptr = x;
                return T_EOF;

            // 換行
            // :行解析結(jié)束
            // :當(dāng)前識別位置(+1)(記錄), 返回T_NEWLINE
            case '\n':
                x++;
                state->ptr = x;
                return T_NEWLINE;

            // 空格, 制表符, 回車
            // :無效字符
            // :當(dāng)前識別位置(+1), 繼續(xù)循環(huán)
            case ' ':
            case '\t':
            case '\r':
                x++;
                continue;

            // #號
            // :注釋, 跳過該行所有字符直到
            //   - 換行     : 該行解析結(jié)束, 當(dāng)前識別位置(+1)(記錄), 返回T_NEWLINE
            //   - NULL字符 : 文件解析結(jié)束, 當(dāng)前識別位置, 返回T_EOF
            case '#':
                while (*x && (*x != '\n')) x++;
                if (*x == '\n') {
                    state->ptr = x+1;
                    return T_NEWLINE;
                } else {
                    state->ptr = x;
                    return T_EOF;
                }

            // 其他字符
            // :識別為一個詞的首部
            // :開始單詞檢出流程
            default:
                goto text;
        }
    }
    ...
}

單詞檢出流程:
int next_token(struct parse_state *state) {
    ...

// 檢出單詞单鹿,返回T_TEXT令牌
// 單詞末端位置寫入NULL字符, 剪裁出字符串
// 當(dāng)前識別位置(記錄), 返回T_TEXT
textdone:
    state->ptr = x;       // 當(dāng)前識別位置保存到state
    *s = 0;               // 單詞末端位置寫入NULL字符
    return T_TEXT;

// 單詞檢出流程 (初始化單詞的首尾指針)
text:
    state->text = s = x;   // 初始化單詞的首尾指針為當(dāng)前識別位置

// 單詞檢出流程
textresume:
    for (;;) {
        switch (*x) {

            // '\0', 即NULL字符
            // :字符串結(jié)尾
            // :檢出單詞
            case 0:
                goto textdone;

            // 空格, 制表符, 回車
            // :詞結(jié)尾
            // :當(dāng)前識別位置(+1), 檢出單詞
            case ' ':
            case '\t':
            case '\r':
                x++;
                goto textdone;

            // 換行
            // :行解析結(jié)束
            // :當(dāng)前識別位置(+1), 檢出單詞, 并緩存T_NEWLINE
            case '\n':
                state->nexttoken = T_NEWLINE;
                x++;
                goto textdone;
            
            // 引號(左則)
            // 被引號包裹的字符串視為一個整體進(jìn)行處理
            case '"':
                // 當(dāng)前識別位置(+1), 即跳過引號
                x++;
                for (;;) {
                    switch (*x) {
                        // :文件解析結(jié)束
                        // :丟棄當(dāng)前解析中的單詞, 返回T_EOF
                        case 0:
                            state->ptr = x;
                            return T_EOF;

                        // 引號(右則)
                        // :跳到單詞檢出流程
                        // :正常情況下, 會檢出單詞, 跳到textdone
                        case '"':
                            x++;
                            goto textresume;

                        // 其他字符
                        // :單詞尾端寫入當(dāng)前字符
                        default:
                            *s++ = *x++;
                    }
                }
                break;

            // 處理轉(zhuǎn)義字符
            case '\\':
                // 當(dāng)前識別位置(+1), 即跳過當(dāng)前轉(zhuǎn)義字符
                x++;
                switch (*x) {
                    // '\0'
                    // :字符串結(jié)尾
                    // :跳到單詞檢出流程
                    case 0:
                        goto textdone;

                    // 需要寫入的轉(zhuǎn)移字符
                    // :單詞尾端寫入對應(yīng)字符
                    case 'n':
                        *s++ = '\n';
                        break;
                    case 'r':
                        *s++ = '\r';
                        break;
                    case 't':
                        *s++ = '\t';
                        break;
                    case '\\':
                        *s++ = '\\';
                        break;

                    // \\r
                    // :回車
                    // :"\\r\n"則換行, 否則跳過字符
                    case '\r':
                        if (x[1] != '\n') {
                            x++;
                            continue;
                        }

                    // '\n'
                    // :換行
                    // :行號(+1), 跳過接下來的空格或制表符
                    case '\n':
                        state->line++;
                        x++;
                        while((*x == ' ') || (*x == '\t')) x++;
                        continue;

                    // 其他轉(zhuǎn)移字符
                    // :直接在單詞尾端寫入當(dāng)前字符
                    default:
                        *s++ = *x++;
                }
                continue;

            // 其他字符
            // :直接在單詞尾端寫入當(dāng)前字符
            default:
                *s++ = *x++;
        }
    }
    return T_EOF;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市深纲,隨后出現(xiàn)的幾起案子仲锄,更是在濱河造成了極大的恐慌,老刑警劉巖湃鹊,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件儒喊,死亡現(xiàn)場離奇詭異,居然都是意外死亡币呵,警方通過查閱死者的電腦和手機(jī)怀愧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余赢,“玉大人芯义,你說我怎么就攤上這事∑奁猓” “怎么了扛拨?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長举塔。 經(jīng)常有香客問我绑警,道長,這世上最難降的妖魔是什么央渣? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任计盒,我火速辦了婚禮,結(jié)果婚禮上芽丹,老公的妹妹穿的比我還像新娘北启。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布暖庄。 她就那樣靜靜地躺著聊替,像睡著了一般。 火紅的嫁衣襯著肌膚如雪培廓。 梳的紋絲不亂的頭發(fā)上惹悄,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音肩钠,去河邊找鬼泣港。 笑死,一個胖子當(dāng)著我的面吹牛价匠,可吹牛的內(nèi)容都是我干的当纱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼踩窖,長吁一口氣:“原來是場噩夢啊……” “哼坡氯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起洋腮,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤箫柳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后啥供,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悯恍,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年伙狐,在試婚紗的時候發(fā)現(xiàn)自己被綠了涮毫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡贷屎,死狀恐怖罢防,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情唉侄,我是刑警寧澤篙梢,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站美旧,受9級特大地震影響渤滞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜榴嗅,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一妄呕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嗽测,春花似錦绪励、人聲如沸肿孵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽停做。三九已至,卻和暖如春大莫,著一層夾襖步出監(jiān)牢的瞬間蛉腌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工只厘, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留烙丛,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓羔味,卻偏偏與公主長得像河咽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子赋元,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容