摘要:實現(xiàn)狀態(tài)機可能產(chǎn)生四種輸入元素,其中只有兩種,狀態(tài)機的第一個狀態(tài)就是根據(jù)第一個輸入字符來判斷進入了哪種狀態(tài)用函數(shù)表示狀態(tài),用表示狀態(tài)的遷移關(guān)系,用值表示下一個狀態(tài)。運行狀態(tài)機輸出結(jié)果四語法分析語法分析根據(jù)每一個產(chǎn)生式來寫一個函數(shù)。
筆記說明
重學(xué)前端是程劭非(winter)【前手機淘寶前端負責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點筆記以及感悟,完整的可以加入winter的專欄學(xué)習(xí)【原文有winter的語音】,如有侵權(quán)請聯(lián)系我,郵箱:[email protected]。一、分析
按照編譯原理相關(guān)的知識,將其分成幾個步驟。
定義四則運算:產(chǎn)出四則運算的詞法定義和語法定義。
詞法分析:把輸入的字符串流變成 token。
語法分析:把 token 變成抽象語法樹 AST。
解釋執(zhí)行:后序遍歷 AST,執(zhí)行得出結(jié)果。
二、定義四則運算 2.1、定義詞法
Token
Number: 1 2 3 4 5 6 7 8 9 0 的組合
Operator: +、-、*、/ 之一
Whitespace:
LineTerminator:
語法定義多數(shù)采用 BNF。巴科斯范式(BNF: Backus-Naur Form 的縮寫)是由 John Backus 和 Peter Naur 首次引入一種形式化符號來描述給定語言的語法(最早用于描述ALGOL 60 編程語言)。JavaScript 標(biāo)準(zhǔn)里面就是一種跟 BNF 類似的自創(chuàng)語法。
1、加法是由若干個乘法再由加號或者減號連接成的:
::= ::= | <+> | <->
2、可把普通數(shù)字當(dāng)成乘法的一種特例:
::= | <*> | >
上面就是四則運算的定義。
三、詞法分析:狀態(tài)機詞法分析:把字符流變成 token 流,有兩種方案,一種是狀態(tài)機,一種是正則表達式,它們是等效的。3.1、實現(xiàn)狀態(tài)機
// 可能產(chǎn)生四種輸入元素,其中只有兩種 token,狀態(tài)機的第一個狀態(tài)就是根據(jù)第一個輸入字符來判斷進入了哪種狀態(tài) var token = []; function start(char) { if(char === "1" || char === "2"|| char === "3" || char === "4"|| char === "5"|| char === "6"|| char === "7" || char === "8"|| char === "9"|| char === "0") { token.push(char); return inNumber; } if(char === "+" || char === "-" || char === "*" || char === "/") { emmitToken(char, char); return start } if(char === " ") { return start; } if(char === " " || char === " ") { return start; } } function inNumber(char) { if ( char === "1" || char === "2" || char === "3" || char === "4"|| char === "5" || char === "6" || char === "7" || char === "8" || char === "9" || char === "0") { token.push(char); return inNumber; } else { emmitToken("Number", token.join("")); token = []; // put back char return start(char); } } // 用函數(shù)表示狀態(tài),用 if 表示狀態(tài)的遷移關(guān)系,用 return 值表示下一個狀態(tài)。3.2、運行狀態(tài)機
function emmitToken(type, value) { console.log(value); } var input = "1024 + 2 * 256" var state = start; for(var c of input.split("")) state = state(c); state(Symbol("EOF")) // 輸出結(jié)果 1024 + 2 * 256四、語法分析:LL
LL 語法分析根據(jù)每一個產(chǎn)生式來寫一個函數(shù)。4.1、寫好函數(shù)名
function AdditiveExpression( ){ } function MultiplicativeExpression(){ }4.2、假設(shè)已經(jīng)拿到 token
var tokens = [{ type:"Number", value: "1024" }, { type:"+", value: "+" }, { type:"Number", value: "2" }, { type:"*", value: "*" }, { type:"Number", value: "256" }, { type:"EOF" }];4.3、AdditiveExpression處理
1、三種情況
::= | <+> | <->
2、AdditiveExpression 的寫法
AdditiveExpression 的寫法是根傳入的節(jié)點,利用產(chǎn)生式合成新的節(jié)點。
function AdditiveExpression(source){ if(source[0].type === "MultiplicativeExpression") { let node = { type:"AdditiveExpression", children:[source[0]] } source[0] = node; return node; } if(source[0].type === "AdditiveExpression" && source[1].type === "+") { let node = { type:"AdditiveExpression", operator:"+", children:[source.shift(), source.shift(), MultiplicativeExpression(source)] } source.unshift(node); } if(source[0].type === "AdditiveExpression" && source[1].type === "-") { let node = { type:"AdditiveExpression", operator:"-", children:[source.shift(), source.shift(), MultiplicativeExpression(source)] } source.unshift(node); } }4.4、函數(shù) Expression 處理
1、把解析好的 token 傳給的頂層處理函數(shù) Expression。
Expression(tokens);
2、如果 Expression 收到第一個 token,是個 Number,就需要對產(chǎn)生式的首項層層展開,根據(jù)所有可能性調(diào)用相應(yīng)的處理函數(shù),這個過程在編譯原理中稱為求 closure。
function Expression(source){ 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); } function AdditiveExpression(source){ if(source[0].type === "MultiplicativeExpression") { let node = { type:"AdditiveExpression", children:[source[0]] } source[0] = 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()); MultiplicativeExpression(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()); MultiplicativeExpression(source); node.children.push(source.shift()); source.unshift(node); return AdditiveExpression(source); } if(source[0].type === "AdditiveExpression") return source[0]; MultiplicativeExpression(source); return AdditiveExpression(source); } function MultiplicativeExpression(source){ if(source[0].type === "Number") { let node = { type:"MultiplicativeExpression", children:[source[0]] } source[0] = node; return MultiplicativeExpression(source); } if(source[0].type === "MultiplicativeExpression" && source[1] && source[1].type === "*") { let node = { type:"MultiplicativeExpression", operator:"*", children:[] } node.children.push(source.shift()); node.children.push(source.shift()); node.children.push(source.shift()); source.unshift(node); return MultiplicativeExpression(source); } if(source[0].type === "MultiplicativeExpression"&& source[1] && source[1].type === "/") { let node = { type:"MultiplicativeExpression", operator:"/", children:[] } node.children.push(source.shift()); node.children.push(source.shift()); node.children.push(source.shift()); source.unshift(node); return MultiplicativeExpression(source); } if(source[0].type === "MultiplicativeExpression") return source[0]; return MultiplicativeExpression(source); }; var source = [{ type:"Number", value: "3" }, { type:"*", value: "*" }, { type:"Number", value: "300" }, { type:"+", value: "+" }, { type:"Number", value: "2" }, { type:"*", value: "*" }, { type:"Number", value: "256" }, { type:"EOF" }]; var ast = Expression(source); console.log(ast); // 輸出結(jié)果 children: Array(1) children: Array(3)還可以繼續(xù)展開。。。 { type: "Expression", children: [ { type: "AdditiveExpression", operator: "+", children: [ { type: "AdditiveExpression", children: Array(1) }, { type: "+", value: "+" }, { type: "MultiplicativeExpression", operator: "*", children: Array(3) } ] }, { type: "EOF" } ] }五、解釋執(zhí)行
得到了 AST 之后,只需要對這個樹做遍歷操作執(zhí)行即可。
// 根據(jù)不同的節(jié)點類型和其它信息,用 if 分別處理即可: function evaluate(node) { if(node.type === "Expression") { return evaluate(node.children[0]) } if(node.type === "AdditiveExpression") { if(node.operator === "-") { return evaluate(node.children[0]) - evaluate(node.children[2]); } if(node.operator === "+") { return evaluate(node.children[0]) + evaluate(node.children[2]); } return evaluate(node.children[0]) } if(node.type === "MultiplicativeExpression") { if(node.operator === "*") { return evaluate(node.children[0]) * evaluate(node.children[2]); } if(node.operator === "/") { return evaluate(node.children[0]) / evaluate(node.children[2]); } return evaluate(node.children[0]) } if(node.type === "Number") { return Number(node.value); } }個人總結(jié)
這下完全懵逼了 _(:3」∠)_
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104453.html
摘要:實現(xiàn)狀態(tài)機可能產(chǎn)生四種輸入元素,其中只有兩種,狀態(tài)機的第一個狀態(tài)就是根據(jù)第一個輸入字符來判斷進入了哪種狀態(tài)用函數(shù)表示狀態(tài),用表示狀態(tài)的遷移關(guān)系,用值表示下一個狀態(tài)。運行狀態(tài)機輸出結(jié)果四語法分析語法分析根據(jù)每一個產(chǎn)生式來寫一個函數(shù)。 筆記說明 重學(xué)前端是程劭非(winter)【前手機淘寶前端負責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點...
摘要:實現(xiàn)狀態(tài)機可能產(chǎn)生四種輸入元素,其中只有兩種,狀態(tài)機的第一個狀態(tài)就是根據(jù)第一個輸入字符來判斷進入了哪種狀態(tài)用函數(shù)表示狀態(tài),用表示狀態(tài)的遷移關(guān)系,用值表示下一個狀態(tài)。運行狀態(tài)機輸出結(jié)果四語法分析語法分析根據(jù)每一個產(chǎn)生式來寫一個函數(shù)。 筆記說明 重學(xué)前端是程劭非(winter)【前手機淘寶前端負責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點...
摘要:申明與賦值立即執(zhí)行的函數(shù)表達式,通過創(chuàng)建一個函數(shù),并且立即執(zhí)行,來構(gòu)造一個新的域,從而控制的范圍。函數(shù)接受一個的形參,該參數(shù)是一個對象引用,并執(zhí)行了。在最新的標(biāo)準(zhǔn)中,引入了一個新概念。 筆記說明 重學(xué)前端是程劭非(winter)【前手機淘寶前端負責(zé)人】在極客時間開的一個專欄,每天10分鐘,重構(gòu)你的前端知識體系,筆者主要整理學(xué)習(xí)過程的一些要點筆記以及感悟,完整的可以加入winter的專欄...
閱讀 3072·2021-10-12 10:12
閱讀 1582·2021-09-09 11:39
閱讀 1909·2019-08-30 15:44
閱讀 2354·2019-08-29 15:23
閱讀 2906·2019-08-29 15:18
閱讀 2973·2019-08-29 13:02
閱讀 2698·2019-08-26 18:36
閱讀 747·2019-08-26 12:08