阅读更多

1顶
0踩

Web前端

转载新闻 JavaScript的语法解析与抽象语法树

2015-07-10 16:43 by 副主编 mengyidan1988 评论(0) 有19468人浏览
本文转自:http://wwsun.me/

抽象语法树(Abstract Syntax Tree)也称为AST语法树,指的是源代码语法所对应的树状结构。也就是说,对于一种具体编程语言下的源代码,通过构建语法树的形式将源代码中的语句映射到树中的每一个节点上。

JavaScript语法解析
什么是语法树

可以通过一个简单的例子来看语法树具体长什么样子。有如下代码:



我们可以发现,程序代码本身可以被映射成为一棵语法树,而通过操纵语法树,我们能够精准的获得程序代码中的某个节点。例如声明语句,赋值语句,而这是用正则表达式所不能准确体现的地方。JavaScript的语法解析器Espsrima提供了一个在线解析的工具,你可以借助于这个工具,将JavaScript代码解析为一个JSON文件表示的树状结构。

有什么用

抽象语法树的作用非常的多,比如编译器、IDE、压缩优化代码等。在JavaScript中,虽然我们并不会常常与AST直接打交道,但却也会经常的涉及到它。例如使用UglifyJS来压缩代码,实际这背后就是在对JavaScript的抽象语法树进行操作。

在一些实际开发过程中,我们也会用到抽象语法树,下面通过一个小栗子来看看怎么进行JavaScript的语法解析以及对节点的遍历与操纵。
举个例子
小需求
我们将构建一个简单的静态分析器,它可以从命令行进行运行。它能够识别下面几部分内容:
  • 已声明但没有被调用的函数
  • 调用了未声明的函数
  • 被调用多次的函数

现在我们已经知道了可以将代码映射为AST进行语法解析,从而找到这些节点。但是,我们仍然需要一个语法解析器才能顺利的进行工作,在JavaScript的语法解析领域,一个流行的开源项目是Esprima,我们可以利用这个工具来完成任务。此外,我们需要借助Node来构建能够在命令行运行的JS代码。b

完整代码地址:
https://github.com/wwsun/awesome-javascript/tree/master/src/day05

准备工作

为了能够完成后面的工作,你需要确保安装了Node环境。首先创建项目的基本目录结构,以及初始化NPM。
mkdir esprima-tutorial
cd esprima-tutorial
npm install esprima --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');

在上面的代码中:

1.函数analyzeCode用于执行主要的代码分析工作,这里我们暂时预留下来这部分工作待后面去解决。
2.我们需要确保用户在命令行中指定了分析文件的具体位置,这可以通过查看process.argv的长度来得到。为什么?你可以参考Node的官方文档:
引用
The first element will be ‘node’, the second element will be the name of the JavaScript file. The next elements will be any additional command line arguments.

3.获取文件,并将文件传入到analyzeCode函数中进行处理
解析代码和遍历AST

借助Esprima解析代码非常简单,只要使用一个方法即可:
var ast = esprima.parse(code);

esprima.parse()方法接收两种类型的参数:字符串或Node的Buffer对象,它也可以收附加的选项作为参数。解析后返回结果即为抽象语法树(AST),AST遵守Mozilla SpiderMonkey的解析器API。例如代码:
引用
6 * 7

解析后的结果为:
{
    "type": "Program",
    "body": [
        {
            "type": "ExpressionStatement",
            "expression": {
                "type": "BinaryExpression",
                "operator": "*",
                "left": {
                    "type": "Literal",
                    "value": 6,
                    "raw": "6"
                },
                "right": {
                    "type": "Literal",
                    "value": 7,
                    "raw": "7"
                }
            }
        }
    ]
}

我们可以发现每个节点都有一个type,根节点的type为Program。type也是所有节点都共有的,其他的属性依赖于节点的type。例如上面实例的程序中,我们可以发现根节点下面的子节点的类型为EspressionStatement,依此类推。

