首页 > C/C++开发工具专区 > VC技术 > C++中消息自动派发之二 About IDL解析器
2012
02-22

C++中消息自动派发之二 About IDL解析器

 前一篇blog中讲了如何在C++中实现消息的自动派发,而关键点在于如何实现通过IDL文件自动生成msg_dispatcher模板类。有几个网友提醒我idl解析器会比较难写,事实却是如此。我第一个版本的idl解析器本来只是想做demo只用。花了一个晚上时间拼凑了几个python函数,msg_dispatcher类倒是能生成,但解析器的代码太混乱了,简直毫无结构可言。说实话,这个消息自动派发框架我还要深入的开发、扩展、优化,所以还是像模像样的搞一个解析器吧。于是果断扔掉第一版本的解析器代码,重新实现之。仍然采用Python实现,目前只完成了cpp代码生成器,并且只能支持消息体的decode,不支持encode,语法报错机制也没有加入。随未完美,但是毕竟开了个好头,这里讲一下解析器的实现。

完整示例代码 svn co http://ffown.googlecode.com/svn/trunk/fflib/lib/generator/


示例idl 文件:svn co http://ffown.googlecode.com/svn/trunk/fflib/lib/generator/example.idl


struct student_t
{
struct book_t
{
int16 pages;
};
string age;
};


 1. 词法分析


    用Python的好处是解析字符串非常方便,首先要把idl源文件解析成单个的单词。我定义了一个src_parser_t类实现此功能。解析分如下几步:


  1> 读入idl 源文件内容


  2> 把源文件内容分隔成单个行,只需将file_content_str.split(‘\n’)即可。


  3> 在把每行按空格分隔成单个单词 split(‘ ‘)即可


  4> 如果有单词最后一个字符有分号去掉。


解析代码如下(只有80行):


from pylib.inc import *

class src_parser_t:
def __init__(self, file):
self.file = file
self.struct_def_mgr = struct_def_mgr_t()
self.file_content =
self.all_words = []
f = open(file)
self.file_content = f.read()
f.close()
def get_struct_def_mgr(self):
return self.struct_def_mgr
def parse_to_words(self):
all_line = self.file_content.split(\n)
for line in all_line:
words = line.split( )
for w in words:
w = w.strip()
if w != :
self.all_words.append(w)

def build_struct_relation(self):
struct_stack = []
index = 0
while index < len(self.all_words):
if len(struct_stack) < 1:
struct_stack.append(self.struct_def_mgr)

parent_struct = struct_stack[len(struct_stack) - 1]
cur_word = self.all_words[index]
if cur_word == struct:
struct_def = struct_def_t(self.all_words[index + 1])
parent_struct.add_struct(struct_def)
struct_stack.append(struct_def)
index = index + 1
elif cur_word == } or cur_word == };:
struct_stack.pop()
elif cur_word == int8 or cur_word == int16 or cur_word == int32 or \
cur_word == float or cur_word == string:
field_name = self.all_words[index + 1].split(;)[0]
field = field_def_t(field_name, cur_word, , )
parent_struct.add_field(field)
index = index + 1
else:
if -1 == cur_word.find(dictionary) and -1 == cur_word.find({) and -1 == cur_word.find(array) :
field_name = self.all_words[index + 1].split(;)[0]
field = field_def_t(field_name, cur_word, , )
parent_struct.add_field(field)
index = index + 1
else:
field_type =
field_name =
key_type =
val_type =
if -1 != cur_word.find(array):
field_name = self.all_words[index + 1].split(;)[0]
word_split = cur_word.split(<)
field_type = word_split[0]
key_type = word_split[1].split(>)[0]
field = field_def_t(field_name, field_type, key_type, )
parent_struct.add_field(field)
index = index + 1
elif -1 != cur_word.find(dictionary):
field_name = self.all_words[index + 1].split(;)[0]
word_split = cur_word.split(<)
field_type = word_split[0]
key_val_type = word_split[1].split(>)
key_type = key_val_type[0].split(,)[0]
val_type = key_val_type[0].split(,)[1]
field = field_def_t(field_name, field_type, key_type, val_type)
parent_struct.add_field(field)
index = index + 1
index = index + 1

def exe(self):
self.parse_to_words()
self.build_struct_relation()


2. 语法分析


  idl 文件语法规则非常简单,遍历所有单词,依次做如下判断:


  1> 如果当前单词为struct, 那么下一个单词即为新的消息体名称,当然也有可能是子消息体,无需担心,只需将新创建的消息体对象添加到特定栈的的栈顶struct对象中,默认struct_def_mgr存在于栈中。并把新的消息体压入栈中。


  2> 如果为int/string/float/array/dictionary,那么下一个单词即为消息体的字段名称。把新字段对象add到栈顶的struct_def对象中


  3> 遇到‘}’ 代表当前struct的解析完成。pop 弹出栈顶struct_def 对象。


  4> 其他字段忽略


