<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                >[success] # 詞法解析 ~~~ 1.生活中經常我們會有一些對話比如'今天我吃了魚香肉絲',或者是'I ate noodles today' 但是實際 上如果我們大腦不進行分詞理解這些語句實際變得無意義就像'Iatenoodlestoday' 只是一堆字符串 詞法解析就像,我們大腦幫我們翻譯的一樣'今天''我''吃了''魚香肉絲' 2.如何可以讓程序也像人一樣可以對這些詞進行分類,其實在學習語言的過程時候已經知道了答 案,在我們第一次去學習漢字時候往往第一步是學習每一個'字',在將'字組成詞',同理在學習 英語時候需要先學習'26個字母',再學的是將不同'26個字母組成單詞',無論是'漢字'還是'單詞' 組成的字它們會有一些新的標記例如'名詞'、'動詞'等 3.現在按照我們讓大腦可以進行'詞法分析'學習步驟,來實現編程語言的詞法分析,第一步就是 '掃描',這個步驟將輸入的內容當作一個無意義的字符串,讀取時候它所看到的只是一次一個字符 例如'今天 我吃了魚香肉絲',掃描后變成了['今', '天', ' ', '我', '吃', '了', '魚', '香', '肉', '絲'] 4.得到了這些我們在然后生成詞素(lexeme)。詞素是組成編程語言的最小的有意義的單元實 變成類似['今天','','我','吃', '了', '魚香','肉絲'],此時這個階段不知道它們是什么“類型”的詞。只知道 單詞在文本本身中的結束和開始位置。例如'今天' start:0 end:1 5.現在要做的是識別詞類型,將識別的單詞統一轉換成詞法單元'token' 形式即'<種別碼,屬性值>' 舉個例子來看'<名詞,今天><代詞,我>...' ~~~ >[info] ## 詞法單元'token' 兩個例子來源 [MOOC編譯原理](https://www.icourse163.org/course/HIT-1002123007?tid=1467039443) [Reading Code Right, With Some Help From The Lexer](https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d) >[danger] ##### 例子一 ![](https://img.kancloud.cn/e3/95/e3953a62436b5bd291445f62971e4f64_736x313.png) * 舉個例子 ![](https://img.kancloud.cn/86/a5/86a5eee550c842164fb8ad008a2307dd_587x416.png) >[danger] ##### 舉個前端例子的'token' ~~~ 1.var toSleep = "to dream";,可以看到空格并不會作為一個詞法單元('token'),但這完全是因為js 不需要,但如果你是python 開發就會知道'空格最為縮減是完全有作為詞法單元('token')'必要 ~~~ ![](https://img.kancloud.cn/f6/64/f66405f3c2cd18f30427a5dbde4e6630_1400x953.png) >[info] ## 做一個自己詞法解析器 ~~~ 1.詞法編輯器步驟,'讀取每個字'=》'將字組成詞素(lexeme)'=》'做好令牌token標記' 2.js程序語言比自然語言要稍微好處理點,首先js 和自然語句都一樣都需有語法,即屬于自己 的特定規則 2.1.空白:JS中連續的空格、換行、縮進等這些如果不在字符串里,就沒有任何實際邏輯意義, 所以把連續的空白符直接組合在一起作為一個語法單元。 2.2.注釋:行注釋或塊注釋,雖然對于人類來說有意義,但是對于計算機來說知道這是個“注釋” 就行了,并不關心內容,所以直接作為一個不可再拆的語法單元 2.3.字符串:對于機器而言,字符串的內容只是會參與計算或展示,里面再細分的內容也是沒 必要分析的 2.4.數字:JS語言里就有16、10、8進制以及科學表達法等數字表達語法,數字也是個具備含 義的最小單元 2.5.標識符:沒有被引號擴起來的連續字符,可包含字母、_、$、及數字(數字不能作為開 頭)。標識符可能代表一個變量,或者true、false這種內置常量、也可能是if、return、 function這種關鍵字,是哪種語義,分詞階段并不在乎,只要正確切分就好了。 2.6.運算符:+、-、*、/、>、<等等 2.7.括號:(...)可能表示運算優先級、也可能表示函數調用,分詞階段并不關注是哪種語義, 只把“(”或“)”當做一種基本語法單元 2.8.還有其他:如中括號、大括號、分號、冒號、點等等 ~~~ >[danger] ##### 舉個例子 ~~~ if (1 > 0) { alert("if \"1 > 0\""); } ~~~ ~~~ 1.第一步'掃描'拆解成單獨字符 [ 'i', 'f', '(', 'a', ' ', '=', '=', '=', ' ', '1', ')', '{', '\n', ' ', ' ', ' ', ' ', 'c', 'o', 'n', 's', 'o', 'l', 'e', '.', 'l', 'o', 'g', '(', 'a', ')', '\n', '}' ] 2.做詞素(lexeme),這里就變得簡單了,js關鍵字即具備實際意義可以組成語句的并不像 自然語言那么多。而且大多數情況下通過'空格'即是每一個詞最小單位例如'if' 等,這里將 詞素(lexeme)和 token 作為一步一起輸出(<種別碼,屬性值>),js像表達類似(<種別碼,屬性值>) 這里選擇了對象,下面例子可以看出'if' 被標記為'Keyword' 即關鍵字 [ { "type": "Keyword", "value": "if" }, { "type": "Punctuator", "value": "(" }, { "type": "Identifier", "value": "a" }, { "type": "Punctuator", "value": "===" }, { "type": "Numeric", "value": "1" }, { "type": "Punctuator", "value": ")" }, { "type": "Punctuator", "value": "{" }, { "type": "Identifier", "value": "console" }, { "type": "Punctuator", "value": "." }, { "type": "Identifier", "value": "log" }, { "type": "Punctuator", "value": "(" }, { "type": "Identifier", "value": "a" }, { "type": "Punctuator", "value": ")" }, { "type": "Punctuator", "value": "}" } ] ~~~ * 詞素(lexeme) ![](https://img.kancloud.cn/3a/e6/3ae6c41d8a5176e677dbef7b02833c62_696x233.png) >[danger] ##### 形象的圖形理解 * 圖片來自【圖文詳解】200行JS代碼,帶你實現代碼編譯器(人人都能學會) - https://juejin.cn/post/6844904105937207304#heading-24 ~~~ 1.這拆分過程其實就是簡單粗暴地一個字符一個字符地遍歷,然后分情況討論 ~~~ ![](https://img.kancloud.cn/e3/55/e3556474d743c9008ec3c26c004aecbe_3088x3103.png) >[danger] ##### 開始敲代碼 ~~~ function tokenizeCode(code) { // 當前讀取指針位置 let current = 0; // 令牌結果 const tokens = []; // 當前字符 let currentChar = ""; while (current < code.length) { currentChar = code[current]; // 如果是; 就是結束符 直接存起來 // 類似 const b = 2;const a = 1 此時; 也是有語義的 if (currentChar === ";") { tokens.push({ type: "sep", value: ";", }); // 將指針指向下一個字符 ++current; // 這個字符不需要其他特殊出來因此可以直接處理 下一個 continue; } // 處理() 情況 if (currentChar === "(" || currentChar === ")") { tokens.push({ type: "parens", value: currentChar, }); // 將指針指向下一個字符 ++current; // 這個字符不需要其他特殊出來因此可以直接處理 下一個 continue; } // 處理{} 情況 if (currentChar === "}" || currentChar === "{") { // 與 ; 類似只是語法單元類型不同 tokens.push({ type: "brace", value: currentChar, }); ++current; continue; } // 處理 < > = 但實際情況比這復雜 還會有 >= <= == === 等情況 if (currentChar === ">" || currentChar === "<") { // 與 ; 類似只是語法單元類型不同 tokens.push({ type: "operator", value: currentChar, }); ++current; continue; } // 處理數字 if (/[0-9]/.test(currentChar)) { let value = ""; // 當情況為 1234 這種情況時候,即將1234 看作一個整體 // 需要一直循環到最后一個數字截至 while (/[0-9]/.test(currentChar)) { value += currentChar; currentChar = code[++current]; } tokens.push({ type: "number", value: value, }); ++current; continue; } // 處理字符串 也就是引號" 開頭到下一個 "結束 // 期望輸出結果 例如"aa" { type: "string", value: "\"aa\"" }, // 可以看到對結果輸出多了\ 轉義符 這就是對字符處理稍微注意地方 if (currentChar === '"' || currentChar === "'") { let value = ""; // 保存實際對應的閉合標簽 const closeTag = currentChar; value += currentChar; while (currentChar !== closeTag) { currentChar = code[++current]; value += currentChar; } currentChar = code[++current]; value += currentChar; const token = { type: "string", value, }; tokens.push(token); ++current; continue; } if (/[a-zA-Z\$\_]/.test(currentChar)) { // 標識符是以字母、$、_開始的 let value = ""; // 標識符是以字母、$、_開始的 和數字同理 // 即 if else for 這些 while (/[a-zA-Z\$\_]/.test(currentChar)) { value += currentChar; currentChar = code[++current]; } tokens.push({ type: "identifier", value: value, }); ++current; continue; } if (/\s/.test(currentChar)) { // let value = ""; // while (/\s/.test(currentChar)) { // value += currentChar; // currentChar = code[++current]; // } // tokens.push({ // type: "whitespace", // value: value, // }); ++current; continue; } // 還可以有更多的判斷來解析其他類型的語法單元 // 遇到其他情況就拋出異常表示無法理解遇到的字符 throw new Error("Unexpected " + currentChar); } return tokens; } const code = ` if (1 > 0) { alert("aaaa"); } `; console.log(tokenizeCode(code)); ~~~ * 打印結果 ~~~ 1.像 const if 這種等 這種沒有雙引號包裹的,因此可以我們理解為是變量名或者系統關鍵字,即 屬于'標識符'(可以看上面案對標識符說明) ~~~ ~~~ [ { type: 'identifier', value: 'if' }, { type: 'parens', value: '(' }, { type: 'number', value: '1' }, { type: 'operator', value: '>' }, { type: 'number', value: '0' }, { type: 'brace', value: '{' }, { type: 'identifier', value: 'alert' }, { type: 'string', value: '"a' }, { type: 'identifier', value: 'aaa' }, { type: 'parens', value: ')' }, { type: 'sep', value: ';' }, { type: 'brace', value: '}' } ] ~~~ >[info] ## 文章內容參考來源 [Rebuilding Babel: The Tokenizer](https://www.nan.fyi/tokenizer) https://github.com/narendrasss/compiler/blob/main/src/tokenizer.ts [MOOC編譯原理](https://www.icourse163.org/course/HIT-1002123007?tid=1467039443) [Babel是如何讀懂JS代碼的 ](https://zhuanlan.zhihu.com/p/27289600)[Reading Code Right, With Some Help From The Lexer](https://medium.com/basecs/reading-code-right-with-some-help-from-the-lexer-63d0be3d21d) https://github.com/YongzeYao/the-super-tiny-compiler-CN/blob/master/the-super-tiny-compiler.js
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看