为了能够分析代码,我们需要对得到的AST进行遍历,我们可以借助Estraverse进行节点的遍历。执行如下命令进行安装该NPM包:
npm install estraverse --save

基本用法如下:
function analyzeCode(code) {
    var ast = esprima.parse(code);
    estraverse.traverse(ast, {
        enter: function (node) {
            console.log(node.type);
        }
    });
}

上面的代码会输出遇到的语法树上每个节点的类型。

获取分析数据

为了完成需求,我们需要遍历语法树,并统计每个函数调用和声明的次数。因此,我们需要知道两种节点类型。首先是函数声明:
{
    "type": "FunctionDeclaration",
    "id": {
        "type": "Identifier",
        "name": "myAwesomeFunction"
    },
    "params": [
        ...
    ],
    "body": {
        "type": "BlockStatement",
        "body": [
            ...
        ]
    }
}

对函数声明而言,其节点类型为FunctionDeclaration,函数的标识符(即函数名)存放在id节点中,其中name子属性即为函数名。params和body分别为函数的参数列表和函数体。

我们再来看函数调用:
"expression": {
    "type": "CallExpression",
    "callee": {
        "type": "Identifier",
        "name": "myAwesomeFunction"
    },
    "arguments": []
}

对函数调用而言,即节点类型为CallExpression,callee指向被调用的函数。有了上面的了解,我们可以继续完成我们的程序如下:
function analyzeCode(code) {
    var ast = esprima.parse(code);

    var functionsStats = {}; //1

    var addStatsEntry = function (funcName) { //2
        if (!functionsStats[funcName]) {
            functionsStats[funcName] = { calls: 0, declarations: 0 };
        }
    };

	// 3
    estraverse.traverse(ast, {
        enter: function (node) {
            if (node.type === 'FunctionDeclaration') {
                addStatsEntry(node.id.name); //4
                functionsStats[node.id.name].declarations++;
            } else if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
                addStatsEntry(node.callee.name);
                functionsStats[node.callee.name].calls++; //5
            }
        }
    });
}

1.我们创建了一个对象functionStats用来存放函数的调用和声明的统计信息,函数名作为key。
2.函数addStatsEntry用于实现存放统计信息。
3.遍历AST
4.如果发现了函数声明,增加一次函数声明
5.如果发现了函数调用,增加一次函数调用
处理结果

最后进行结果的处理,我们只需要遍历查看functionStats中的信息就可以得到结果。创建结果处理函数如下:
function processResults(results) {
    for (var name in results) {
        if (results.hasOwnProperty(name)) {
            var stats = results[name];
            if (stats.declarations === 0) {
                console.log('Function', name, 'undeclared');
            } else if (stats.declarations > 1) {
                console.log('Function', name, 'decalred multiple times');
            } else if (stats.calls === 0) {
                console.log('Function', name, 'declared but not called');
            }
        }
    }
}

然后,在analyzeCode函数的末尾调用该函数即可,如下:
processResults(functionsStats);

测试

创建测试文件demo.js如下:
function declaredTwice() {
}

function main() {
    undeclared();
}

function unused() {
}

function declaredTwice() {
}

main();

执行如下命令:
$ node index.js demo.js

你将得到如下的处理结果:
引用

Reading test.js
Function declaredTwice decalred multiple times
Function undeclared undeclared
Function unused declared but not called
Done

小结
是时候进行小结,本文主要介绍了如何对JavaScript代码使用Esprima进行解析,解析后的结果是一棵符合SpiderMonkey解析API的语法树,然后我们使用Estraverse进行遍历,在遍历过程中我们通过识别节点类型来判断代码位置。最后,如果你需要修改节点,你可以参考[3]。

References
1.Esprima tutorial
2.Fun with Esprima and Static Analysis
3.Parsing and modifying JavaScript code with Esprima and Scodegen

本文转自:http://wwsun.me/
  • 大小: 84.2 KB