3. 消息体结构管理


  1> field_def_t 描述消息体字段信息,包括字段的名称、类型、key_type、val_type、父消息体对象。如array<int>那么key_type为int,如果dictionary<int,string> 那么key_type为int, val_type为string


  2> struct_def_t 描述单个消息体的信息,包括消息体名称、子消息集合、字段对象集合。


  3> struct_def_mgr_t 维护所有的消息体集合。


代码即注释:


class field_def_t:
def __init__(self, name, type, key_type, val_type_):
self.name = name
self.parent = None
self.type = type
self.key_type = key_type
self.val_type = val_type_
def get_name(self):
return self.name
def get_parent(self):
return self.parent
def set_parent(self, p):
self.parent = p
def get_type(self):
return self.type
def get_key_type(self):
return self.key_type
def get_val_type(self):
return self.val_type
def dump(self, prefix = ):
print(prefix, self.name, self.type, self.key_type, self.val_type)

class struct_def_t:
def __init__(self, name, parent = None):
self.name = name
self.parent = parent
self.all_fields = {}
self.sub_struct = []

def get_name(self):
return self.name
def get_parent(self):
return self.parent
def set_parent(self, parent):
self.parent = parent
def add_field(self, field_def_):
self.all_fields[field_def_.get_name()] = field_def_
field_def_.set_parent(self)
def add_struct(self, struct_def_):
self.sub_struct.append(struct_def_)
struct_def_.set_parent(self)
def get_all_struct(self):
return self.sub_struct
def get_all_field(self):
return self.all_fields
def get_parent(self):
return self.parent
def has_field(self, name):
if None == self.all_fields.get(name):
return False
return True
def dump(self, prefix = ):
print(prefix, self.name, include struct:)
for struct in self.sub_struct:
struct.dump(prefix + )
print(prefix, self.name, include fields:)
for field in self.all_fields:
self.all_fields[field].dump(prefix + )


class struct_def_mgr_t:
def __init__(self):
self.all_struct = {}
def get_name(self):
return
def add_struct(self, struct_def_):
self.all_struct[struct_def_.get_name()] = struct_def_
struct_def_.set_parent(None)
def get_all_struct(self):
return self.all_struct
def get_struct(self, name):
return self.all_struct[name]
def get_parent(self):
return
def dump(self):
for name in self.all_struct:
self.all_struct[name].dump()



4. 中间代码生成


  代码是由code_generator_t 类实现的。考虑到未来需要支持多语言,中间代码生成采用策略模式。当前只实现了cpp的code_generator。如果要增强其他语言,只需再编写一个特定的code_generator_t类即可。


5. TODO


  1> struct 消息体只支持decode from json,还不能支持encode to json,也不能支持decode from Bin or encode to Bin。


  2> 语法报错不够友好。


  3> 多语言支持。


FROM:http://www.cnblogs.com/zhiranok/archive/2012/02/21/json_to_cpp_struct_idl_parser.html


