关于静态常量的编译

来源:互联网 发布:microservices java 编辑:程序博客网 时间:2024/05/29 09:18
     作者:dlite@163.com

    最近在设计一种语法类似C#的脚本语言,我们称之为N语言,简称nlang。关于编译和初始化静态常量有一些注意事项,记录在本文中。为描述方便,下面将静态常量简称为常量。
     先考虑nlang中支持的几种静态常量定义:
static const floatBASE_FACT= 3.1415927;//1static const floatSCALE_IN_FACT= 2.53 * BASE_FACT;//2static const uint MAX_CONN = getConfigConn();//3static const Bar MY_BAR = {1, "a bar"};//4

    对于表达式1,处理很简单,编译时直接替换为字面常量就可以。
    对于表达式2,似乎可以直接在编译时定值,实际未竟如此。如果语言支持动态连接,假设表达式1位于模块A中,且表达式2位于模块B中。那么表达式1的改变并独立编译模块A后,如果不重新编译模块B,我们无法保证表达式2能正确更新。这种情况,常量表达式的值在链接时才能确定。
     对于表达式3,依赖于运行时配置,显然需要运行时定值。
     表达式4是一个对象常量,为初始化相关RTTI信息,也需要运行时定值。
 
     因此要支持上述功能,我们需要考虑以下问题:
     如何处理依赖于其他非字面常量的常量定义?
     如何处理依赖于函数的常量?
     如何处理对象常量?
     在解决这些问题的同时,还需要保持语言的简洁性,避免规则过于复杂;性能因素也不能忽视。

     下面给出最终采用的处理规则和方法。

     首先,我们规定编译时的可定值变换:
     1)恒同变换;
     2)基本类型操作符(+-*/等)对应的内置函数。[1]
 
     其次,我们规定编译时的可定值性:
     1)基本类型字面常量,可以在编译时直接定值。
     例如:
     static const int A = 100;
     static const string KITTY_NAME = "Tommy";
     2)作用于字面常量的可定值变换,可以在编译时直接定值。
     例如:
     static const int X = 1234 + 5678; //整数加法运算是可定值变换
     3)作用于同一个编译单元中已定值常量的可定值变换,可以在编译时直接定值。
     例如:
     static const int X = 1;
     static const int Y = X + 1; //Y可编译时定值,因为X在同一编译单元中已定值。
 
     然后. 对于简单类型的其他非字面常量,比如依赖于函数的常量。分两种情况处理:
     1)如果所依赖的内容可在编译时定值,则在编译时计算并定值。
     2)如果所依赖的内容不能在编译时定值,则在模块加载时统一定值。[2]
     上述依赖定值需要递归进行,并且在发现循环依赖时,提示编译错误。
 
     最后,对于对象常量,因为需要设置RTTI信息,在模块加载时统一定值。
 
     备注:
     [1] 以后做进一步优化时,可以参考C语言,规定更宽泛一些。例如,某些内置函数也支持可定值变换,例如cos()等,或者通过支持Annotation来通用化。
     [2] 模块加载时定值,发生在动态链接之后,用户初始化模块函数之前。在此处理之前,所有未定值静态量都会被初始化为其缺省值。
0 0