摘要:原文链接何为语法树什么是语法树你是否曾想过,这个世界存在这么多语言的意义。语法树,计算机描述世界真理的树状结构。不同的语言,都会配之不同的语法分析器,而语法分析器是把源代码作为字符串读入解析,并建立语法树的程序。
什么是语法树?原文链接:BlueSun | 何为语法树
你是否曾想过,这个世界存在这么多语言的意义。
假如现在你面前有一个物体,它是一个不规则的圆体,整个身体通红,头部还有一根细长稍微弯曲偏右呈棕色的圆柱体。
在中文我们称之为「苹果」,
在英文我们称之为「Apple」,
在日文中我们称之为「アップル」,
在法语中我们称之为「pomme」,
在德语中我们称之为「Apfel」,
无论用不同的语言,针对这个物体在文字上、发音上都完全不一样,但这个物体确确实实的存在这个时空上,颜色、气味、形状都不曾因为语言而改变过。
无论这个世界存在多少语言,它们所描述的真理都不曾改变过。
或者说,真理就存在那里,可以用不同的语言的不同表达方式描述出来。那么计算机的世界,这么多编程的语言,C、C++、Java、C#、JavaScript、Python、Go、Ruby等等等,它们共同所描述的真理是什么?
我们知道人类语言上,无论什么语种,都会有「主语」「动词」「宾语」「标点符号」来描述一个现实世界所发生的事件。
而在计算机编程语言上,无论什么语种,都会有「类型」「运算符」「流程语句」「函数」「对象」等概念来表达计算机中存在内存中的0和1,以及背后运算与逻辑。
语法树,计算机描述世界真理的树状结构。
不同的语言,都会配之不同的语法分析器,而语法分析器是把源代码作为字符串读入、解析,并建立语法树的程序。语法的设计和语法分析器的实现是决定语言外在表现的重要因素。
什么是语法树?摘自Wiki一段:
一则简单的例子在计算机科学中,抽象语法树(abstract syntax tree 或者缩写为 AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。树上的每个节点都表示源代码中的一种结构。之所以说语法是「抽象」的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
如果我们需要让计算机帮忙算一下 「1加2再乘以3」 的结果,该怎么表达呢?
现在我们大多数的现代编程语言,都是使用「中缀表达式」的方式来编写运算,比如JavaScript:
(1 + 2) * 3
而FORTH语言则使用「后缀表达式」,这基本上与日语中的语序是一致的:
1 2 + 3 *
LISP语言使用的「前缀表达式」:
( * (+ 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 有不少工具可以把代码构造出清晰的语法树,比如 esprima、v8、SpiderMonkey、UglifyJS、AST explorer等。
这里,我使用「esprima」来探讨一下JavaScript运算(1 + 2) * 3的语法树。
javascript code:
(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)
我们可以利用语法树做些什么?看到这里你可能会问,知道语法是又有什么用呢?跟我日常编写代码貌似半毛钱关系都没有。其实语法树还是很有用的,想一下如果想做「语法高亮」、「关键字匹配」、「作用域判断」、以及「代码压缩」等等,都是最好把代码解构成语法树之后再去各种操作,当然仅仅解构还不够,还需要提供各种函数去遍历与修改语法树。
另一方面,去研究、去探讨计算机真实的世界不是一个很精彩很刺激的过程么?
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/78917.html
摘要:在执行上下文栈中,全局执行上下文处于栈底,顶部为当前的执行上下文。可以把所有的程序执行看作一个执行上下文栈,栈的顶部是正在激活的上下文。 前言 本文内容主要涵盖了执行上下文栈、执行上下文、变量对象、函数变量提升等内容。 众所周知,JavaScript是单线程编程语言,同一时间只能做一件事情,程序执行顺序由上而下,程序的执行主要依托JavaScript引擎,JavaScript引...
摘要:但在中会有些不同,包含表单元素的组件将会在中追踪输入的值,并且每次调用回调函数时,如会更新,重新渲染组件。在构造函数中调用的目的是什么在被调用之前,子类是不能使用的,在中,子类必须在中调用。将使用单个事件监听器监听顶层的所有事件。 已经开源 地址:https://github.com/nanhupatar...关注我们团队:showImg(https://segmentfault.co...
摘要:如何为你的项目添加配置如何为你的项目添加配置现在已经是年了,网上许多教程和分享帖都已经过期,照着他们的步骤来会踩一些坑,如已经不再维护,以及之后文件只剩下部分等。如有疑问或授权协商请与我联系。如何为你的 Vue 项目添加配置 Stylelint 现在已经是 9102 年了,网上许多教程和分享帖都已经过期,照着他们的步骤来会踩一些坑,如 stylelint-processor-html 已经不...
阅读 2637·2021-11-23 09:51
阅读 1623·2021-11-22 13:54
阅读 2755·2021-11-18 10:02
阅读 918·2021-08-16 10:57
阅读 3516·2021-08-03 14:03
阅读 1857·2019-08-30 15:54
阅读 3507·2019-08-23 14:39
阅读 570·2019-08-23 14:26