上一章我们已经简单介绍了Solidity语言的基本概念及特点,在了解Solidity的基础知识及用法后,我们可以尝试在Remix、JIDE等编译器上尝试编写一些简单的智能合约,以此来更好地熟悉开发智能合约所需的环境及基础。那么今天,我们将在这里更详细地讲解一些Solidity语言的语法。 首先来讲解一下Solidity语言中的源文件映射。它作为AST输出的一部分,各个编译器会提供AST中节点对应的源代码范围。可用于检测AST静态代码,分析错误,也可用于高亮本地变量以及对应的调试工具。编译器也能生成从字节码到指令源代码之间的范围映射,这在静态分析工具中占据着重要地位,在字节码级别中的分析,可在调试工具中显示对应的代码位置,同时也支持断点操作。 接下来,让我们一起来了解一下属于Solidity语言特有的性质。Solidity有着一些独特的语法,函数类型。在Solidity语言中,函数类型可以作为本地变量,也就是说,在使用var 时,可以给var赋予不同的函数。 contract FunctionSelector {
function select(bool useB, uint x) returns (uint z) {
var f = a;
if (useB) f = b;
return f(x);
}
function a(uint x)** returns **(uint z) {
return x * x;
}
function b(uint x)
returns
(uint z) {
**return **2 * x;
} } 而Solidity语言还有着两个非常有意思的内部机制:清理变量(Cleaning Up Variables)与优化(The Optimizer)。 清理变量(Cleaning Up Variables):在Solidity中,当一个值的占用位数小于32个字节,其中无用的位将会被清除。Solidity编译器可在因无用的数据而产生任何副作用之前就将这些无用的数据清除,例如,在向内存写入一个值之前,不需要的字节位需要先清除掉,因为没有用到的内存位也可能被用于计算哈希值,也可能会作为消息调用作为数据存储。同样,在storage中存储的无用字节位也需处理,否则会带来一些负面影响。 另外,后续操作的不正确也会产生副作用,我们是不会主动的去处理无用字节位的。Solidity编译器会在输入数据加载到栈上后对这些无用字节位进行相应处理。不同的无效值有着不一样的处理规则: 优化(The Optimizer):Solidity的优化基于汇编,也就是说,Solidity可以被其他的编程语言使用。编译器在JUMP和JUMPDEST处拆分基本的指令序列为一个个的基本块。在这些代码块中,所有的指令都将被分析。所有的对栈,内存或存储的操作被记录成由指令及其参数组成的一个个表达式,而这些表达式又会指向另一个表达式。核心目的是找到一些表达式在任何输入的情况下都恒等,然后将它们组合成一个表达式类。优化器首先尝试在一系列已知的表达式中,找出一些全新的表达式。如果找不到,表达式通过一些简单的原则进行简化。流程最后,会有一个表达式处于栈顶,并且有一系列的对内存或存储的修改。这些信息与基本块存在一起以方便地对他们进行连接。此外,关于栈,存储和内存配置的信息会传递到下一个块。如果我们知道所有JUMP和JUMPI指令的目标,我们就可以构建程序的完整的控制流程图。 在最后一步中,每个块中的代码都将重新生成。在某个块结束时,将生成栈上表达式的依赖树,不在依赖树上的操作会被处理。在我们原始代码中想要应用的对内存、存储想要的修改顺序的代码就生成出来了(被丢弃的修改被判定为完全不需要的),最终,生成了所有的需要在栈上存在的值。 这些步骤应用于每个基本的块,如果新生成的代码更小,将会替换现有的代码。如果一个块处于分析期间时在JUMPI处分裂,条件被证实为一个常量,JUMPI将可以基于常量值被替换掉,比如下述代码: var x = 7; data[7] = 9; if (data[x] != x + 2)
return 2; else return 1; 简化的代码可以被编译为:
data[7] = 9; return 1;

Solidity的完整语法,敬请期待后续文章。 部分资料来源: www.tryblockchain.org