久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合

站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

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

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

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

前端中的AST抽象語(yǔ)法樹(shù)問(wèn)題

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

四則運(yùn)算

首先明確,此次的代碼都是基于LL的語(yǔ)法分析來(lái)實(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抽象語(yǔ)法樹(shù)問(wèn)題

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

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

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

詞法分析

我們?cè)谶@一部分對(duì)上面的代碼做優(yōu)化。
首先是剛才提到的:
當(dāng) RegExpObject 是一個(gè)全局正則表達(dá)式時(shí),exec() 的行為就稍微復(fù)雜一些。它會(huì)在 RegExpObject 的 lastIndex 屬性指定的字符處開(kāi)始檢索字符串 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>

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

語(yǔ)法分析

首先編寫(xiě)分塊的產(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來(lái)進(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)      }       //如果是乘號(hào)或者除號(hào),則將三項(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抽象語(yǔ)法樹(shù)問(wèn)題
接下來(lái)看AdditiveExpression 本質(zhì)上和MultiplicativeExpresson沒(méi)有什么不同,差異點(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)         }          //如果是乘號(hào)或者除號(hào),則將三項(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抽象語(yǔ)法樹(shù)問(wèn)題
那么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抽象語(yǔ)法樹(shù)問(wèn)題

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
久久精品五月,日韩不卡视频在线观看,国产精品videossex久久发布 ,久久av综合
狠狠久久婷婷| 青青在线精品| 亚洲色诱最新| 欧美激情三区| 欧美日韩精品免费观看视欧美高清免费大片 | 国产精品久久久久蜜臀| 亚洲精品黄色| 99久久夜色精品国产亚洲1000部| www.com.cn成人| 精品一区二区三区四区五区| 中文字幕在线高清| 国产伦理一区| 99视频精品视频高清免费| 国产福利亚洲| 鲁鲁在线中文| 另类专区亚洲| 国产精品调教| 国语对白精品一区二区| 亚洲va在线| 国产麻豆久久| 亚洲一区日本| 91精品二区| 图片区亚洲欧美小说区| 久久天堂av| 久久伦理在线| 国产亚洲网站| 久久夜色精品| 国产精品普通话对白| 免费观看在线综合| 麻豆传媒一区二区三区| 群体交乱之放荡娇妻一区二区| 中文在线不卡| 国产精品日本一区二区三区在线| 欧美日韩国产高清| 亚洲婷婷丁香| 日韩综合一区| 日本视频一区二区| 玖玖玖国产精品| 欧美激情精品| 蜜臀va亚洲va欧美va天堂 | 国产精品久久久久久久久久妞妞| 精品黄色一级片| 久久裸体视频| 久久免费视频66| 日韩av一二三| 精品久久影院| 国产中文在线播放| 日韩va欧美va亚洲va久久| 午夜久久av | 久久中文字幕av一区二区不卡| 日产欧产美韩系列久久99| 中文精品在线| 亚洲日本网址| 国产成人久久| 国产精品激情| 国产精品大片免费观看| 国产日韩亚洲| 国产精品成人3p一区二区三区| 91精品久久久久久久久久不卡| 777久久精品| 综合亚洲自拍| 国产精品一区二区av日韩在线| 婷婷综合社区| 欧美精品aa| 美女视频黄 久久| 久久精品99久久久| 亚洲精品乱码| 国产精品2区| aa国产精品| 日本三级亚洲精品| 男人天堂欧美日韩| 国产精品一区二区三区www | 久久激情网站| 日韩高清不卡一区二区| 久久精品国产在热久久| 欧美日韩激情| 怡红院精品视频在线观看极品| 视频一区日韩精品| 国产欧美三级| 国产精品视频一区二区三区四蜜臂 | 国产精品自拍区| 丝袜美腿成人在线| 久久国产亚洲| 国产精品永久| 久久久亚洲欧洲日产| 亚洲一级淫片| 嫩呦国产一区二区三区av| 国产亚洲在线观看| 高潮一区二区| 中文字幕一区二区三区在线视频| 日韩av成人高清| 国产精品丝袜xxxxxxx| 日韩不卡一区二区三区| 亚久久调教视频| 日本中文字幕不卡| 国产亚洲欧美日韩精品一区二区三区| 免费久久99精品国产| 亚洲精品日韩久久| 天堂√8在线中文| 久久国产日韩欧美精品| 久久精品官网| 欧美男人天堂| 日韩av中文字幕一区二区| 精品国产乱码久久久| 国产精品99精品一区二区三区∴| 欧美日韩视频免费观看| 欧美日韩亚洲一区| 亚洲精品麻豆| 激情欧美丁香| 亚洲精品乱码久久久久久蜜桃麻豆| 亚洲成人精品| 午夜久久tv| 在线精品一区| 国产精品久久久免费| 性欧美长视频| 欧美成人基地 | 男女激情视频一区| 亚洲色诱最新| 国产精品一在线观看| 久久要要av| 日本91福利区| 韩国久久久久久| 欧美黄页在线免费观看| 欧美视频久久| 天堂√8在线中文| 亚洲一区有码| 日韩影院二区| 日韩久久电影| 久久久久久久久久久妇女| 妖精视频成人观看www| 久久精品av| 精品国产乱码久久久| 亚洲二区在线| 国产精品欧美大片| 日韩精品一区二区三区免费视频| 欧美视频久久| 国产精品88久久久久久| 日韩在线视频一区二区三区| 国产精品一区二区三区av麻| 成人免费电影网址| 欧美影院三区| 婷婷综合国产| 香蕉精品久久| 欧美91视频| 99精品视频在线| 蜜桃久久av一区| 欧美精品观看| 日韩精品视频网| 欧美日韩四区| 日韩国产欧美三级| 日本在线视频一区二区| 日韩精品成人在线观看| 亚洲精品91| 久久久人人人| 五月天激情综合网| 欧美日韩国产观看视频| 首页亚洲欧美制服丝腿| 日韩国产激情| 国产精品亚洲欧美| 青青青国产精品| 日韩av一二三| 国产精品亚洲综合色区韩国| 蜜桃av.网站在线观看| 欧美在线资源| 日韩美女国产精品| 视频一区视频二区中文| 视频一区在线视频| 亚洲精品1区2区| 香蕉久久夜色精品国产| 日韩在线中文| 亚洲激情另类| 99久久婷婷| 国产aⅴ精品一区二区四区| 日韩av一区二| 国产日韩一区| 福利一区在线| 美女国产精品| 欧美日韩调教| 国产精品啊啊啊| 久久久久久久久久久9不雅视频| 蜜桃视频免费观看一区| 视频小说一区二区| 国产精品mv在线观看| 国产极品久久久久久久久波多结野| 日韩av在线免费观看不卡| 91麻豆精品激情在线观看最新| 亚洲网站视频| 国产伊人久久| 国内揄拍国内精品久久| 一区二区三区网站| 中文字幕一区日韩精品| 亚洲精品视频一二三区| 国产伦精品一区二区三区视频| 日本aⅴ亚洲精品中文乱码| 国产精品第一国产精品| 在线看片一区| 日本午夜精品一区二区三区电影 | 久久www成人_看片免费不卡| 一本大道色婷婷在线| 日韩久久视频|