- 基本概念
- 基本字:阿拉伯數(shù)字、大小寫拉丁字母蜓竹、其他字符(~箕母、!俱济、%嘶是、&、_姨蝴、-俊啼、+、=左医、{}授帕、[]同木、:、跛十;彤路、<、>芥映、洲尊,、.奈偏、坞嘀?、/惊来、|丽涩、\)、空格符裁蚁、換行符矢渊、制表符等。
- 關鍵字(keyword):提前被定義枉证,并賦予有特殊的含義的單詞
- 保留字: 提前被定義矮男,但還未被賦值(保留字與關鍵字有時等價)
- 標識符(identifier): 由數(shù)字、字母室谚、下劃線組成毡鉴,且不能以數(shù)字開頭,用于給變量舞萄、常量眨补、函數(shù)、語句塊等命名倒脓。
- c語言中標識符包括:關鍵字(如int撑螺、while)、預定義標識符(如printf)和用戶自定義標識符崎弃。
當下的編譯器都做了純文本轉(zhuǎn)AST的事情甘晤。
一款編譯器的編譯流程是很復雜的,但我們只需要關注詞法分析和語法分析饲做,這兩步是從代碼生成AST的關鍵所在线婚。
- 詞法分析器(scanner)
在掃描器的驅(qū)動下,預處理子程序?qū)⒌捷斎刖彌_區(qū)中源代碼的字符處理后由
掃描緩沖區(qū)讀入盆均。掃描器在掃描緩沖區(qū)中識別單詞符號塞弊,然后輸出。
其中預處理子程序的作用是:
現(xiàn)代程序設計語言在最初設計時就遵循了一些規(guī)則:
- 所有基本字都是保留字诀黍,不可再作為標識符
- 基本字作為特殊的標識符處理
- 基本字袋坑、標識符和常數(shù)間若沒有確定的運算符或界符作間隔,必須使用一個空白符作間隔眯勾,一方面避免了超前搜索枣宫、方便編譯程序進行詞法分析,另一方面增加代碼的可讀性
- 詞法分析器設計:
- 確定語言單詞規(guī)范——單詞表
- 有單詞表得到該語言所有字的狀態(tài)轉(zhuǎn)換圖
- 根據(jù)狀態(tài)轉(zhuǎn)換圖實現(xiàn)詞法分析器
詞法分析器會讀取代碼吃环,它會一個一個字母地讀取代碼也颤,所以很形象地稱之為掃描(scanner)。然后把它們按照預定的規(guī)則合并成一個個的標識(tokens)模叙,當它遇到空格歇拆、操作符鞋屈,或者特殊符號的時候范咨,它會認為一個話已經(jīng)完成了。同時厂庇,它會移除空白符渠啊、注釋等。最后权旷,整個代碼將被分割進一個 tokens 列表(或者說一維數(shù)組)
//詞法分析器典型輸入輸出
const a = 5;
// 轉(zhuǎn)換成
[{value: 'const', type: 'keyword'}, {value: 'a', type: 'identifier'}, ...]
- 語法分析器(parser)
語法分析會將詞法分析出來的列表轉(zhuǎn)換成樹形的形式替蛉,同時驗證語法。語法如果有錯的話拄氯,拋出語法錯誤躲查。
[{value: 'const', type: 'keyword'}, {value: 'a', type: 'identifier'}, ...]
// 語法分析后的樹形形式
{
type: "VariableDeclarator", //變量聲明
id: {
type: "Identifier",//標識符
name: "a"
},
...
當生成樹的時候,解析器會刪除一些沒必要的標識 tokens(比如:不完整的括號)译柏,因此 AST 不是 100% 與源碼匹配的镣煮。
- 語法分析相關概念
- 巴克斯范式(EBNF)【巴克斯范式(Backus Form)簡單例子-from知乎】
EBNF元符號 | 含義 |
---|---|
::= | 可解釋為,可推導為 |
| | 或 |
() | 一項鄙麦,一次重復 |
[] | 0次和1次重復 |
{} | 0次或任意多次重復 |
. | 一條生成規(guī)則的結束 |
<> | 非終結符 |
“” | 終結符 |
- 翻譯單元: 什么是翻譯單元?
現(xiàn)在典唇,我們拆解一個簡單的add函數(shù)
function add(a, b) {
return a + b
}
首先,我們拿到的這個語法塊胯府,是一個FunctionDeclaration(函數(shù)定義)對象介衔。
用力拆開,它成了三塊:
- 一個id骂因,就是它的名字炎咖,即add
- 兩個params,就是它的參數(shù),即[a, b]
- 一塊body乘盼,也就是大括號內(nèi)的一堆東西
{
name: 'add'
type: 'identifier'
...
}
params繼續(xù)拆下去急迂,其實是兩個Identifier組成的數(shù)組。之后也沒辦法拆下去了蹦肴。
[
{
name: 'a'
type: 'identifier'
...
},
{
name: 'b'
type: 'identifier'
...
}
]
接下來僚碎,我們繼續(xù)拆開body,我們發(fā)現(xiàn)阴幌,body其實是一個BlockStatement(塊狀域)對象勺阐,用來表示是
打開Blockstatement,里面藏著一個ReturnStatement(Return域)對象矛双,用來表示
繼續(xù)打開ReturnStatement,里面是一個BinaryExpression(二項式)對象渊抽,用來表示
繼續(xù)打開BinaryExpression,它成了三部分议忽,懒闷、、
即
里面裝的栈幸,是Identifier對象
里面裝的愤估,是Identifer對象
就這樣速址,我們把一個簡單的add函數(shù)拆解完畢玩焰,用圖表示就是
酷文章:
- AST抽象語法樹——最基礎的javascript重點知識,99%的人根本不了解
- Python詞法分析器實現(xiàn)
- 在《Python詞法分析器實現(xiàn)》一文中在定義“種別碼”是用到“有窮自動機”理論的使用芍锚,具體可見 :
編譯原理:有窮自動機(DFA與NFA)