最長 token 匹配
注意伯顶,下面進(jìn)入糟糕區(qū)域,如果看不懂請查看英文原文!
S05-metasyntax/longest-alternative.t lines 53–460
因?yàn)?"longest-token matching" 是一個(gè)很長的短語, 我們會經(jīng)常將這個(gè)概念叫做 LTM
. 這個(gè)基本的概念就是人們在頭腦中傾向于怎么去解析文本, 所以計(jì)算機(jī)應(yīng)該像人一樣嘗試做同樣的事情. 而使用 LTM
解析文本就是關(guān)于計(jì)算機(jī)怎樣決定匹配一組備選分支中的哪一個(gè)備選分支的.
在 Perl 6 中, |
代表使用聲明性的 longest-token 語義的邏輯備選分支.(你現(xiàn)在能使用 ||
來標(biāo)示舊的暫存的備選分支. 就是, |
和 ||
現(xiàn)在在正則語法內(nèi)的運(yùn)作方式和在正則語法外的運(yùn)作方式很像, 在正則語法外部, |
和 ||
代表 junctional 和 短路的 OR
. 這也包括事實(shí)上 |
的優(yōu)先級比 ||
的優(yōu)先級高.)
在過去, Perl 中正則表達(dá)式是通過一個(gè)能回溯的 NFA 算法來處理的. 這很強(qiáng)大, 但是很多解析器通過并行地處理 rules , 而不是一個(gè)接著一個(gè)地處理, 工作起來更高效, 至少達(dá)到某種程度. 如果你看一下像 yacc grammar 這樣的東西, 你會發(fā)現(xiàn)很多 pattern/action 聲明, 其中的 patterns 被認(rèn)為是并行的, 并且最終由 grammar 決定觸發(fā)哪個(gè) action. 雖然默認(rèn)的Perl 解析角度是從上至下的(或許使用一個(gè)中間層的從下至上角度來處理操作符優(yōu)先級), 這對用戶理解 token 處理進(jìn)行確定性很有用。所以, 為了 regex 匹配的意圖, 我們把 tokens 模式定義為那些不含潛在副作用或自引用的能被匹配的模式。(因?yàn)榭崭裨谛修D(zhuǎn)換時(shí)經(jīng)常有副作用, 所以通常被這樣的模式排除, 給予或采取一點(diǎn)向前查看。) 基本上, Perl 自動地從 grammar 中派生出一個(gè)詞法分析程序, 而不需要你自己寫一個(gè)垢油。
為此, Perl 6 中的每個(gè) regex 被要求能把它的純模式和它的 actions 區(qū)分開, 并返回它的初始 token 模式的列表(包含由regex 的純部分調(diào)用的 subrule 的 token 模式, 但是不包含多于一次的 subrule, 因?yàn)槟强赡軙鹱砸? 這在傳統(tǒng)正則表達(dá)式中是不被允許的。) 一個(gè)使用|
的邏輯備選分支接收兩個(gè)或多個(gè)這種列表并分發(fā)給匹配最長 token 前綴的備選分支圆丹。出現(xiàn)在第一位的可能是也可能不是那個(gè)備選分支滩愁。
然而, 如果兩個(gè)備選分支以同樣的長度匹配, 綁定首先由特異性打破。 以最長的固定字符串開頭的備選分支勝出; 即一個(gè)精確的匹配被看作是比使用字符類更接近. 如果它不起作用, 綁定會由兩個(gè)方法中的一個(gè)破壞. 如果備選分支在不同的 grammars 中, 那么標(biāo)準(zhǔn)的 MRO(方法解析順序)決定首先嘗試哪一個(gè). 如果備選分支在同一個(gè) grammar 文件中, 本文出現(xiàn)的更早的備選分支取得優(yōu)先權(quán). (如果一個(gè) grammar 的 rules 被定義在不止一個(gè)文件中, 那么順序是未定義的, 則必須使用一個(gè)顯式的斷言用于強(qiáng)制失敗, 如果首先嘗試錯(cuò)誤的那個(gè)的話)
這個(gè)長的標(biāo)記前綴大致相當(dāng)于“令牌”在其他分析系統(tǒng)使用一個(gè)詞法分析器的概念辫封,但對于Perl這很大程度上是自動從語法定義一個(gè)偶然現(xiàn)象硝枉。然而,盡管是自動計(jì)算的倦微,這一套標(biāo)記可以由用戶修改妻味;各種內(nèi)構(gòu)造正則表達(dá)式的語法來告訴引擎,這是完成圖案的部分開始的副作用欣福,所以將這種構(gòu)建用戶控件被認(rèn)為是象征性的责球,什么是不。被視為終止一個(gè)令牌聲明并啟動“行動”部分的結(jié)構(gòu)的結(jié)構(gòu)包括:
這種最長 token 前綴大致相當(dāng)于在其它解析系統(tǒng)中使用詞法解析程序的 "token" 標(biāo)記, 但對于 Perl 這很大程度上是從 grammar 定義中派生的附帶現(xiàn)象拓劝。然而雏逾,盡管是自動計(jì)算的, 這套 tokens 可以由用戶修改; regex 中的各種結(jié)構(gòu)聲明性的告訴 grammar 引擎, 模式部分結(jié)束, 并開始進(jìn)入副作用, 所以通過插入這樣的結(jié)構(gòu), 用戶控制什么是 token, 什么不是。終止 token 聲明并開始模式的 "action" 部分的結(jié)構(gòu)包括:
- 任何 :: 或 ::: 回溯控制 (而不是e : 肯定修飾符).
- 任何帶有節(jié)儉匹配(使用
?
修飾符)量詞化的原子郑临。 - 任何
{...}
action, 但不是含有閉包的斷言栖博。(空的閉包{}
通常用于顯式地終止模式的 pure 部分。) 一般的**{...}
量詞形式的閉包也會終止最長 token, 但是無閉包形式的量詞不會厢洞。
- 任何諸如
||
或&&
按次序的控制流操作符. - 作為前一點(diǎn)的結(jié)果仇让,因?yàn)闃?biāo)準(zhǔn)的 grammar 規(guī)則使用
||
定義空格, 最長的token 也由那 可能 使用那個(gè)規(guī)則匹配空格的 regex 或 rule 的任意部分終止, 包括通過:sigspace
隱式匹配的空格。(然而犀变,token 聲明明確允許通過在 token 中使用諸如\h+
或其它字符類這種低級原語來識別空格) - Subpatterns(捕獲)不終止token模式妹孙,但可能需要重新解析 token以找到Subpatterns的位置。同樣地获枝,在確定最長token之后斷言可能需要被檢查蠢正。(或者, 如果以任何一種方式模仿了 DFA 語義, 例如, 使用湯普森的NFA,可能可以知道什么時(shí)候觸發(fā)斷言而不使用backchecks省店。)
貪婪量詞和字符類不會終止 token 模式嚣崭。 諸如單詞邊界的零寬斷言也不會。
因?yàn)檫@種斷言可以是 token 的一部分, 詞法分析程序引擎必須能從這種斷言的失敗中恢復(fù), 并回溯到下一個(gè)最佳 token 候選者, 它可能等長或更短, 但是絕對不會當(dāng)前候選者更長懦傍。
對于含有諸如 <?foo>
或 <?before \s>
這樣的正向向前查看的模式, 這種斷言會被認(rèn)為比隨后的模式更特殊, 所以向前查看的模式被當(dāng)作最長 token 的最后一部分; 最長 token 匹配器會足夠智能地把額外的 bit 當(dāng)作是零寬的, 即, 重新匹配任何由向前查看遍歷到的文本,當(dāng)它(如果)繼續(xù)匹配的時(shí)候雹舀。(實(shí)際上, 如果整個(gè)向前查看足夠純粹地參與 LTM, 再匹配可能僅僅優(yōu)化掉 rematching, 因?yàn)橄蚯安榭匆呀?jīng)在 LTM 引擎中匹配過了)
然而, 對于包含諸如 <!foo>
或 <!before \s>
這種否定向前查看斷言的模式, 反面的才是真: 隨后的模式被認(rèn)為比該斷言更特殊。所以 LTM 完全忽略了否定向前查看, 并繼續(xù)從跟在否定向前查看后面的任何東西中查找純粹模式粗俱。你可能會說, 正向向前查看對 LTM 是不透明的, 否地向前查看對 LTM 是透明的说榆。 結(jié)論是,如果你想寫一個(gè)對 LTM 是透明的正向向前查看, 你可以使用兩個(gè)感嘆號的否定: <!!foo>
來標(biāo)示它。(優(yōu)化器能自由地移除雙否定, 但是不是透明性)。
奇怪的是签财,這 令牌
關(guān)鍵詞具體不確定一個(gè)令牌的范圍串慰,除了一個(gè)令牌模式通常不匹配的空白,而空白是終止令牌的典型方式唱蒸。
很奇怪, token
關(guān)鍵字不確定 token 的作用域, 除了作為一個(gè) token 模式通常不做很多的空格匹配情況之外, 空格是終止 tokens 的原型方式邦鲫。
初始token匹配器必須把區(qū)分大小寫考慮在內(nèi)(或任何其他規(guī)范化原語)并做正確的事, 即使傳播到不具有相同的規(guī)范化的 rules 時(shí)。也就是說神汹,它們必須繼續(xù)代表較低規(guī)則能匹配的一組匹配庆捺。
||
形式有舊的短路語義,而不會試圖匹配其右側(cè), 除非它的左側(cè)耗盡了所有的可能性(包括所有 |
可能性)屁魏。regex 中的第一個(gè) ||
讓它左側(cè)的 token 模式能從外部的最長 token 匹配器中訪問, 但從最長 token 匹配隱藏的任何后續(xù)的測試滔以。每一個(gè) ||
建立了一個(gè)新的最長 token匹配器。那就是, 如果你在 ||
右側(cè)使用 |
蚁堤,那么右側(cè)為最長 token 處理這子表達(dá)式和任何被調(diào)用的 subrules建立了一個(gè)新的頂級作用域處理這個(gè)子表達(dá)式和任何所謂的規(guī)則醉者。右邊的最長 token 自動機(jī)是對于左側(cè)的 ||
或外部的含有 ||
的 regex是不可見的。
大西瓜啊披诗,翻譯的狗屎一樣撬即,慘不忍睹!