C++中消息自动派发之二 About IDL解析器》有 0 条评论

  1. coolker 说:

     前一篇blog中讲了如何在C++中实现消息的自动派发,而关键点在于如何实现通过IDL文件自动生成msg_dispatcher模板类。有几个网友提醒我idl解析器会比较难写,事实却是如此。我第一个版本的idl解析器本来只是想做demo只用。花了一个晚上时间拼凑了几个python函数,msg_dispatcher类倒是能生成,但解析器的代码太混乱了,简直毫无结构可言。说实话,这个消息自动派发框架我还要深入的开发、扩展、优化,所以还是像模像样的搞一个解析器吧。于是果断扔掉第一版本的解析器代码,重新实现之。仍然采用Python实现,目前只完成了cpp代码生成器,并且只能支持消息体的decode,不支持encode,语法报错机制也没有加入。随未完美,但是毕竟开了个好头,这里讲一下解析器的实现。

    完整示例代码 svn co http://ffown.googlecode.com/svn/trunk/fflib/lib/generator/

    示例idl 文件:svn co http://ffown.googlecode.com/svn/trunk/fflib/lib/generator/example.idl

    struct student_t{    struct book_t    {        int16       pages;    };   string           age;};

     1. 词法分析

        用Python的好处是解析字符串非常方便,首先要把idl源文件解析成单个的单词。我定义了一个src_parser_t类实现此功能。解析分如下几步:

      1> 读入idl 源文件内容

      2> 把源文件内容分隔成单个行,只需将file_content_str.split(‘\n’)即可。

      3> 在把每行按空格分隔成单个单词 split(‘ ‘)即可

      4> 如果有单词最后一个字符有分号去掉。

    解析代码如下(只有80行):

    from pylib.inc import *
    
    class src_parser_t:    def __init__(self, file):        self.file = file        self.struct_def_mgr = struct_def_mgr_t()        self.file_content =         self.all_words    = []        f = open(file)        self.file_content = f.read()        f.close()    def get_struct_def_mgr(self):        return self.struct_def_mgr    def parse_to_words(self):        all_line = self.file_content.split(\n)        for line in all_line:            words = line.split( )            for w in words:                w = w.strip()                if w != :                    self.all_words.append(w)
    
        def build_struct_relation(self):        struct_stack = []        index = 0        while index < len(self.all_words):            if len(struct_stack) < 1:                struct_stack.append(self.struct_def_mgr)
    
                parent_struct = struct_stack[len(struct_stack) - 1]            cur_word = self.all_words[index]            if cur_word == struct:                struct_def = struct_def_t(self.all_words[index + 1])                parent_struct.add_struct(struct_def)                struct_stack.append(struct_def)                index = index + 1            elif cur_word == } or cur_word == };:                struct_stack.pop()            elif cur_word == int8 or cur_word == int16 or cur_word == int32 or \               cur_word == float or cur_word == string:                field_name = self.all_words[index + 1].split(;)[0]                field = field_def_t(field_name, cur_word, , )                parent_struct.add_field(field)                index = index + 1            else:                if -1 == cur_word.find(dictionary) and  -1 == cur_word.find({) and -1 == cur_word.find(array) :                    field_name = self.all_words[index + 1].split(;)[0]                    field = field_def_t(field_name, cur_word, , )                    parent_struct.add_field(field)                    index = index + 1                else:                    field_type =                     field_name =                     key_type   =                     val_type   =                     if -1 != cur_word.find(array):                        field_name = self.all_words[index + 1].split(;)[0]                        word_split = cur_word.split(<)                        field_type = word_split[0]                        key_type = word_split[1].split(>)[0]                        field = field_def_t(field_name, field_type, key_type, )                        parent_struct.add_field(field)                        index = index + 1                    elif -1 != cur_word.find(dictionary):                        field_name = self.all_words[index + 1].split(;)[0]                        word_split = cur_word.split(<)                        field_type = word_split[0]                        key_val_type = word_split[1].split(>)                        key_type = key_val_type[0].split(,)[0]                        val_type = key_val_type[0].split(,)[1]                        field = field_def_t(field_name, field_type, key_type, val_type)                        parent_struct.add_field(field)                        index = index + 1            index = index + 1
    
        def exe(self):        self.parse_to_words()        self.build_struct_relation()        

    2. 语法分析

      idl 文件语法规则非常简单,遍历所有单词,依次做如下判断:

      1> 如果当前单词为struct, 那么下一个单词即为新的消息体名称,当然也有可能是子消息体,无需担心,只需将新创建的消息体对象添加到特定栈的的栈顶struct对象中,默认struct_def_mgr存在于栈中。并把新的消息体压入栈中。

      2> 如果为int/string/float/array/dictionary,那么下一个单词即为消息体的字段名称。把新字段对象add到栈顶的struct_def对象中

      3> 遇到‘}’ 代表当前struct的解析完成。pop 弹出栈顶struct_def 对象。

      4> 其他字段忽略

    3. 消息体结构管理

      1> field_def_t 描述消息体字段信息,包括字段的名称、类型、key_type、val_type、父消息体对象。如array<int>那么key_type为int,如果dictionary<int,string> 那么key_type为int, val_type为string

      2> struct_def_t 描述单个消息体的信息,包括消息体名称、子消息集合、字段对象集合。

      3> struct_def_mgr_t 维护所有的消息体集合。

    代码即注释:

    class field_def_t:    def __init__(self, name, type, key_type, val_type_):        self.name       = name        self.parent     = None        self.type       = type        self.key_type   = key_type        self.val_type   = val_type_    def get_name(self):        return self.name    def get_parent(self):        return self.parent    def set_parent(self, p):        self.parent = p    def get_type(self):        return self.type    def get_key_type(self):        return self.key_type    def get_val_type(self):        return self.val_type    def dump(self, prefix = ):        print(prefix, self.name, self.type, self.key_type, self.val_type)
    
    class struct_def_t:    def __init__(self, name, parent = None):        self.name       = name        self.parent     = parent        self.all_fields = {}        self.sub_struct = []
    
        def get_name(self):        return self.name    def get_parent(self):        return self.parent    def set_parent(self, parent):        self.parent = parent        def add_field(self, field_def_):        self.all_fields[field_def_.get_name()] = field_def_        field_def_.set_parent(self)    def add_struct(self, struct_def_):        self.sub_struct.append(struct_def_)        struct_def_.set_parent(self)    def get_all_struct(self):        return self.sub_struct    def get_all_field(self):         return self.all_fields    def get_parent(self):        return self.parent    def has_field(self, name):        if None == self.all_fields.get(name):            return False        return True    def dump(self, prefix = ):        print(prefix, self.name, include struct:)        for struct in self.sub_struct:            struct.dump(prefix + )        print(prefix, self.name, include fields:)        for field in self.all_fields:            self.all_fields[field].dump(prefix + )
    
    class struct_def_mgr_t:    def __init__(self):        self.all_struct = {}    def get_name(self):        return     def add_struct(self, struct_def_):        self.all_struct[struct_def_.get_name()] = struct_def_        struct_def_.set_parent(None)    def get_all_struct(self):        return self.all_struct    def get_struct(self, name):        return self.all_struct[name]    def get_parent(self):        return     def dump(self):        for name in self.all_struct:            self.all_struct[name].dump()

    4. 中间代码生成

      代码是由code_generator_t 类实现的。考虑到未来需要支持多语言,中间代码生成采用策略模式。当前只实现了cpp的code_generator。如果要增强其他语言,只需再编写一个特定的code_generator_t类即可。

    5. TODO

      1> struct 消息体只支持decode from json,还不能支持encode to json,也不能支持decode from Bin or encode to Bin。

      2> 语法报错不够友好。

      3> 多语言支持。

    FROM:http://www.cnblogs.com/zhiranok/archive/2012/02/21/json_to_cpp_struct_idl_parser.html

留下一个回复