成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript語法解析與抽象語法樹(AST)----Espsrima的使用方法

Kaede / 3446人閱讀

摘要:語法解析首先來看一下什么是抽象語法樹。抽象語法樹也稱為語法樹,指的是源代碼語法所對(duì)應(yīng)的樹狀結(jié)構(gòu)。也就是說,對(duì)于一種具體編程語言下的源代碼,通過構(gòu)建語法樹的形式將源代碼中的語句映射到樹中的每一個(gè)節(jié)點(diǎn)上。

前言

最近在分析微信小程序,需要統(tǒng)計(jì)以前代碼中所使用過的wx.api。思路為對(duì)js文件進(jìn)行語法分析,然后找出調(diào)用者為wx的成員表達(dá)式。

JavaScript語法解析

首先來看一下什么是抽象語法樹。抽象語法樹(Abstract Syntax Tree)也稱為AST語法樹,指的是源代碼語法所對(duì)應(yīng)的樹狀結(jié)構(gòu)。也就是說,對(duì)于一種具體編程語言下的源代碼,通過構(gòu)建語法樹的形式將源代碼中的語句映射到樹中的每一個(gè)節(jié)點(diǎn)上。
可以通過一個(gè)demo來看一下什么是AST。
js代碼為

var a = 1;
function main() {
    console.log("this is a function");
}
main();

這段代碼的AST長(zhǎng)這樣:

可以發(fā)現(xiàn),代碼被映射成了一顆語法樹,有三個(gè)節(jié)點(diǎn),不同語句映射成不同的節(jié)點(diǎn)。那么我們便可以通過操作語法樹來準(zhǔn)確的獲得代碼中的某個(gè)節(jié)點(diǎn),對(duì)代碼進(jìn)行分析等。

Espsrima

Espsrima是一個(gè)較為成熟的JavaScript語法解析開源項(xiàng)目。使用Espsrima對(duì)js代碼進(jìn)行語法解析的步驟如下:

1. 準(zhǔn)備環(huán)境

我們使用node來構(gòu)建能夠在命令行中運(yùn)行的js代碼。所以首先確保安裝了node環(huán)境。
然后創(chuàng)建項(xiàng)目目錄。

新建一個(gè)文件夾,比如我新建一個(gè)‘espsrima’的文件夾。

進(jìn)入該文件夾

cd espsrima。

安裝庫(kù)接下來要用到的庫(kù)

npm install esprima --save  
npm install estraverse --save

在根目錄下新建index.js文件,初始代碼如下

var fs = require("fs"),  
    esprima = require("esprima");  
  
function analyzeCode(code) {  
    // 1  
}  
  
// 2  
if (process.argv.length < 3) {  
    console.log("Usage: index.js file.js");  
    process.exit(1);  
}  
  
// 3  
var filename = process.argv[2];  
console.log("Reading " + filename);  
var code = fs.readFileSync(filename);  
  
analyzeCode(code);  
console.log("Done");  
2. 解析js代碼并分析數(shù)據(jù)

esprima 將代碼解析為語法樹,Estraverse則用來對(duì)節(jié)點(diǎn)進(jìn)行遍歷。我們?nèi)砸赃@段代碼為例

var a = 1;
function main() {}
wx.laod();

我們看下這段代碼節(jié)點(diǎn)遍歷的結(jié)果,結(jié)果太長(zhǎng)截圖其中一部分:

從圖中看出,type代表節(jié)點(diǎn)類型,如函數(shù)聲明FunctionDeclaration和函數(shù)調(diào)用 CallExpression。我們的目的是找出所有的wx.xxx的函數(shù),所以我們主要關(guān)注函數(shù)調(diào)用類型。我們來看基本的函數(shù)調(diào)用代碼:

"expression": {  
    "type": "CallExpression",  
    "callee": {  
        "type": "Identifier",  
        "name": "myAwesomeFunction"  
    },  
    "arguments": []  
}  

對(duì)函數(shù)調(diào)用而言,即節(jié)點(diǎn)類型為 CallExpression,callee指向被調(diào)用函數(shù)。
我們?cè)賮砜聪滦稳?"wx.xxx"的代碼

CallExpression: {
  type: "CallExpression",
  callee: 
   StaticMemberExpression {
     type: "MemberExpression",
     computed: false,
     object: Identifier { type: "Identifier", name: "wx" },
     property: Identifier { type: "Identifier", name: "laod" } },
  arguments: [] 
    
}

可以看到,節(jié)點(diǎn)類型仍然為 CallExpression,callee的類型為 MemberExpression, callee的object name為wx??梢来颂岢鰓x.xxx。

3. 輔助函數(shù)

首先需要一個(gè)對(duì)象functionsStats,用來存儲(chǔ)提取的api。其次,需要一個(gè)"對(duì)象去重函數(shù)addStatsEntry".最后需要一個(gè)函數(shù)對(duì)functionsStats進(jìn)行處理,將結(jié)果寫到本地。 經(jīng)過以上的分析,最終的代碼如下:

var fs = require("fs"),  
    esprima = require("esprima"),
    estraverse = require("estraverse");