来自: wwsun.me
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • treehugger:JavaScript AST(抽象语法树)转换工具

    现在: Javascript:一个(基于的)解析器,分析重建类型结构并首先尝试进行类型推断。 lib/treehugger/js/*.js 该项目依赖进行库加载。 AST表示 ast.js使用一些简单的数据结构来表示AST,并使用文本表示形式来...

  • JavaScript语法解析与抽象语法树(AST)----Espsrima的使用方法

    前言 最近在分析微信小程序,...JavaScript语法解析 首先来看一下什么是抽象语法树。抽象语法树(Abstract Syntax Tree)也称为AST语法树,指的是源代码语法所对应的树状结构。也就是说,对于一种具体编程语言下的源...

  • 【前端源码解析】AST 抽象语法树

    AST 抽象语法树

  • JavaScript中的 抽象语法树 AST

    抽象语法树(Abstract Syntax Tree)也称为AST语法树,指的是源代码语法所对应的树状结构。也就是说,一种编程语言的源代码,通过构建语法树的形式将源代码中的语句映射到树中的每一个节点上。 而在JavaScript中,...

  • 转JavaScript的语法解析与抽象语法树

    JavaScript的语法解析与抽象语法树 Jul 10, 2015 抽象语法树(Abstract Syntax Tree)也称为AST语法树,指的是源代码语法所对应的树状结构。也就是说,对于一种具体编程语言下的源代码,通过构建语法树的形式将源...

  • php ast 抽象语法树,抽象语法树(AST)

    抽象语法树入门到放弃?抽象语法树(Abstract syntax tree AST)在计算机科学中,抽象语法和抽象语法树其实是源代码的抽象语法结构的树状表现形式为什么是抽象的?前端工程化,离不了 AST虽然AST是编译原理中的基础...

  • AST 抽象语法树

    ast抽象语法树是对象,这个对象就是对源代码的描述,通过JS Parser把代码转化成一个抽象的语法树,这个数定义了代码的结构,通过操纵这课树,我们可以精准的定位到声明语句,赋值语句,运算语句等等,实现对代码的...

  • html转换成抽象语法树,了解JavaScript抽象语法树

    本篇文章给大家谈谈JavaScript抽象语法树。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。前言babel是现在几乎每个项目中必备的一个东西,但是其工作原理避不开对js的解析在生成的过程,babel有...

  • java抽象语法树(ast),【你应该了解的】抽象语法树AST

    本文介绍的抽象语法树,就是他们用到的技术,是不是应该了解一下呢?本文没有晦涩难懂的理论,也没有大段大段的代码,完全从零开始,小白阅读也无任何障碍。通过本文的阅读,您将会了解AST的基本原理以及使用方法。...

  • vue源码解析---AST抽象语法树

    在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。我们可以理解为:把 template(模板)解析成一...

  • python 抽象语法树_抽象语法树(Abstract Syntax Tree)

    一般来说,程序中的一段源代码在执行之前...2 解析/语法分析这个过程是将词法单元流(数组)转换成一个由元素逐级嵌套所组成的代表了程序语法结构的树,这个树就叫“抽象语法树”(AST)。全称 Abstract Syntax Tree。...

  • 抽象语法树 -Abstract Syntax Tree

    抽象语法树

  • cst:JavaScript具体语法树

    与AST (抽象语法树)不同, CST包含JavaScript源文件中的所有信息:空格,标点符号,注释。 此信息对于代码样式检查器和其他代码查询非常有用。 当您需要在保留初始文件格式的同时对现有JavaScript文件应用修改的...

  • ibus-table-chinese-erbi-1.4.6-3.el7.x64-86.rpm.tar.gz

    1、文件内容:ibus-table-chinese-erbi-1.4.6-3.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/ibus-table-chinese-erbi-1.4.6-3.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊

  • 基于微信小程序的新乡学院自习室预约系统.zip

    选择Java后台技术和MySQL数据库,在前台界面为提升用户体验,使用Jquery、Ajax、CSS等技术进行布局。 系统包括两类用户:学生、管理员。 学生用户只要实现了前台信息的查看,打开首页,查看网站介绍、自习室信息、在线留言、轮播图信息公告等,通过点击首页的菜单跳转到对应的功能页面菜单,包括网站首页、自习室信息、注册登录、个人中心、后台登录。 学生用户通过账户账号登录,登录后具有所有的操作权限,如果没有登录,不能在线预约。学生用户退出系统将注销个人的登录信息。 管理员通过后台的登录页面,选择管理员权限后进行登录,管理员的权限包括轮播公告管理、老师学生信息管理和信息审核管理,管理员管理后点击退出,注销登录信息。 管理员用户具有在线交流的管理,自习室信息管理、自习室预约管理。 在线交流是对前台用户留言内容进行管理,删除留言信息,查看留言信息。

  • 面向基层就业个性化大学生服务平台(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计

    面向基层就业个性化大学生服务平台(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 【功能需求】 面向基层就业个性化大学生服务平台(源码+数据库+论文+ppt)java开发springboot框架javaweb,可做计算机毕业设计或课程设计 面向基层就业个性化大学生服务平台中的管理员角色主要负责了如下功能操作。 (1)职业分类管理功能需求:对职业进行划分分类管理等。 (2)用户管理功能需求:对用户信息进行维护管理等。 (3)职业信息管理功能需求:对职业信息进行发布等。 (4)问卷信息管理功能需求:可以发布学生的问卷调查操作。 (5)个性化测试管理功能需求:可以发布个性化测试试题。 (6)试题管理功能需求:对测试试题进行增删改查操作。 (7)社区交流管理功能需求:对用户的交流论坛信息进行维护管理。 面向基层就业个性化大学生服务平台中的用户角色主要负责了如下功能操作。 (1)注册登录功能需求:没有账号的用户,可以输入账号,密码,昵称,邮箱等信息进行注册操作,注册后可以输入账号和密码进行登录。 (2)职业信息功能需求:用户可以对职业信息进行查看。 (3)问卷信息功能需求:可以在线进行问卷调查答卷操作。 (4)社区交流功能需求:可以在线进行社区交流。 (5)个性化测试功能需求:可以在线进行个性化测试。 (6)公告资讯功能需求:可以查看浏览系统发布的公告资讯信息。 【环境需要】 1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境:IDEA,Eclipse,Myeclipse都可以。 3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可 4.数据库:MySql 5.7/8.0等版本均可; 【购买须知】 本源码项目经过严格的调试,项目已确保无误,可直接用于课程实训或毕业设计提交。里面都有配套的运行环境软件,讲解视频,部署视频教程,一应俱全,可以自己按照教程导入运行。附有论文参考,使学习者能够快速掌握系统设计和实现的核心技术。

  • 三菱Fx3u程序:自动检测包装机电机控制模板,PLC脉冲与伺服定位,手自动切换功能,三菱Fx3u程序:自动检测包装机电机控制模板-涵盖伺服定位与手自动切换功能,三菱Fx3u程序,自动检测包装机 该

    三菱Fx3u程序:自动检测包装机电机控制模板,PLC脉冲与伺服定位,手自动切换功能,三菱Fx3u程序:自动检测包装机电机控制模板——涵盖伺服定位与手自动切换功能,三菱Fx3u程序,自动检测包装机。 该程序六个电机,plc本体脉冲控制3个轴,3个1pg控制。 程序内包括伺服定位,手自动切,功能快的使用,可作为模板程序,很适合新手。 ,三菱Fx3u程序; 自动检测包装机; 六个电机; PLC脉冲控制; 伺服定位; 手自动切换; 功能快捷键; 模板程序。,三菱Fx3u PLC控制下的自动包装机程序:六电机伺服定位与手自动切换模板程序

  • 基于多尺度集成极限学习机回归 附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

Global site tag (gtag.js) - Google Analytics