使用acorn对JavaScript代码进行解析。
2017-04-15 16:08
561 查看
使用acorn对JavaScript代码进行解析。
Acorn简介
Acorn是一个小小的快速JavaScript解析器,完全用JavaScript编写并且性能和效率比Esprima更胜一筹。解析思路是把代码解析成语法树的形式。如下代码是一个简单的例子。
c = 1 + 1;
通过Acorn解析结果如下:
AST树简介
在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax
tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。比如,嵌套括号被隐含在树的结构中,并没有以节点的形式呈现;而类似于if-condition-then这样的条件跳转语句,可以使用带有两个分支的节点来表示。
AST树作为程序的一种中间表示形式,在程序分析等诸多领域有广泛的应用.利用抽象语法树可以方便地实现多种源程序处理工具,比如源程序浏览器、智能编辑器、语言翻译器等.
var AST = "is Tree";
这里的解析结果和Acorn的解析结果看起来很像,他们在形式上是相同的区别只是在于对不同信息的保存上或多或少,比如下代码
int a = 1;//给a赋值 int b = 2;
Acorn的处理逻辑会把注释和第二句代码链接起来,而Esprima则是会注释的信息分别和两句话都链接起来。那么这也就在处理代码和注释的对应上有一点误差(后面会讲到)。
解析过程和核心代码介绍
要使用Acorn进行解析那么第一步就是安装Acorn,通过
npm install acorn即可安装。
我们的目的是提取JavaScript代码中的注释和对应的代码,所以对应的操作就是
1. 如何解析出AST树。
2. 如何遍历AST树拿出其中的注释和找到注释对应的代码。
3. 如何把注释和注释对应的代码存成对应的格式。
Acorn对代码的解析很简单
var ast = acorn.parse(source, { sourceType: "script", locations: true, onComment: comments, onToken: tokens, });
官方给出这样的解释“*parse(input, options) is used to parse a JavaScript
program. The input parameter is a string, options can be undefined or
an object setting some of the options listed below. The return value
will be an abstract syntax tree object as specified by the ESTree
spec.*”通过以上操作我们便可以得到解析完成AST,第一个参数是String类型的文本,第二个参数是一个对象,是对AST树的一些设置。下边对上面用到的参数做一个收集
locations :When true, each node has a loc object attached with start and end subobjects, each of which contains the one-based line and zero-based column numbers in {line, column} form. Default is false.
onComment: If a function is passed for this option, whenever a comment is encountered the function will be called with the following parameters:
block: true if the comment is a block comment, false if it is a line comment. text: The content of the comment. start: Character offset of the start of the comment. end: Character offset of the end of the comment.
每个注释都会被按照下面的形式存储起来
当我们通过Acorn拿到了带有完整注释信息的AST树那么就有对树进行一个遍历,取出对注释和注释对应的代码进行存储。
//注释说明1 int a = 2; //注释说明2 int b = 3; //注释说明3
经过对于AST树中的节点来说 注释一是代码一的leadingComments,注释而是代码一的trailingComments,同样代码二也有对应的leadingComments和trailingComments分别是注释二和注释三。但是也有一种特殊的情况如下
int a = 2; //注释说明1 int b = 3; //注释说明2
注释一和注释二会被认为是代码二的leadingComments和trailingComments,而代码一没有trailingComments。这样的话就和我们的处理逻辑是不一样的,我们需要然后上面例子中注释一是代码一的trailingComments。所以就需要对整个树进行一个遍历,对节点信息记性一个设置。
遍历会用到
estraverse这个库。处理逻辑如下代码所示
estraverse.traverse(ast, { leave: function (node, parent) { if (!node.hasOwnProperty('trailingComments')) { var old_node = node; var old_line = node.loc.end.line; var old_column = node.loc.end.column; estraverse.traverse(parent, { leave: function (node, parent) { if (node !== old_node && node.hasOwnProperty('leadingComments') && node.leadingComments[0].loc.start.line === old_line && node.leadingComments[0].loc.start.column >= old_column) { old_node.trailingComments = []; old_node.trailingComments[0] = node.leadingComments.shift(); if (node.leadingComments.length === 0) { delete node.leadingComments; } estraverse.VisitorOption.Break; } } }); node = old_node; }
通过如上操作便可对上文提到的特殊情况进行更正。
现在最后一个问题就是如何把得到的注释和代码对应起来,对AST树来说这里操作就很简单了,我们需要对AST在遍历时候对每个节点的状态进行判别。
var t = node.hasOwnProperty('trailingComments'); var l = node.hasOwnProperty('leadingComments'); if (t && l) { comment_code.comment = node.leadingComments.concat(node.trailingComments); comment_code.code.push(escodegen.generate(node));//将注释和代码对应起来 extract.push(comment_code); } else if (l) { comment_code.comment = node.leadingComments; comment_code.code.push(escodegen.generate(node)); extract.push(comment_code); } else if (t) { comment_code.comment = node.trailingComments; comment_code.code.push(escodegen.generate(node)); extract.push(comment_code); } comment_code = {comment: [], code: []};
把代码和注释都存在数组中之后,通过
var fs = require("fs"); fs.writeFileSync(filepaht, filecontent);
进行存储。到此处理完毕。
相关文章推荐
- JavaScript使用json2.js对json数据进行解析
- JavaScript 使用正则表达式进行表单验证的示例代码
- 使用JetBrains WebStorm 让 jquery 等javascript技术进行代码提示
- 使用C#解析并运行JavaScript代码
- mybatis使用xml进行增删改查代码解析
- php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
- 使用JSP代码和使用JavaScript代码进行表单数据验证有什么不同?
- 说说如何使用 JavaScript 进行代码调试
- 使用Apache commons-cli包进行命令行参数解析的示例代码
- JavaScript 使用反斜杠对代码行进行折行
- php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
- php中使用parse_url()对网址进行解析的实现代码(parse_url详解)
- JavaScript 使用正则表达式进行表单验证的示例代码
- 后台代码中使用Post 进行跳转
- 如何使用后台代码在head标记中动态生成javascript?
- 使用 PHP 解析 javascript escape() 编码过的字串
- 使用vbscript脚本在表单中进行选择的代码
- 如何使用JavaScript和正则表达式进行数据验证
- 使用PowerDesigner进行代码生成