亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長資訊網(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>

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

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

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

    詞法分析

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

    <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)行比較,判斷是否有字符串沒有匹配上。
    將整個(gè)函數(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"時(shí)調(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());             //考慮到第三個(gè)數(shù)可能時(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"時(shí)調(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號