AST抽象語法樹


1.概念html

抽象語法樹(abstract syntax code,AST)是源代碼的抽象語法結構的樹狀表示。這裏特指編程語言的源代碼。前端

樹上的每一個節點都表示源代碼中的一種結構,之因此說是抽象的,是由於抽象語法樹並不會表示出真實語法出現的每個細節,好比說,嵌套括號被隱含在樹的結構中,並無以節點的形式呈現。node

抽象語法樹並不依賴於源語言的語法,也就是說語法分析階段所採用的上下文無關文法,由於在寫文法時,常常會對文法進行等價的轉換(消除左遞歸,回溯,二義性等),這樣會給文法分析引入一些多餘的成分,對後續階段形成不利影響,甚至會使各個階段變得混亂。所以,不少編譯器常常要獨立地構造語法分析樹,爲前端,後端創建一個清晰的接口。git

抽象語法樹在不少領域有普遍的應用,好比瀏覽器,智能編輯器,編譯器等。github


2.爲什麼須要抽象語法樹(抽象語法樹做用)typescript

編程語言太多,須要一個統一的結構讓計算機識別。npm

做用:好比typescript的類型檢查,IDE的語法高亮,代碼檢查,轉譯等等,都是須要先將代碼轉化成AST在進行後續的操做。編程


3.抽象語法樹的生成過程(編譯)segmentfault

js爲例:後端

詞法分析(lexical analysis):進行詞法分析的程序或者函數叫做詞法分析器(Lexical analyzer,簡稱Lexer),也叫掃描器(Scanner,例如typescript源碼中的scanner.ts),字符流轉換成對應的Token流

tokenize:tokenize就是按照必定的規則,例如token令牌(一般表明關鍵字,變量名,語法符號等),將代碼分割爲一個個的「串」,也就是語法單元)。涉及到詞法解析的時候,常會用到tokennize。

語法分析(parse analysis)是編譯過程的一個邏輯階段。語法分析的任務是在詞法分析的基礎上將單詞序列組合成語法樹,如「程序」,「語句」,「表達式」等等.語法分析程序判斷源程序在結構上是否正確。源程序的結構由上下文無關文法描述。

例如:對

const a = 1;
const b = a + 1;
複製代碼

的編譯過程。


圖片地址:www.processon.com/view/link/5…

詞法解析過程:一邊掃描源代碼一邊進行分類,例如掃描到第一行const a = 1,首先掃描到const,會生成一個語法單元說這是關鍵字const,接着掃描到a,這是變量名a,接着操做符=,接着常量1,等等,構成一個個token流。

語法分析過程:將token流轉化爲一個有元素層級嵌套所組成的表明程序語法結構的樹,這個樹被叫作抽象語法樹AST。

4.擴展測試:如何將const a = 1轉化成var a = 1

   1. 新建一個testAst的工程

mkdir testAst複製代碼

     testAst下新建test.js文件

touch test.js複製代碼

  • testAst下安裝esprima的npm模塊,獲得AST

npm i  esprima --save複製代碼


   test.js寫入代碼

const esprima = require('esprima');

let code = 'const a = 1';
const ast = esprima.parseScript(code);

console.log(ast);
複製代碼

  2.運行test.js

node test.js複製代碼

  3.獲得生成的AST


也可經過esprima.org/demo/parse.…,輸入代碼,在線查看AST

  • testAst下安裝estraverse的npm模塊,遍歷更新AST

npm i estraverse  --save
複製代碼

  

 4.修改代碼以下:

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

let code = 'const a = 1';
const ast = esprima.parseScript(code);
estraverse.traverse(ast, {
    enter: function (node) {
        node.kind = "var";
    }
});

console.log(ast);複製代碼

 5.運行test.js,獲得更新事後的AST


  • testAst下安裝escodegen的npm模塊,獲得轉譯後的代碼
npm i escodegen  --save複製代碼

6.修改代碼以下:

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

let code = 'const a = 1';
const ast = esprima.parseScript(code);
estraverse.traverse(ast, {
    enter: function (node) {
        node.kind = "var";
    }
});
const transformCode = escodegen.generate(ast);

console.log(transformCode);
複製代碼

7.運行test.js,獲得轉譯後的代碼



參考文檔:

  1. https://segmentfault.com/a/1190000012943992

  2. https://baike.baidu.com/item/語法分析/8853407?fr=aladdin
  3. baike.baidu.com/item/詞法分析
  4. blog.csdn.net/feng98ren/a…
  5. https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-asts
相關文章
相關標籤/搜索