编程语言的语法和语义
http://blog.csdn.net/gengzhikui1992/article/details/50762309
为了完整地定义编程语言,我们需要:
语法,描述程序看起来是什么样的;
语义,描述程序的含义。
语法
语法的定义
每一种编程语言都有一系列规则,描述在那种语言中什么样的字符串被认为是有效程序。这些规则定义了这种语言的语法。通过语言的语法规则,我们能把像 y = x + 1 这样可能有效的程序与像 >/;x:1@4 这样毫无意义的字符串区分开。
抽象语法树
当然,计算机程序的预期用途是被计算机读取,而要读程序就需要语法解析器:这个分析器程序能够读取代表程序的字符串,根据语法规则检查它是否有效,然后把它转换成一个适合被进一步处理的结构化表示。
有各种各样的工具能把一种语言的语法规则自动转换成一个语法解析器。
总体来讲一个语法解析器应该读入像 y = x + 1 这样的字符串,然后把它转换成抽象语法树( AST)。抽象语法树是源代码的一种表示,去掉了空格之类的无关细节,而只关注程序的分层结构。
语法总结
语法关心的只是程序的表面是什么样的,而不是它的含义。程序有可能语法正确但没有任何实际意义。例如,程序 y = x + 1 本身可能没有任何意义,因为并没有事先说明 x 是什么,而程序 z = true + 1 可能会在运行时候报错,因为它试图在一个布尔型值上加数字。
操作语义
操作语义定义
考虑程序含义的最实际方法是思考它做了些什么:在运行程序的时候,我们期望发生什么呢?在运行时编程语言中不同的结构都是如何表现的?把它们放到一起组成更大的程序时会是什么效果?
这是操作语义学( operational semantic)的基础,这种方法为程序在某种机器上的执行定义一些规则,以此来捕捉编程语言的含义。这个机器常常是一种抽象的机器:
小步规约
那么,我们如何设计一台抽象机器,并使用它定义一种编程语言的操作语义呢?一种方法就是假想一台机器,用这台机器直接按照这种语言的语法进行操作一小步一小步地对其进行反复规约,从而对一个程序求值。不管最后得到的结果含义是什么,我们每一步都能让程序更接近最终结果。
这种小步规约类似于对代数式求值的方式。例如, 为了对 (1×2) + (3×4) 求值,我们知道应该:
- 执行左侧的乘法( 1×2 变成了 2),这样表达式就规约成了 2 + (3×4);
- 执行右侧的乘法( 3×4 变成了 12),这样表达式规约成了 2 + 12
- 执行加法( 2 + 12 变成了 14),最终得到 14。
我们可以认为 14 就是结果, 因为通过上面步骤已经不能再进一步规约了;我们认为 14 是一个特殊代数表达式,它是一个值,有自己的含义,不需要进一步的努力了。
小步规约的形式化规则
把如何进行每一小步的规约写成形式化规则,这个非形式化的过程就可以转换成一个操作语义。
这些规则本身需要用某种语言( 元语言)写下来,而这种语言通常是数学符号。
参考:《计算的本质:深入剖析程序和计算机》