成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

精讀《手寫 SQL 編譯器 - 詞法分析》

wuyangnju / 1023人閱讀

摘要:解析可以分為如下四步詞法分析,將字符串拆分成包含關(guān)鍵詞識(shí)別的字符段。涉及到語意處理就要考慮上下文,而這都不是詞法分析階段要考慮的。更多討論討論地址是精讀手寫編譯器詞法分析如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。

1 引言

因?yàn)楣ぷ麝P(guān)系,需要開發(fā)支持眾多方言的 SQL 編輯器,所以復(fù)習(xí)了一下編譯原理相關(guān)知識(shí)。

相比編譯原理專家,我們只需要了解部分編譯原理即可實(shí)現(xiàn) SQL 編輯器,所以這是一篇寫給前端的編譯原理文章。

解析 SQL 可以分為如下四步:

詞法分析,將 SQL 字符串拆分成包含關(guān)鍵詞識(shí)別的字符段(Tokens)。

語法分析,利用自頂向下或自底向上的算法,將 Tokens 解析為 AST,可以手動(dòng),也可以自動(dòng)。

錯(cuò)誤檢測(cè)、恢復(fù)、提示推斷,都需要利用語法分析產(chǎn)生的 AST。

語義分析,做完這一步就可以執(zhí)行 SQL 語句了,不過對(duì)前端而言,不需要深入到這一步,可以跳過。

2 精讀

詞法分析就像刀削面的過程,拿著一段字符串(面條)一端不斷下刀,當(dāng)面條被切完也就完成了詞法分析,所以詞法分析是 字符串 -> 一堆字符段 的過程。

流程很簡(jiǎn)單,難點(diǎn)就在下刀的分寸了,每次砍幾厘米呢?

回到詞法分析,為了準(zhǔn)備切分,我們需要定義 SQL 的 Token 有哪些類型,即 Token 分類。

Token 分類

SQL 的 Token 可以分為如下幾類:

注釋。

關(guān)鍵字(SELECT、CREATE)。

操作符(+、-、>=)。

開閉合標(biāo)志((、CASE)。

占位符(?)。

空格。

引號(hào)包裹的文本、數(shù)字、字段。

方言語法(${variable})。

可以看到,在詞法分析階段,我們的 Tokens 不需要關(guān)心關(guān)鍵詞是什么,只要識(shí)別是不是關(guān)鍵詞即可,因?yàn)殛P(guān)鍵詞的辨認(rèn)會(huì)留到語法分析時(shí)處理。涉及到語意處理就要考慮上下文,而這都不是詞法分析階段要考慮的。

同樣,操作符、空格、文本、占位符等構(gòu)成了 SQL 語句的其他部分,最后通過開閉合標(biāo)志比如左括號(hào)和右括號(hào),讓 SQL 支持子語句。

再強(qiáng)調(diào)一次,雖然 SQL 支持子語句,但并不是放在任何位置都是合理的,其他類型 Token 同理,但是詞法分析不需要考慮 Token 是否合理,只要切分即可。

用正則逐段分詞

像大多數(shù)語言一樣,SQL 為了方便人類閱讀,采用從左到右的書寫方式,因此分詞方向也從左到右。

我們?yōu)槊總€(gè) Token 類型寫一個(gè)函數(shù),比如匹配空格的匹配函數(shù):

function getTokenWhitespace(restStr: string) {
  const matches = restStr.match(/^(s+)/);

  if (matches) {
    return { type, value: matches[1] };
  }
}

restStr 表示掐去頭部剩下的 SQL 字符串,所有匹配函數(shù)都拿 restStr 進(jìn)行匹配,已經(jīng)匹配的不需要再處理。

通過正則 /^(s+)/ 匹配到第一個(gè)以空格開頭的空格(讀起來有點(diǎn)別扭),匹配時(shí)必須保證以你要匹配的內(nèi)容開頭,而且只匹配一次,這樣才不會(huì)在切詞時(shí)發(fā)生遺漏。

同理匹配 /**/ 類型注釋時(shí),也能通過正則輕而易舉的實(shí)現(xiàn):

function getTokenBlockComment(restStr: string) {
  const matches = restStr.match(/^(/*[^]*?(?:*/|$))/);

  if (matches) {
    return { type, value: matches[1] };
  }
}

