形式语义05 Semantics

Formal Semantic

一般分三种

  1. Operational Semantic,操作语义
  2. Denotational Semantic,指称语义
  3. Axiomatic Semantic,公理语义

主要记一下操作语义

Operational Semantic

对命令式语言而言,一个程序的运行状态可以用 状态( imes)当前语句地址 二元组确定,那么就可以用 (left<c,sigma ight>) 描述一个执行状况,表示接下来要执行 (c),目前的状态为 (sigma)

状态一般指的是 ( ext{Value}^ ext{Var}) 的函数,这里规定 ( ext{Var}) 表示变量的集合,( ext{Value}) 表示值(常量)的集合。注意这里的集合内都是符号,与语义无关。例如我们说(23456)是一个值,但它的具体含义是什么在这里并不关心。具体给值的符号赋予含义的操作,一般由另外的函数进行,例如说 ( ext{Meaning}: ext{Value}mapsto mathbb N) 就是一个给所有Integer Tokens赋予具体整数含义的映射

操作语义一般分为大步语义((Downarrow)Big-Step)和小步语义(( ightarrow)Small-Step),分别用于不同目的的研究。一般操作语义要依靠语法结构进行,即它是Syntax Directed的。因此有时候也叫做SOS(Structural Operational Semantics)

通常讲语义会基于一个具体的语言给一些例子,建议直接找PLDI和POPL的形式语义论文看

Evaluation

[frac{left<x,sigma ight> ightarrowleft<{ m{n_1}},sigma' ight>}{left<x+y,sigma ight> ightarrowleft<{ m{n_1}}+y,sigma' ight>} \ \ frac{left<y,sigma' ight> ightarrow left<{ m{n_2}},sigma'' ight>}{left<{ m{n_1}}+y,sigma' ight> ightarrowleft<{ m n_1+n_2},sigma'' ight>} \ \ frac{xin ext{Var}}{left<x,sigma ight> ightarrowleft<sigma(x),sigma ight>} \ \ frac{ ext{Meaning}({ m n_1})+ ext{Meaning}({ m n_2})= ext{Meaning}({ m n_3})}{left<{ m n_1+n_2},sigma ight> ightarrowleft<{ m n_3},sigma ight>} ]

注意这里( ext{Meaning})映射后的加法实际上是正整数的加法,而二元组中的(+)仅作为符号,具体含义由( ext{Meaning})决定

以求值为例,来展示一下小步语义的特点

给出的求值语义有一些比较好的性质:

  1. 可以看到上面给出的求值语义是确定的(Deterministic),这并不是所有语言必备的
  2. 并且我们对代码、状态二元组的推导只能通过每次寻找当前语句的结构中,最左的可推导的句子,这也不是所有语言必备的;

到这里就可以发现一些情况了。所谓的形式语义无非是刻画某些东西性质的一类工具,具体只能作为解决问题的帮手,而本身只起到一种规范的作用,也就是Reference Manual了。并且这种语义是建立在数学符号上的,可以与具体的实现无关(当然也可以有关,但这并不是我们希望的),可以非常容易地进行推理

对于上面给出的例子,可以用写表达式求值辅助:对于给定的表达式二叉树(why 二叉?),我们规定必须先算左子树,再算右子树。如果遇到了变量,就替换为它在环境中的值;如果遇到了常量+常量,就把token转化为整数,计算之后再变回token。

到这里就又可以发现一些事情。操作语义几乎就是在模拟一个具体的算法、一个抽象计算机上编程语言的执行过程、一个解释执行的解释器。反过来,有了操作语义,我们也可以以此指导编译器、解释器的实现,规范具体细节。

这有什么用?用JYY的话说,我们就可以用一个甚至还没有被实现的语言来编写程序、模拟执行,并且预测这些程序的结果、证明它的细节了。这是多酷的一件事情!

While

[frac{[![exp]!]sigma=old{true}}{left<{old{while}};exp;old{do};stmt,sigma ight> ightarrowleft<stmtold;;old{while};exp;old{do};stmt,sigma ight>} \ \ frac{[![exp]!]sigma=old{false}}{left<{old{while}};exp;old{do};stmt,sigma ight> ightarrowleft<old{skip},sigma ight>} \ \ frac{left<stmt_1,sigma ight> ightarrow left<stmt_1',sigma' ight>}{left<stmt_1old;;stmt_2,sigma ight> ightarrowleft<stmt_1'old;;stmt_2,sigma' ight>} \ \ frac{}{left<old{skip;};stmt,sigma ight> ightarrowleft<stmt,sigma ight>} \ \ frac{}{left<old{skip},sigma ight> ightarrowleft<old{skip},sigma ight>} ]

这里主要想讲 ([![exp]!]sigma) 这个符号的用法。这里表示在环境 (sigma) 下,表达式求出的值是什么。其具体含义与操作语义的求值相同,但是注意到操作语义在执行的过程中会丢失表达式的结构信息(我们在一步步化简),因此通常需要把求值和化简分开,这里表现为用单独的函数表示求值操作,以此简化(old{while};ldots;old{do}) 的操作语义规则,否则我们得这么写:

[frac{}{left<{old{while}};exp;old{do};stmt,sigma ight> ightarrowleft<old{if};exp;old{then};(stmtold;;old{while};exp;old{do};stmt);old{else};old{skip},sigma ight>} ]

Evaluation Context

人总喜欢偷懒,观察到上面的操作语义其实在做很重复的事情:

  1. 我们写一堆加法的rules,然后获得了加法操作
  2. 再写一堆乘法的rules
  3. 再写一堆减法的rules
  4. 再写一堆二元运算的rules....

可以发现,既然这些都是二元运算,那么能不能给所有的二元运算定义一次求值顺序(e.g. 最左推导、确定性blabla),然后只需要根据不同情况带入具体算符就可以了?

这就是所谓的Evaluation Context了

仍然以Evaluation为例,可以规定

[{cal E}:=[;]{\,Big |\,}{cal E}+exp{\,Big |\,}{ m n}+{cal E}{\,Big |\,}{cal E}-exp{\,Big |\,}{ m n}-{cal E} ]

这里我们称 (cal E) 为Evaluation Context,对于带入其中的项 (r) 称为Redex

那么我们只需要如下几条rules,就足够表达出带有加减法的表达式求值语法:

[frac{ ext{Meaning}({ m n_1})+ ext{Meaning}({ m n_2})= ext{Meaning}({ m n_3})}{left<{ m n_1+n_2},sigma ight> ightarrowleft<{ m n_3},sigma ight>} \ \ frac{ ext{Meaning}({ m n_1})- ext{Meaning}({ m n_2})= ext{Meaning}({ m n_3})}{left<{ m n_1-n_2},sigma ight> ightarrowleft<{ m n_3},sigma ight>} \ \ frac{left<s,sigma ight> ightarrow left<t,sigma ight>}{left<{cal E}[s],sigma ight> ightarrowleft<{cal E}[t],sigma' ight>} ]

本文来自博客园,作者:jjppp。本博客所有文章除特别声明外,均采用CC BY-SA 4.0 协议

原文地址:https://www.cnblogs.com/jjppp/p/15520746.html