欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題

          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題

          免費(fèi)學(xué)習(xí)推薦:javascript學(xué)習(xí)教程

          前端中的AST抽象語法樹問題

          • 四則運(yùn)算
          • 正則表達(dá)式
          • 詞法分析
          • 語法分析
          • 完整代碼

          四則運(yùn)算

          首先明確,此次的代碼都是基于LL的語法分析來實(shí)現(xiàn)的,實(shí)現(xiàn)的是四則混合運(yùn)算的功能,先看下定義:
          TokenNumber:
          · 1 2 3 4 5 6 7 8 9 0 的組合
          Operator:
          + - * / 之一
          WhiteSpace:
          <SP>
          LineTerminator:
          <LF> <CR>

          看下產(chǎn)生式:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題

          正則表達(dá)式

          我們首先實(shí)現(xiàn)正則表達(dá)式的匹配原則:

          <script>     var regexp = /([0-9.]+)|([ t]+)|([rn]+)|(*)|(/)|(+)|(-)/g      var dictionary = ["Number", "Whitespace", "LineTerminator", "*", "/", "+", "-"];      function tokenize(source) {         var result = null;         while(true) {             result = regexp.exec(source);              if(!result) break;              for(var i = 1; i <= dictionary.length; i ++) {                 if(result[i])                     console.log(dictionary[i - 1]);             }             console.log(result);         }     }      tokenize("1024 + 10 * 25");</script>

          此時我們看一下頁面的運(yùn)行打印結(jié)果:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題
          值得一提的是這里用到了exec方法,exec() 方法用于檢索字符串中的正則表達(dá)式的匹配。
          我們看一下它的語法:
          RegExpObject.exec(string)

          如果 exec() 找到了匹配的文本,則返回一個結(jié)果數(shù)組。否則,返回 null。此數(shù)組的第 0 個元素是與正則表達(dá)式相匹配的文本,第 1 個元素是與 RegExpObject 的第 1 個子表達(dá)式相匹配的文本(如果有的話),第 2 個元素是與 RegExpObject 的第 2 個子表達(dá)式相匹配的文本(如果有的話),以此類推。除了數(shù)組元素和 length 屬性之外,exec() 方法還返回兩個屬性。index 屬性聲明的是匹配文本的第一個字符的位置。input 屬性則存放的是被檢索的字符串 string。我們可以看得出,在調(diào)用非全局的 RegExp 對象的 exec() 方法時,返回的數(shù)組與調(diào)用方法 String.match() 返回的數(shù)組是相同的。

          但是,當(dāng) RegExpObject 是一個全局正則表達(dá)式時,exec() 的行為就稍微復(fù)雜一些。它會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當(dāng) exec() 找到了與表達(dá)式相匹配的文本時,在匹配后,它將把 RegExpObject 的 lastIndex 屬性設(shè)置為匹配文本的最后一個字符的下一個位置。這就是說,您可以通過反復(fù)調(diào)用 exec() 方法來遍歷字符串中的所有匹配文本。當(dāng) exec() 再也找不到匹配的文本時,它將返回 null,并把 lastIndex 屬性重置為 0。

          詞法分析

          我們在這一部分對上面的代碼做優(yōu)化。
          首先是剛才提到的:
          當(dāng) RegExpObject 是一個全局正則表達(dá)式時,exec() 的行為就稍微復(fù)雜一些。它會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當(dāng) exec() 找到了與表達(dá)式相匹配的文本時,在匹配后,它將把 RegExpObject 的 lastIndex 屬性設(shè)置為匹配文本的最后一個字符的下一個位置。
          那么我們就要考慮到?jīng)]有匹配上字符的情況,做一個判斷處理:

          <script>     var regexp = /([0-9.]+)|([ t]+)|([rn]+)|(*)|(/)|(+)|(-)/g      var dictionary = ["Number", "Whitespace", "LineTerminator", "*", "/", "+", "-"];      function* tokenize(source) {         var result = null;         var lastIndex = 0;         while(true) {             lastIndex = regexp.lastIndex;             result = regexp.exec(source);              if(!result) break;              if(regexp.lastIndex - lastIndex > result[0].length)                 break;                          let token = {                 type: null,                 value: null             }              for(var i = 1; i <= dictionary.length; i ++) {                 if(result[i])                     token.type = dictionary[i - 1];             }             token.value = result[0];             yield token        }         yield {             type: 'EOF'         }     }      for (let token of tokenize("1024 + 10 * 25")) {         console.log(token)     }</script>

          如上,我們對regexp.lastIndex - lastIndexresult[0] 的長度進(jìn)行比較,判斷是否有字符串沒有匹配上。
          將整個函數(shù)改成generator函數(shù)的形式,我們看下運(yùn)行的結(jié)果:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題

          語法分析

          首先編寫分塊的產(chǎn)生式,我們看一下總的代碼結(jié)構(gòu):

          <script>     var regexp = /([0-9.]+)|([ t]+)|([rn]+)|(*)|(/)|(+)|(-)/g      var dictionary = ["Number", "Whitespace", "LineTerminator", "*", "/", "+", "-"];      function* tokenize(source) {         var result = null;         var lastIndex = 0;         while(true) {             lastIndex = regexp.lastIndex;             result = regexp.exec(source);              if(!result) break;              if(regexp.lastIndex - lastIndex > result[0].length)                 break;                          let token = {                 type: null,                 value: null             }              for(var i = 1; i <= dictionary.length; i ++) {                 if(result[i])                     token.type = dictionary[i - 1];             }             token.value = result[0];             yield token        }         yield {             type: 'EOF'         }     }      let source = [];      for(let token of tokenize("10 * 25")) {         if (token.type !== "Whitespace" && token.type !== "LineTerminator")             source.push(token);     }      function Expression(tokens) {      }      function AdditiveExpression(source){      }      function MultiplicativeExpresson(source) {         console.log(source);     }      MultiplicativeExpresson("10 * 25")</script>

          我們先從MultiplicativeExpresson來進(jìn)行研究,它分為四種情況:

          function MultiplicativeExpresson(source) { 	//如果是數(shù)字則進(jìn)行封裝      if(source[0].type === "Number") {          let node = {              type: "MultiplicativeExpresson",              children:[source[0]]          }          source[0] = node;          return MultiplicativeExpresson(source)      }       //如果是乘號或者除號,則將三項(xiàng)出棧,進(jìn)行重組      if(source[0].type === "MultiplicativeExpresson" && source[1] && source[1].type === "*") {          let node = {              type: "MultiplicativeExpresson",              operator: "*",              children: []          }          node.children.push(source.shift());          node.children.push(source.shift());          node.children.push(source.shift());          source.unshift(node);          return MultiplicativeExpresson(source)      }       if(source[0].type === "MultiplicativeExpresson" && source[1] && source[1].type === "/") {          let node = {              type: "MultiplicativeExpresson",              operator: "*",              children: []          }          node.children.push(source.shift());          node.children.push(source.shift());          node.children.push(source.shift());          source.unshift(node);          return MultiplicativeExpresson(source)      }       //遞歸結(jié)束的條件      if(source[0].type === "MultiplicativeExpresson")          return source[0];       return MultiplicativeExpresson(source);  }

          我們看一下當(dāng)source為"10 * 25 / 2"時調(diào)用console.log(MultiplicativeExpresson(source))最后運(yùn)行的結(jié)果:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題
          接下來看AdditiveExpression 本質(zhì)上和MultiplicativeExpresson沒有什么不同,差異點(diǎn)已經(jīng)標(biāo)注在代碼當(dāng)中了:

              function AdditiveExpression(source){         if(source[0].type === "MultiplicativeExpresson") {             let node = {                 type: "AdditiveExpression",                 children:[source[0]]             }             source[0] = node;             return AdditiveExpression(source)         }          //如果是乘號或者除號,則將三項(xiàng)出棧,進(jìn)行重組         if(source[0].type === "AdditiveExpression" && source[1] && source[1].type === "+") {             let node = {                 type: "AdditiveExpression",                 operator: "+",                 children: []             }             node.children.push(source.shift());             node.children.push(source.shift());             //考慮到第三個數(shù)可能時Number 需要在這里再次調(diào)用一下 MultiplicativeExpresson 做處理             MultiplicativeExpresson(source);             node.children.push(source.shift());             source.unshift(node);             return AdditiveExpression(source)         }          if(source[0].type === "AdditiveExpression" && source[1] && source[1].type === "-") {             let node = {                 type: "AdditiveExpression",                 operator: "-",                 children: []             }             node.children.push(source.shift());             node.children.push(source.shift());             MultiplicativeExpresson(source);             node.children.push(source.shift());             source.unshift(node);             return AdditiveExpression(source)         }          //遞歸結(jié)束的條件         if(source[0].type === "AdditiveExpression")             return source[0];          //第一次進(jìn)循環(huán) 調(diào)用         MultiplicativeExpresson(source);         return AdditiveExpression(source);     }

          我們看一下當(dāng)source為"10 * 25 / 2"時調(diào)用console.log(AdditiveExpression(source))最后運(yùn)行的結(jié)果:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題
          那么Expression的代碼邏輯就很好表達(dá)了:

          function Expression(tokens) {      if(source[0].type === "AdditiveExpression" && source[1] && source[1].type === "EOF") {          let node = {              type: "Expression",              children: [source.shift(), source.shift()]          }          source.unshift(node);          return node;      }      AdditiveExpression(source);      return Expression(source);  }

          看下運(yùn)行后的結(jié)果:
          談?wù)凧S實(shí)現(xiàn)AST抽象語法樹問題

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號