其中 (?:*/) 表示匹配到以 */ 結(jié)尾處,而 (?:*/|$) 后面的 |$ 表示或者直接匹配到結(jié)尾(如果一直沒有遇到 */ 那后面全部當(dāng)作注釋)。

所以只要 Token 分類得當(dāng),并且能為每一個(gè)分類寫一個(gè)頭匹配正則,分詞功能就實(shí)現(xiàn)了 90%。

方言拓展

為了支持某些方言,需要從分詞時(shí)就開始做考慮。比如 ${variable} 作為一種變量用法時(shí),我們需要在普通字段的正則匹配中,加入一項(xiàng) ${[a-zA-Z0-9]+} 匹配。

如果要支持純中文作為字段,可以再補(bǔ)充 |u4e00-u9fa5

分詞主流程

有了一個(gè)個(gè)分詞函數(shù),再補(bǔ)充一個(gè)不斷匹配、切割字符串、再匹配的主函數(shù)即可,這一步更簡(jiǎn)單:

while (sqlStr) {
  token =
    getTokenWhitespace(sqlStr, token) | getTokenBlockComment(sqlStr, token);

  sqlStr = sqlStr.substring(token.value.length);

  tokens.push(token);
}

上面的函數(shù)每取一次 Token,都將取到的 Token 長度丟掉,繼續(xù)匹配剩下的字符串,直到字符串被切分完為止。

有些特殊情況需要拿到上次的 Token 才能判斷下一個(gè) Token 該如何切割,所以將 Token 傳給每一個(gè)下一步 Match 函數(shù)。

最后,執(zhí)行這個(gè)主函數(shù),分詞就完成了!

3 總結(jié)

分詞比較簡(jiǎn)單,到這里就全部結(jié)束了。后面即將進(jìn)入深水區(qū)語法分析,敬請(qǐng)期待。

4 更多討論
討論地址是:精讀《手寫 SQL 編譯器 - 詞法分析》 · Issue #93 · dt-fe/weekly

如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/96025.html

相關(guān)文章

  • 精讀手寫 SQL 譯器 - 智能提示》

    摘要:經(jīng)過連續(xù)幾期的介紹,手寫編譯器系列進(jìn)入了智能提示模塊,前幾期從詞法到文法語法,再到構(gòu)造語法樹,錯(cuò)誤提示等等,都是為智能提示做準(zhǔn)備。 1 引言 詞法、語法、語義分析概念都屬于編譯原理的前端領(lǐng)域,而這次的目的是做 具備完善語法提示的 SQL 編輯器,只需用到編譯原理的前端部分。 經(jīng)過連續(xù)幾期的介紹,《手寫 SQL 編譯器》系列進(jìn)入了 智能提示 模塊,前幾期從 詞法到文法、語法,再到構(gòu)造語法...

    ztyzz 評(píng)論0 收藏0
  • 精讀《syntax-parser 源碼》

    摘要:引言是一個(gè)版語法解析器生成器,具有分詞語法樹解析的能力。實(shí)現(xiàn)函數(shù)用鏈表設(shè)計(jì)函數(shù)是最佳的選擇,我們要模擬調(diào)用棧了。但光標(biāo)所在的位置是期望輸入點(diǎn),這個(gè)輸入點(diǎn)也應(yīng)該參與語法樹的生成,而錯(cuò)誤提示不包含光標(biāo),所以我們要執(zhí)行兩次。 1. 引言 syntax-parser 是一個(gè) JS 版語法解析器生成器,具有分詞、語法樹解析的能力。 通過兩個(gè)例子介紹它的功能。 第一個(gè)例子是創(chuàng)建一個(gè)詞法解析器 my...

    yuanxin 評(píng)論0 收藏0
  • 精讀手寫 SQL 譯器 - 文法介紹》

    摘要:一般用大寫的表示文法的開頭,稱為開始符號(hào)。更多討論討論地址是精讀手寫編譯器文法介紹如果你想?yún)⑴c討論,請(qǐng)點(diǎn)擊這里,每周都有新的主題,周末或周一發(fā)布。 1 引言 文法用來描述語言的語法規(guī)則,所以不僅可以用在編程語言上,也可用在漢語、英語上。 2 精讀 我們將一塊語法規(guī)則稱為 產(chǎn)生式,使用 Left → Right 表示任意產(chǎn)生式,用 Left => Right 表示產(chǎn)生式的推導(dǎo)過程,比如對(duì)...

    TNFE 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<