摘要:語法解析首先來看一下什么是抽象語法樹。抽象語法樹也稱為語法樹,指的是源代碼語法所對應的樹狀結構。也就是說,對于一種具體編程語言下的源代碼,通過構建語法樹的形式將源代碼中的語句映射到樹中的每一個節點上。
前言
最近在分析微信小程序,需要統計以前代碼中所使用過的wx.api。思路為對js文件進行語法分析,然后找出調用者為wx的成員表達式。
JavaScript語法解析首先來看一下什么是抽象語法樹。抽象語法樹(Abstract Syntax Tree)也稱為AST語法樹,指的是源代碼語法所對應的樹狀結構。也就是說,對于一種具體編程語言下的源代碼,通過構建語法樹的形式將源代碼中的語句映射到樹中的每一個節點上。
可以通過一個demo來看一下什么是AST。
js代碼為
var a = 1; function main() { console.log("this is a function"); } main();
這段代碼的AST長這樣:
可以發現,代碼被映射成了一顆語法樹,有三個節點,不同語句映射成不同的節點。那么我們便可以通過操作語法樹來準確的獲得代碼中的某個節點,對代碼進行分析等。
EspsrimaEspsrima是一個較為成熟的JavaScript語法解析開源項目。使用Espsrima對js代碼進行語法解析的步驟如下:
1. 準備環境我們使用node來構建能夠在命令行中運行的js代碼。所以首先確保安裝了node環境。
然后創建項目目錄。
新建一個文件夾,比如我新建一個‘espsrima’的文件夾。
進入該文件夾
cd espsrima。
安裝庫接下來要用到的庫
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代碼并分析數據
esprima 將代碼解析為語法樹,Estraverse則用來對節點進行遍歷。我們仍以這段代碼為例
var a = 1; function main() {} wx.laod();
我們看下這段代碼節點遍歷的結果,結果太長截圖其中一部分:
從圖中看出,type代表節點類型,如函數聲明FunctionDeclaration和函數調用 CallExpression。我們的目的是找出所有的wx.xxx的函數,所以我們主要關注函數調用類型。我們來看基本的函數調用代碼:
"expression": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "myAwesomeFunction" }, "arguments": [] }
對函數調用而言,即節點類型為 CallExpression,callee指向被調用函數。
我們再來看下形如 "wx.xxx"的代碼
CallExpression: { type: "CallExpression", callee: StaticMemberExpression { type: "MemberExpression", computed: false, object: Identifier { type: "Identifier", name: "wx" }, property: Identifier { type: "Identifier", name: "laod" } }, arguments: [] }
可以看到,節點類型仍然為 CallExpression,callee的類型為 MemberExpression, callee的object name為wx??梢来颂岢鰓x.xxx。
3. 輔助函數首先需要一個對象functionsStats,用來存儲提取的api。其次,需要一個"對象去重函數addStatsEntry".最后需要一個函數對functionsStats進行處理,將結果寫到本地。 經過以上的分析,最終的代碼如下:
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!"); }); } // 結果處理函數 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);
可以看到類似以下的處理結果
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92998.html
摘要:引擎負責整個程序的編譯和執行過程編譯器負責語法分析和代碼生成作用域收集和維護一系列查詢由所有聲明的標識符組成例子聲明一個變量并賦值編譯器對該程序段分解成詞法單元編譯器對以上的詞法單元解析成一個樹結構抽象語法樹的語法解析器提供了一個在線解析的 引擎:負責整個js程序的編譯和執行過程編譯器:負責語法分析和代碼生成作用域:收集和維護一系列查詢(由所有聲明的標識符組成) 【例子:聲明一個變量并...
摘要:的目標是對高級程序中間表示的適當低級抽象,即代碼旨在由編譯器生成而不是由人來寫。表示把源代碼變成解釋器可以運行的代碼所花的時間表示基線編譯器和優化編 WebAssembly 那些事兒 什么是 WebAssembly? WebAssembly 是除 JavaScript 以外,另一種可以在網頁中運行的編程語言,并且相比之下在某些功能和性能問題上更具優勢,過去我們想在瀏覽器中運行代碼來對網...
摘要:無論你使用的是解釋型語言還是編譯型語言,都有一個共同的部分將源代碼作為純文本解析為抽象語法樹的數據結構。和抽象語法樹相對的是具體語法樹,通常稱作分析樹。這是引入字節碼緩存的原因。 這是專門探索 JavaScript 及其所構建的組件的系列文章的第 14 篇。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! 如果你錯過了前面的章節,可以在這里找到它們: JavaS...
摘要:本文主要介紹解析生成的抽象語法樹節點,的實現也是基于的。原文地址解析器是把源碼轉化為抽象語法樹的解析器。參考文獻前端進階之抽象語法樹抽象語法樹 前言 Babel為當前最流行的代碼JavaScript編譯器了,其使用的JavaScript解析器為babel-parser,最初是從Acorn 項目fork出來的。Acorn 非???,易于使用,并且針對非標準特性(以及那些未來的標準特性) 設...
摘要:例如會被分解成解析語法分析這個過程是將詞法單元流數組轉換成一個由元素逐級嵌套所組成的代表了程序語法結構的樹,這個樹就叫抽象語法樹。常用的有使用生成并使用抽象語法樹。 一般來說,程序中的一段源代碼在執行之前會經歷下面三個步驟1 分詞/詞法分析這個過程會將由字符組成的字符串分解成有意義的代碼快,這些代碼塊被稱為詞法單元。例如 var a = 4;會被分解成 var、a、=、4、; 2 解析...
閱讀 3297·2021-11-16 11:45
閱讀 2655·2021-09-22 15:23
閱讀 564·2021-07-30 14:58
閱讀 459·2019-08-30 15:54
閱讀 2235·2019-08-29 16:19
閱讀 3016·2019-08-29 12:45
閱讀 935·2019-08-23 17:57
閱讀 1788·2019-08-23 17:54