2023年6月29日发(作者:)
AST介绍:解析html⽣成语法树前⾔这个名词⼀直不陌⽣,但是没有细致了解过,结合⾃⼰的项⽬,记录⼀下⾃⼰对AST的理解。1. 什么是AST(抽象语法树)?抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这⾥特指编程语⾔的源代码。2. AST的作⽤?解释器/编译器进⾏语法分析的基础3. AST的使⽤场景?JS:代码压缩、混淆、编译CSS:代码兼容多版本HTML:Vue中Virtual DOM的实现4. 如何获取AST?uglify、acorn、bablyon、esprima、htmlparser2、postcss5. AST标准认识⼀个解析器电脑中,解析器(parser)是指⼀个程序,通常是编译器的部分,接收输⼊的顺序源程序指令、交互式联机命令、标记或者⼀些其它定义的接⼝,将它们打破分成⼏个部分(例如名词(对象),动词(⽅法)和他们的属性或者选项),然后能够被其它的编程控制(如在编译器中的其它组成)。⽬标/* ====
解析器部分 begin ==== */
function parseCode(string) { /** *
这⾥做了⼀些事情讲JS代码转换为语法树 * @string String JS代码 * * return @Ast Object
抽象语法树 * */
do something return Ast}
/* ====
解析器部分 end ==== */
/* ====
使⽤部分 begin ==== */
const CODE_STRING = "var USER = 'Yu Liang';"
const RESULT = parseCode(CODE_STRING)
{ type: 'Program', body: [ { type: 'VariableDeclaration', declarations: [ { type: 'VariableDeclarator', id: { type: 'Identifier', name: 'USER' }, init: { type: 'Literal', value: 'Yu Liang', raw: ''Yu Liang'' } } ], kind: 'var' }], sourceType: 'script'}
/* ====
使⽤部分 end ==== */解析思路1. 词法分析Token KindTokenizeTokens Array⽬标图例:
2. 语法分析Synax Kind(Parse TokenBuild NodeBuild TreeMVP(Minimum Viable Product 最⼩可⾏性产品)MVP产品同学经常⽤到的⼀个名词,其实开发也很需要了解这个概念。/** * Created by yuliang on 2018/3/19 17:18 */
var esprima = require('esprima');var CODE_STRING = "const answer = 'yuliang'";
// (ze(CODE_STRING));
//
定义token
种类//
定义token
种类const TOKEN_KIND = { Keyword: 'Keyword', //关键词 Identifier: 'Identifier', //标识 Punctuator: 'Punctuator', //
符号 String: 'String', //
字符串 WhiteSpace: 'WhiteSpace', //
字符串 EOF: 'EOF' //
结束};//
定义获取token时的statusconst TOKENIZE_STATUS = { keywordStart: 'keywordStart', keywordend: 'keywordend'};
// todo
每⼀种token都会有的固定的属性,使⽤时继承下去,虽然我没做完class _token { constructor(x, y) { = x; = y; }}
function getCodeTokenKindFn(item) { if (['=', ';'].indexOf(item) >= 0) { //
符号 return 'Punctuator'; } else if (item === ' ') { //
空格 return 'WhiteSpace'; } else if (['const'].indexOf(item) >= 0) { //
字符-keyword return 'Keyword'; } else { return 'String'; }}
//
获取代码的token列表function tokenize(code) { let index = 0; //
⽤来记数
现在处理到第⼏个字符了 const length = ; //
代码总字符长度 // ('length', length);
let TOKEN_ARRAY = []; //⽤来存储token的数组 let STATUS = ''; while (index < length) { const ITEM = code[index]; //
应该⽤switch if (getCodeTokenKindFn(ITEM) === TOKEN_ator) { //
处理多个符号连成串的情况
例如:== // if(){} // (code[index], index); TOKEN_({ type: TOKEN_ator, value: ITEM }); index++; } else if (getCodeTokenKindFn(ITEM) === TOKEN_pace) { //
空格情况 // (code[index], index); // TOKEN_({ // type: TOKEN_pace, // value: ITEM // }); index++; index++; } else { // (code[index], index); let _S = ITEM; while ( index + 1 < length && getCodeTokenKindFn(code[index + 1]) !== TOKEN_ator && getCodeTokenKindFn(code[index + 1]) !== TOKEN_pace ) { _S = _S + code[index + 1]; index++; // ('不是空格和符号', _S); } if (getCodeTokenKindFn(_S) === TOKEN_d) { STATUS = TOKENIZE_dend; TOKEN_({ type: TOKEN_d, value: _S }); } else if (STATUS === TOKENIZE_dend) { STATUS = ''; TOKEN_({ type: TOKEN_fier, value: _S }); } else { TOKEN_({ type: TOKEN_, value: _S }); } index++; } } return TOKEN_ARRAY;}
function getSyntaxKindFn(keyword) { return { const: 'VariableDeclaration', var: 'VariableDeclaration' }[keyword];}//
定义获取token时的statusconst ANALYSIS_STATUS = { VariableDeclarationStart: 'VariableDeclarationStart', VariableDeclarationEnd: 'VariableDeclarationEnd', VariableDeclarationStart: ''};//
分析tokens
返回语法树function analysis(tokens) { let index = 0; //
当前处理到token的位置 const length = ; // tokens数组长度 let TREE = { type: 'Program', body: [], sourceType: 'script' }; //语法树 let CURRENT_STATUS = ''; let CURRENT_NODE = {}; while (index < length) { const TOKEN = tokens[index]; // (length, index, TOKEN); CURRENT_STATUS = ''; CURRENT_NODE = {}; debugger; switch (getSyntaxKindFn()) { case 'VariableDeclaration': if (['const'].indexOf() >= 0) { let NODE = { type: 'VariableDeclaration', declarations: [], kind: 'const' kind: 'const' }; let ID = {}; let INIT = {};
if (tokens[index + 1].type === 'Identifier') { ID = { type: 'Identifier', name: tokens[index + 1].value }; index++; }
if (tokens[index + 1].type !== 'Punctuator') { throw new Error('var 语法错误'); return; } else { index++; } if (tokens[index + 1].type === 'String') { INIT = { type: 'Literal', value: tokens[index + 1].value, raw: tokens[index + 1].value }; index++; } else { throw new Error('var 语法错误'); return; } ({ type: 'VariableDeclarator', id: ID, init: INIT }); CURRENT_NODE = NODE; index++; } (CURRENT_NODE); break; default: ('不识别的语法'); index++; break; } } return TREE;}
function parseCode(code) { const TOKEN_ARRAY = tokenize(code); return analysis(TOKEN_ARRAY);}
s = { parseCode, analysis, tokenize };源码解析token类型词法分析状态根据不同的token类型,执⾏不同的解析策略通过全局变量保存当前解析状态通过tagchain构建树结构,闭合树应⽤1. html⽤AST实现了什么?爬⾍:解析hrml页⾯mpvue:将vue模板语法转换为⼩程序的wxml语法2. CSS⽤AST实现了什么?postcss:sass、less语法编译、autoprefixer3. JS⽤AST实现了什么?bable、uglify、browserify、代码分析参考资料AST相关1. javascript编写⼀个简单的编译器2. Browserify运⾏原理分析3. 抽象语法树在 JavaScript 中的应⽤4. 使⽤ Acorn 来解析 JavaScriptPostCSS1. PostCSS GitHub地址2. PostCSS API⽂档3. PostCSS是什么?Html5Parser1. Html5Parser GitHub地址2. Html5Parser 作者详解Esprima1. Esprima GitHub地址2. Esprima 在线demo
发布者:admin,转转请注明出处:http://www.yc00.com/news/1687981447a63383.html
评论列表(0条)