function addStatsEntry(funcName) {
    if (!functionsStats[funcName]) {  
        functionsStats[funcName] = { calls: 0 };  
    } 
}
// 寫文件
function writeResult(str) {
    fs.writeFileSync("result.txt", str, "utf8", (err) => {
        if (err) throw err;
        console.log("It"s saved!");
    });
}

// 結(jié)果處理函數(shù)
function processResults(results) {  
    var str = "";
    for (var name in results) {  
        if (results.hasOwnProperty(name)) {  
            var stats = results[name];
            var apiName = "wx."+ name;
            console.log("name:", apiName);
            str += apiName+ "
";
        }  
    }  
    writeResult(str);
} 

function analyzeCode(code) {  
    var ast = esprima.parse(code);  
    var functionsStats = {}; //1  
  
    estraverse.traverse(ast, {  
        enter: function (node) { 
            if (node.type === "CallExpression" && node.callee.type === "MemberExpression") {  
                if(node.callee.object.name === "wx") {
                    addStatsEntry(node.callee.property.name);
                    functionsStats[node.callee.property.name].calls++;
                }
            }  
        }  
    }); 
    processResults(functionsStats);  
}   

 
if (process.argv.length < 3) {  
    console.log("Usage: index.js file.js");  
    process.exit(1);  
}  
  
var filename = process.argv[2];  
console.log("Reading " + filename);  
var code = fs.readFileSync(filename, { encoding: "utf8" });  
  
analyzeCode(code);  

可以看到類似以下的處理結(jié)果

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92998.html

相關(guān)文章

  • 關(guān)于JavaScript編譯原理

    摘要:引擎負(fù)責(zé)整個(gè)程序的編譯和執(zhí)行過程編譯器負(fù)責(zé)語法分析和代碼生成作用域收集和維護(hù)一系列查詢由所有聲明的標(biāo)識(shí)符組成例子聲明一個(gè)變量并賦值編譯器對(duì)該程序段分解成詞法單元編譯器對(duì)以上的詞法單元解析成一個(gè)樹結(jié)構(gòu)抽象語法樹的語法解析器提供了一個(gè)在線解析的 引擎:負(fù)責(zé)整個(gè)js程序的編譯和執(zhí)行過程編譯器:負(fù)責(zé)語法分析和代碼生成作用域:收集和維護(hù)一系列查詢(由所有聲明的標(biāo)識(shí)符組成) 【例子:聲明一個(gè)變量并...

    anquan 評(píng)論0 收藏0
  • WebAssembly 那些事兒

    摘要:的目標(biāo)是對(duì)高級(jí)程序中間表示的適當(dāng)?shù)图?jí)抽象,即代碼旨在由編譯器生成而不是由人來寫。表示把源代碼變成解釋器可以運(yùn)行的代碼所花的時(shí)間表示基線編譯器和優(yōu)化編 WebAssembly 那些事兒 什么是 WebAssembly? WebAssembly 是除 JavaScript 以外,另一種可以在網(wǎng)頁(yè)中運(yùn)行的編程語言,并且相比之下在某些功能和性能問題上更具優(yōu)勢(shì),過去我們想在瀏覽器中運(yùn)行代碼來對(duì)網(wǎng)...

    邱勇 評(píng)論0 收藏0
  • JavaScript 是如何工作解析抽象語法AST)+ 提升編譯速度5個(gè)技巧

    摘要:無論你使用的是解釋型語言還是編譯型語言,都有一個(gè)共同的部分將源代碼作為純文本解析為抽象語法樹的數(shù)據(jù)結(jié)構(gòu)。和抽象語法樹相對(duì)的是具體語法樹,通常稱作分析樹。這是引入字節(jié)碼緩存的原因。 這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 14 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過了前面的章節(jié),可以在這里找到它們: JavaS...

    raoyi 評(píng)論0 收藏0
  • 高級(jí)前端基礎(chǔ)-JavaScript抽象語法AST

    摘要:本文主要介紹解析生成的抽象語法樹節(jié)點(diǎn),的實(shí)現(xiàn)也是基于的。原文地址解析器是把源碼轉(zhuǎn)化為抽象語法樹的解析器。參考文獻(xiàn)前端進(jìn)階之抽象語法樹抽象語法樹 前言 Babel為當(dāng)前最流行的代碼JavaScript編譯器了,其使用的JavaScript解析器為babel-parser,最初是從Acorn 項(xiàng)目fork出來的。Acorn 非???,易于使用,并且針對(duì)非標(biāo)準(zhǔn)特性(以及那些未來的標(biāo)準(zhǔn)特性) 設(shè)...

    verano 評(píng)論0 收藏0
  • 抽象語法(Abstract Syntax Tree)

    摘要:例如會(huì)被分解成解析語法分析這個(gè)過程是將詞法單元流數(shù)組轉(zhuǎn)換成一個(gè)由元素逐級(jí)嵌套所組成的代表了程序語法結(jié)構(gòu)的樹,這個(gè)樹就叫抽象語法樹。常用的有使用生成并使用抽象語法樹。 一般來說,程序中的一段源代碼在執(zhí)行之前會(huì)經(jīng)歷下面三個(gè)步驟1 分詞/詞法分析這個(gè)過程會(huì)將由字符組成的字符串分解成有意義的代碼快,這些代碼塊被稱為詞法單元。例如 var a = 4;會(huì)被分解成 var、a、=、4、; 2 解析...

    余學(xué)文 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<