`

CSLight 初探

    博客分类:
  • U3D
 
阅读更多

CSLight 是业内比较厉害的一个人(李剑英)写出来用于对U3D脚本进行热更新的开源项目,从他的一系列博客文章可以看出,他是一个很有想法的人,尤其是在U3D脚本热更新和资源热加载这块有自己的观点。相比ulua我个人还是倾向于CSLight毕竟一个项目里面存在好几种语法规则在维护上是一件很麻烦的事,这两种脚本有人做过测评效率上差不多。

 

1.脚本:

什么是脚本?它的体现形式是一段字符串,然后被一个宿主环境解释执行,例如js在v8里面解释执行,所以js对于v8来说就是脚本。广义上来说,所有的语言都是脚本,而它们的宿主环境就是计算机硬件。无论是解释执行还是编译执行,对于它们的宿主环境来说,都需要做两件事情,解释和执行。解释,就是把一段信息翻译成宿主环境能够认识的东西。

 

2.CSLight:

CSLight就是一个宿主环境,而它的脚本是一个C#规范子集的一段字符串,这个子集的范围在作者博客有介绍:http://www.cnblogs.com/crazylights/p/3888932.html。脚本在解释之后,会把信息以一种宿主环境可以直接调用的形式存储,而CSLight会把这些信息存储在CLS_Environment里面。

 

3.CLS_Environment:

(1)构造:

        Dictionary<CLType, ICLS_Type> types = new Dictionary<CLType, ICLS_Type>();
        Dictionary<string, ICLS_Type> typess = new Dictionary<string, ICLS_Type>();
        Dictionary<string, ICLS_Function> calls = new Dictionary<string, ICLS_Function>();

        public CLS_Environment(ICLS_Logger logger)
        {
            //if(useNamespace==true)
            //{
            //    throw new Exception("使用命名空间还不能完全兼容,建议关闭");
            //}
            this.logger = logger;
            //this.useNamespace = useNamespace;
            tokenParser = new CLS_TokenParser();
            compiler = new CLS_Expression_Compiler(logger);
            RegType(new CLS_Type_Int());
            RegType(new CLS_Type_UInt());
            RegType(new CLS_Type_Float());
            RegType(new CLS_Type_Double());
            RegType(new CLS_Type_String());
            RegType(new CLS_Type_Var());
            RegType(new CLS_Type_Bool());
            RegType(new CLS_Type_Lambda());
            RegType(new CLS_Type_Delegate());
            RegType(new CLS_Type_Byte());
            RegType(new CLS_Type_Char());
            RegType(new CLS_Type_UShort());
            RegType(new CLS_Type_Sbyte());
            RegType(new CLS_Type_Short());
            RegType(new CLS_Type_Long());

            typess["null"] = new CLS_Type_NULL();
            //contentGloabl = CreateContent();
            //if (!useNamespace)//命名空间模式不能直接用函数
            {
                RegFunction(new FunctionTrace());
            }
        }

从构造上来看,这里主要是注册类型和方法信息,而这些类型和方法都是会被脚本用到的,也就是说如果types内容为null脚本写的再漂亮CSLight也是不认识的。

其次需要主要的是构造必须传入一个ICLS_Logger 对象用来输出日志,在运行时输出错误日志是必须的,所以这里是强制要求有一个log对象。而这种方式也很有效的避免了与U3D的依赖。

CLS_TokenParser和CLS_Expression_Compiler应该就是用来执行脚本的。

(2)相对重要的方法:

        public void RegType(ICLS_Type type)
        public void RegFunction(ICLS_Function func)
        public CLS_Content CreateContent()
        public void Project_Compiler(Dictionary<string, IList<Token>> project, bool embDebugToken)
        public CLS_Content.Value Expr_Execute(ICLS_Expression expr, CLS_Content content = null)
        {
            if (content == null) content = CreateContent();
            return expr.ComputeValue(content);
        }
        public IList<Token> ParserToken(string code)
        {
            return tokenParser.Parse(code);
        }
        public ICLS_Expression Expr_CompilerToken(IList<Token> listToken, bool SimpleExpression = false)
        {
            return SimpleExpression ? compiler.Compiler_NoBlock(listToken, this) : compiler.Compiler(listToken, this);
        }

Project_Compiler:这里的工程可以理解为文件夹,它的功能是把一个文件夹下面所有cs文件进行解释,然后把里面的类方法注册到CLS_Environment对象里面。

CLS_Content:可以把它理解为一个容器,存储结果或者参数。

 

3.常用接口:

(1)CLS_Content:

        public class Value
        {
            public CLType type;
            public object value;
            public int breakBlock = 0;//是否是块结束
            public static Value FromICLS_Value(ICLS_Value value)
            {
                Value v = new Value();
                v.type = value.type;
                v.value = value.value;
                return v;
            }
        }

        public Dictionary<string, Value> values = new Dictionary<string, Value>();
        public void Define(string name,CLType type) 
        public void Set(string name,object value)
        public void DefineAndSet(string name,CLType type,object value)
        public Value Get(string name)

 在CLS_Content的内部定义了一个Value类型作为它的值的类型。这里需要注意的是CLS_Content需要先知道object的CLType,然后才能存储它的值。

(2)ICLS_Expression:表达式,一个复杂的表达式由多个简单的组成,这个接口计算表达式的结果。

ICLS_Value:继承ICLS_Expression接口,在其基础上增加了CLType类型信息。

ICLS_Environment_Compiler:编译整个环境

ICLS_Expression_Compiler:编译表达式

这里的编译我个人的理解就是把解析好的指令执行一遍,但是好像又不对,应该是属于解析的第二个过程,第一个过程是分析字符串,把字符串分析成一段段的表达式。这个过程是把表达式换成CSLight可识别的形式。

(3)ICLS_Function和ICLS_Function_Member:接口很简单只有一个Call方法

        CLS_Content.Value Call(CLS_Content content, IList<CLS_Content.Value> param);

        CLS_Content.Value Call(CLS_Content content, object objthis, IList<CLS_Content.Value> param);

 上面的是全局方法,下面的是成员函数,多了一个this指针。

(4)ICLS_Logger:打印日志

 

总结:大致看了一下源代码,多是一些解释执行的东西,大致有点了解就行了,毕竟用好才是最重要的。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics