什么是语法树?
我们知道人类语言上,无论什么语种,都会有「主语」「动词」「宾语」「标点符号」来描述一个现实世界所发生的事件。
而在计算机编程语言上,无论什么语种,都会有「类型」「运算符」「流程语句」「函数」「对象」等概念来表达计算机中存在内存中的0和1,以及背后运算与逻辑。
语法树,计算机描述世界真理的树状结构。
不同的语言,都会配之不同的语法分析器,而语法分析器是把源代码作为字符串读入、解析,并建立语法树的程序。语法的设计和语法分析器的实现是决定语言外在表现的重要因素。
什么是语法树?摘自Wiki一段:
在计算机科学中,抽象语法树(abstract syntax tree 或者缩写为 AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。之所以说语法是「抽象」的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
一则简单的例子
如果我们需要让计算机帮忙算一下 「1加2再乘以3」的结果,该怎么表达呢?
现在我们大多数的现代编程语言,都是使用「中缀表达式」的方式来编写运算,比如JavaScript:
1 | (1 + 2) * 3 |
而FORTH语言则使用「后缀表达式」,这基本上与日语中的语序是一致的:
1 | 1 2 + 3 * |
LISP语言使用的「前缀表达式」:
1 | ( * (+ 1 2) 3) |
我们再看一下这三种表达式的语法树:
可以看出,对于这三种简单的语言,它们只是在这个语法树上按不同的规则遍历而已。三者的代码看起来差别很大,但实际上所用的树结构是相同的。
先来看看Python的语法树
通过Python语言自带的库文件ast,我们可以查看特定的代码被转换成怎样的语法树。
>>> import ast
>>> ast.dump(ast.parse("(1 + 2) * 3"))
'Module(
body=[
Expr(
value=BinOp(
left=BinOp(
left=Num(n=1),
op=Add(),
right=Num(n=2)
),
op=Mult(),
right=Num(n=3)
)
)
]
)'
BinOp op = Mult()
表示乘法运算,与*
相对应; BinOp op = Add()
表示加法运算,与+
相对应; Num n = 1
既为数值1。
再窥视一下JavaScript的语法树
在语法复杂的语言中,语法树是包含很多细节的语法结果表达式,我们需要靠语法树把这种形式以更简洁的形式表达出来。
Javascript 有不少工具可以把代码构造出清晰的语法树,比如 esprima、v8、SpiderMonkey、UglifyJS、AST explorer等。
这里,我使用「esprima」来探讨一下JavaScript运算(1 + 2) * 3
的语法树。
javascript code:
1 | (1 + 2)* 3; |
ast for json:
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "Literal",
"value": 1,
"raw": "1"
},
"right": {
"type": "Literal",
"value": 2,
"raw": "2"
}
},
"right": {
"type": "Literal",
"value": 3,
"raw": "3"
}
}
}
],
"sourceType": "script"
}
body
表示程序体,而程序体中包含了一则表达式ExpressionStatement
, 表达式体里包含了操作符 *
,以及左右两边表达式,其中右边是数字3
,而左边表达式还包含一层表达式,里面是一个+
操作符,以及左右两边分别为1
和2
的数字。
如果还没有看懂,你可以到这里看一下这段代码所生成的语法树:AST for (1 + 2)* 3;*%203%0A)
我们可以利用语法树做些什么?
看到这里你可能会问,知道语法是又有什么用呢?跟我日常编写代码貌似半毛钱关系都没有。其实语法树还是很有用的,想一下如果想做「语法高亮」、「关键字匹配」、「作用域判断」、以及「代码压缩」等等,都是最好把代码解构成语法树之后再去各种操作,当然仅仅解构还不够,还需要提供各种函数去遍历与修改语法树。
AST通常经过词法、语法分析之后产生,关于这方面的可以参考另一篇文章:Lex和YACC学习笔记。
参考
http://huang-jerryc.com/2016/03/15/%E4%BD%95%E4%B8%BA%E8%AF%AD%E6%B3%95%E6%A0%9