Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。
https://muyiy.cn/question/
27.41k stars 3.29k forks source link

第 149 题:babel 怎么把字符串解析成 AST,是怎么进行词法/语法分析的? #315

Open yygmind opened 4 years ago

caiyongmin commented 4 years ago

大致分为下面四步:

具体见下方链接文件的代码:

GeekQiaQia commented 4 years ago

Babel

定义

Babel概述

Babel 中重要的对象Vistor

babel 在处理一个节点时,是以访问者的形式获取节点的信息,并进行相关的操作,这种操作是通过visitor对象实现的。

在 visitor 中定义了处理不同节点的函数。

visitor: {
  Program: {
    enter(path, state) {
      console.log('start processing this module...');
    },
      exit(path, state) {
        console.log('end processing this module!');
      }
  },
    ImportDeclaration:{
      enter(path, state) {
        console.log('start processing ImportDeclaration...');
        // do something
      },
        exit(path, state) {
          console.log('end processing ImportDeclaration!');
          // do something
        }
    }
}

AST

定义

Javascript 语法的AST(抽象语法树)

转换的抽象语法树:var answer= 6 * 7

每一个含有type属性的对象,我们称之为节点,修改是指获取对应的类型并修改改节点的属性即可;

 {
"type": "Program",
"body": [
    {
        "type": "VariableDeclaration",
        "declarations": [
            {
                "type": "VariableDeclarator",
                "id": {
                    "type": "Identifier",
                    "name": "answer"
                },
                "init": {
                    "type": "BinaryExpression",
                    "operator": "*",
                    "left": {
                        "type": "Literal",
                        "value": 6,
                        "raw": "6"
                    },
                    "right": {
                        "type": "Literal",
                        "value": 7,
                        "raw": "7"
                    }
                }
            }
        ],
        "kind": "var"
    }
  ],
  "sourceType": "script" 
}

estraverse 遍历和修改AST

查看遍历过程:

const esprima = require("esprima");
const estraverse = require("estraverse");

let code = "var answer=6 * 7";

// 遍历语法树
estraverse.traverse(esprima.parseScript(code), {
  enter(node) {
    console.log("enter", node.type);
  },
  leave(node) {
    console.log("leave", node.type);
  }
});

escodegen 将 AST 转换成 JS

const esprima = require("esprima");
const estraverse = require("estraverse");
const escodegen= require("escodegen");

let code = "var answer=6 * 7";

let tree=esprima.parseScript(code); // 生成语法树
// 遍历语法树
estraverse.traverse(tree, {
    enter(node) {
        console.log("enter", node.type);
        // 修改变量名
        if(node.type==='VariableDeclarator'){
                node.id.name='result';
        }
    },
    leave(node) {
        console.log("leave", node.type);
    }
});

// 编译修改后的语法树;
let compileTreeJS=escodegen.generate(tree);
console.log(compileTreeJS);

通过工具了解抽象语法树在 JavaScript 中的体现以及在 NodeJS 中用于生成、遍历和修改 AST 抽象语法树的核心依赖;让我们有了更加深刻地认识;

参考整合:https://juejin.im/post/5dca1eb86fb9a04a76025292

pagemarks commented 4 years ago

编译原理(第2版) 值得一读 image

front-end-yu commented 4 years ago

参考:https://mp.weixin.qq.com/s/fH2xYo_Bad0mgvo0OdYRZQ

shinelp100 commented 4 years ago

参考这个:https://the-super-tiny-compiler.glitch.me/intro