日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVAScript黑科技:直接運行AST(抽象語法樹)

實現一個AST解釋器

一段JavaScript代碼,經過語法分析、語法分析等編譯過程之后,會形成一個對應的AST(抽象語法樹),形如:

JavaScript黑科技:實現一個AST解釋器

 

AST是一個JSON格式的大字符串,包含有代碼相關信息,如:成員表達式調用、參數、標識符、字符串字面量等等。如:

{"type":"File","program":{"type":"Program","body":[{"type":"ExpressionStatement","expression":{"type":"CallExpression","callee":{"type":"MemberExpression","object":{"type":"Identifier","name":"console"},"property":{"type":"Identifier","name":"log"}},"arguments":[{"type":"StringLiteral","value":"jshaman"}]}}]}}

上面,是一段AST。

本文將要實現的目標的:直接運行這段AST。

先展示運行效果,如下:

JavaScript黑科技:實現一個AST解釋器

 

即,運行后,輸出一了個字符串。

功能意義

其實,如果直接要輸出這樣一個字符串,在JavaScript中是極為簡單的,只需簡單的一句:console.log('jshaman')。

那么,為什么要轉化為復雜的AST,再執行AST呢?

其意義在于:我們將要實現一個AST解釋器,引申而言,實現一個JavaScript解釋器。在很多場景中,具有非常實用的意義。

比如,在小程序中屏蔽了Eval函數,而如果我們自己實現解釋器,將可突破這個限制。

又比如,JShaman研發團隊中,將它用于JavaScript代碼加密。

JavaScript黑科技:實現一個AST解釋器

 

Tip:JShaman是國內專業的JavaScript代碼保護研究團隊,擁有眾多自主的JS代碼加密方案,此為其一。

實現方案

要讓這個AST能被執行,即要依JavaScript代碼標準解釋AST。

首先,嘗試理解console.log('jshaman')這句代碼的AST。通過astexplorer查看:

JavaScript黑科技:實現一個AST解釋器

 

可以看到,這一句代碼轉成的AST中,包含7個節點。

那么,要執行這個AST,就要能正確處理這7種節點類型。

由于AST是JSON結構,處理時,可遍歷其所有的成員節點。參考astexplorer展示的節點,分別處理:File、Program、ExpressionStatement、CallExpression等,代碼如下:

JavaScript黑科技:實現一個AST解釋器

 

當遇到CallExpression時,獲取其對應的參數、方法名等,如下圖:

JavaScript黑科技:實現一個AST解釋器

 

并用Apply的方式進行執行,以返回結果。

原理即如此。

編碼時,對照著AST節點類型,完成相應的操作即可,為方便調試,可輸出節點類型加以分析,如下圖:

JavaScript黑科技:實現一個AST解釋器

 

完整源碼

完整源碼如下,保存為JS,在NodeJS環境中即可運行。也可在瀏覽器中直接運行代碼,更為方便。

//各節點處理器
var visitors = {
//File節點,JS代碼AST的根節點
File(node, scope) {
ast_excute(node.program, scope);
},
//File的次節點,其Body下對應各行JS代碼
Program(program, scope) {
for (i=0; i< program.body.length;i++) {
//執行各行代碼的AST
ast_excute(program.body[i], scope);
}
},
//Call調用AST之外會包裹有一層表達式語句結構
ExpressionStatement(node, scope) {
return ast_excute(node.expression, scope);
},
//Call調用
CallExpression(node, scope){
//遍歷callee獲取函數體
var func = ast_excute(node.callee, scope);
//獲取參數
var args = node.arguments.map( function(arg){
return ast_excute(arg, scope)
});

var value;
if (node.callee.type === 'MemberExpression') {
value = ast_excute(node.callee.object, scope);
}
//返回函數運行結果
return func.apply(value, args)
},
//成員表達式
MemberExpression(node, scope){
//獲取對象,如console
var obj = ast_excute(node.object, scope);
//獲取對象的方法,如log
var name = node.property.name
//返回表達式,如console.log
return obj[name]
},
//標識符
Identifier(node, scope) {
return scope[node.name];
},
//字符串字面量
StringLiteral(node) {
return node.value;
},
};
//執行
function ast_excute(node, scope) {
var _evalute = visitors[node.type];
if (!_evalute) {
throw new Error("未知的AST類型:" , node.type);
}
// 遞歸調用
return _evalute(node, scope);
}
var ast = {"type":"File","program":{"type":"Program","body":[{"type":"ExpressionStatement","expression":{"type":"CallExpression","callee":{"type":"MemberExpression","object":{"type":"Identifier","name":"console"},"property":{"type":"Identifier","name":"log"}},"arguments":[{"type":"StringLiteral","value":"jshaman"}]}}]}};
ast_excute(ast, {console});

AST簡化

以上代碼中,使用的是簡化過的AST。astexplorer默認生成的AST,內容較多,如下圖:

JavaScript黑科技:實現一個AST解釋器

 

其包含有代碼行號、起始、結束等位置信息:

JavaScript黑科技:實現一個AST解釋器

 

但這些冗長的位置信息對于執行是無用的,可以將其去除,實現簡化的AST:

JavaScript黑科技:實現一個AST解釋器

 

這樣就成為了代碼中使用的、較簡短的AST。

分享到:
標簽:JavaScript
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定