初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
专题:一个自制代码生成器(嵌入式脚本语言)之总述-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之对象模型-CSDN博客 (本篇)
专题:一个自制代码生成器(嵌入式脚本语言)之堆栈结构和总入口-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之核心逻辑-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之辅助逻辑-CSDN博客
专题:一个自制代码生成器(嵌入式脚本语言)之应用实例-CSDN博客
目录
一、对象模型概述
二、主要代码
2.1 成员变量定义
2.2 读取和设置
2.3 查找对象
2.4 显示对象
三、堆栈结构和总入口
一、对象模型概述
表达对象的东西其实都差不多,只是因为都要在里面加自己的特殊东西,所以没有标准。
所有对象模型都是“节点-节点类型-根据类型不同使用不同的属性和方法-包含的子节点”这么几个要素,这里的对象模型的节点有四种类型:
- 对象 包含一组通过名称区分的子对象(有点怪吗?可是已经是这样了啊)
- 指针 指向一个对象
- 属性 一个值
- 数组 一个对象数组
由于设计原因,一个对象的属性通过子对象来实现,直觉上比把属性直接实现为map<属性名,属性值>要复杂些,不过因为程序里面其实都是通过方法来使用的,内部复杂性并没有很大影响。
二、主要代码
2.1 成员变量定义
struct CCTObject
{enum TYPE { OBJECT, POINTER, PROPERTY, ARRAY };TYPE m_type;//根据type决定哪个成员有效CCTObject* m_Pointer;//指针string m_Property;//属性(值)map<string, CCTObject > m_Object;//对象vector<CCTObject > m_Array;//数组CCTObject() :m_type(OBJECT), m_Pointer(NULL) {}......
}
通过m_type使用另外四个成员之一。如果要省内存可以用union。
使用时使用各种专门的读取和设置方法,这些成员原则上是不对外的,其实可以设置成private。
2.2 读取和设置
string GetDefaultValue(){if (PROPERTY == m_type){return m_Property;}else if (OBJECT == m_type){return m_Object["name"].GetDefaultValue();}else if (POINTER == m_type){return m_Pointer->GetDefaultValue();}else if (ARRAY == m_type){return "ARRAY";}else{return "unknown type";}}string SetDefaultValue(char const* value){if (PROPERTY == m_type){return m_Property = value;}else if (OBJECT == m_type){SetObjectAddProperty("name", value);return value;}else if (POINTER == m_type){return m_Pointer->SetDefaultValue(value);}else if (ARRAY == m_type){return "ARRAY";}else{return "unknown type";}}void SetObjectAddProperty(string name, long value){char buf[64];sprintf(buf, "%ld", value);SetObjectAddProperty(name, buf);}void SetObjectAddProperty(string name, string value){CCTObject p;p.m_type = PROPERTY;p.m_Property = value;m_Object[name] = p;}void SetProperty(string value){m_type = PROPERTY;m_Property = value;}void SetProperty(int value){m_type = PROPERTY;char buf[256];sprintf(buf, "%d", value);m_Property = buf;}void SetPointer(CCTObject* value){m_type = POINTER;m_Pointer = value;}void SetArrayPushBack(CCTObject value){m_type = ARRAY;m_Array.push_back(value);}//给对象初始化一个拥有的数组void SetObjectArrayInit(string name){m_type = OBJECT;CCTObject tmp;tmp.m_type = ARRAY;m_Object[name] = tmp;}//给对象拥有的对象数组添加对象void SetObjectArrayPushBack(string name, CCTObject value){m_type = OBJECT;m_Object[name].SetArrayPushBack(value);}//给对象拥有的属性数组添加属性void SetObjectArrayPushBack(string name, string value){m_type = OBJECT;CCTObject tmp;tmp.SetProperty(value);m_Object[name].SetArrayPushBack(tmp);}void SetObjectAdd(string const& name, CCTObject const& value){m_type = OBJECT;m_Object[name] = value;}void SetObjectAddRef(string const& name, CCTObject * value){m_type = OBJECT;CCTObject tmp;tmp.SetPointer(value);m_Object[name] = tmp;}
每个方法都很简单。
2.3 查找对象
这是个很重要的方法,对象名是个点分字符串,也可以包含数组下标操作[]。将对象名拆解后逐级搜索对象。
//查找对象CCTObject* FindObject(string const& objname){string str;long index = -1;StringTokenizer st(objname, ".");CCTObject* ret = this;DEBUG_LOG << objname << " st.size " << st.size() << endi;for (size_t i = 0; i < st.size(); ++i){DEBUG_LOG << st[i] << endi;while (POINTER == ret->m_type)ret = ret->m_Pointer;size_t pos = st[i].find("[");if (pos != string::npos){index = atol(st[i].substr(pos + 1).c_str());str = st[i].substr(0, pos);}else{index = -1;str = st[i];}if (PROPERTY == ret->m_type){thelog << str << " 不是对象" << ende;return NULL;}else if (OBJECT == ret->m_type){if (ret->m_Object.find(str) != ret->m_Object.end()){ret = &ret->m_Object.find(str)->second;if (index >= 0){if (ARRAY != ret->m_type){thelog << str << " 不是数组" << ende;return NULL;}ret = &ret->m_Array[index];}}else{DEBUG_LOG << str << " 不存在 " << objname << ende;return NULL;}}else{thelog << str << " 未知的类型 " << ret->m_type << ende;return NULL;}}return ret;}
2.4 显示对象
如何把程序里的数据正确地打印出来对很多程序员好像是个难题啊(更愿意解释为“懒惰”?)。
输出多级结构的关键是使用正确的缩进,另外要学会如果设置终端的宽度(不然不够显示)。
使用正确缩进的技巧不过是在递归显示函数里传递深度并用深度构造缩进前缀而已。
//deep=-1不限深度,自身deep=0string tostring(string& ret, long level, long deep)const{string px;long n;for (long i = 0; i < level; ++i)px += "\t";stringstream ss;if (!(deep < 0 || level < deep)){return "";}if (POINTER == m_type){ss << px << "---->>>> :" << endl;string str;ss << tostring(str, level + 2, deep);}else if (PROPERTY == m_type){ss << px << "PROPERTY " << m_Property << endl;}else if (ARRAY == m_type){ss << px << "ARRAY size " << m_Array.size() << endl;n = 1;for (vector<CCTObject >::const_iterator it = m_Array.begin(); it != m_Array.end(); ++it){ss << px << "\t" << n << endl;string str;ss << it->tostring(str, level + 2, deep);++n;}}else if (OBJECT == m_type){if (0 == m_Object.size()){ss << px << "empty" << endl;}for (long i = 0; i < 3; ++i){n = 1;for (map<string, CCTObject >::const_iterator it = m_Object.begin(); it != m_Object.end(); ++it){if (0 == i && PROPERTY != it->second.m_type)continue;if (1 == i && ARRAY != it->second.m_type)continue;if (2 == i && OBJECT != it->second.m_type)continue;string str;if (PROPERTY != it->second.m_type){ss << px << n << "\t" << it->first << endl;ss << it->second.tostring(str, level + 2, deep);}else{ss << px << n << "\t" << it->first << " \t PROPERTY \t" << it->second.m_Property << endl;}++n;}}}else{ss << px << "此类型不能输出 " << m_type << endl;}return ss.str();}string& toString(string& ret)const{return ret = tostring(ret, 0, -1);}
三、堆栈结构和总入口
待续
(这里是结束但不是整个系列的结束)