抽象語法樹(AST)
正如前面提到的,解析器會建立一個結構來表示程式的語義。AST節點是一個普通的JavaScript物件,它有一個型別屬性,指定它是什麼型別的節點,以及根據特定型別指定的附加資訊。
總覽:
num
{ type: "num", value: NUMBER }
str
{ type: "str", value: STRING }
bool
{ type: "bool", value: true or false }
var
{ type: "var", value: NAME }
lambda
{ type: "lambda", vars: [ NAME... ], body: AST }
call
{ type: "call", func: AST, args: [ AST... ] }
if
{ type: "if", cond: AST, then: AST, else: AST }
assign
{ type: "assign", operator: "=", left: AST, right: AST }
binary
{ type: "binary", operator: OPERATOR, left: AST, right: AST }
prog
{ type: "prog", prog: [ AST... ] }
- let
{ type: "let", vars: [ VARS... ], body: AST }
例子:
Numbers ("num"
)
123.5複製程式碼
→
{ type: "num", value: 123.5 }複製程式碼
Strings ("str"
)
"Hello World!"複製程式碼
→
{ type: "str", value: "Hello World!" }複製程式碼
Booleans ("bool"
)
true
false複製程式碼
→
{ type: "bool", value: true }
{ type: "bool", value: false }複製程式碼
識別符號 ("var"
)
foo複製程式碼
→
{ type: "var", value: "foo" }複製程式碼
函式 ("lambda"
)
lambda (x) 10 # or
λ (x) 10複製程式碼
Later we will add an optional "name"
property, to support named
functions, but the first version of our parser won't have it.
→
{
type: "lambda",
vars: [ "x" ],
body: { type: "num", value: 10 }
}複製程式碼
函式呼叫 ("call"
)
foo(a, 1)複製程式碼
→
{
"type": "call",
"func": { "type": "var", "value": "foo" },
"args": [
{ "type": "var", "value": "a" },
{ "type": "num", "value": 1 }
]
}複製程式碼
條件語句 ("if"
)
if foo then bar else baz複製程式碼
→
{
"type": "if",
"cond": { "type": "var", "value": "foo" },
"then": { "type": "var", "value": "bar" },
"else": { "type": "var", "value": "baz" }
}複製程式碼
else
分支是可選的:
if foo then bar複製程式碼
→
{
"type": "if",
"cond": { "type": "var", "value": "foo" },
"then": { "type": "var", "value": "bar" }
}複製程式碼
賦值 ("assign"
)
a = 10複製程式碼
→
{
"type": "assign",
"operator": "=",
"left": { "type": "var", "value": "a" },
"right": { "type": "num", "value": 10 }
}複製程式碼
二進位制表示式 ("binary"
)
x + y * z複製程式碼
→
{
"type": "binary",
"operator": "+",
"left": { "type": "var", "value": "x" },
"right": {
"type": "binary",
"operator": "*",
"left": { "type": "var", "value": "y" },
"right": { "type": "var", "value": "z" }
}
}複製程式碼
序列 ("prog"
)
{
a = 5;
b = a * 2;
a + b;
}複製程式碼
→
{
"type": "prog",
"prog": [
{
"type": "assign",
"operator": "=",
"left": { "type": "var", "value": "a" },
"right": { "type": "num", "value": 5 }
},
{
"type": "assign",
"operator": "=",
"left": { "type": "var", "value": "b" },
"right": {
"type": "binary",
"operator": "*",
"left": { "type": "var", "value": "a" },
"right": { "type": "num", "value": 2 }
}
},
{
"type": "binary",
"operator": "+",
"left": { "type": "var", "value": "a" },
"right": { "type": "var", "value": "b" }
}
]
}複製程式碼
擁有塊作用域的變數 ("let"
)
let (a = 10, b = a * 10) {
a + b;
}複製程式碼
在我們第一版的編譯器將不會有這個節點型別,我們會在之後加入這一特性。
→
{
"type": "let",
"vars": [
{
"name": "a",
"def": { "type": "num", "value": 10 }
},
{
"name": "b",
"def": {
"type": "binary",
"operator": "*",
"left": { "type": "var", "value": "a" },
"right": { "type": "num", "value": 10 }
}
}
],
"body": {
"type": "binary",
"operator": "+",
"left": { "type": "var", "value": "a" },
"right": { "type": "var", "value": "b" }
}
}複製程式碼