如何使用Lark解析自定义消息定义并生成C++结构体

来源:前端技术作者:弥生美月头衔:网络博主
导读:本期聚焦于小伙伴创作的《如何使用Lark解析自定义消息定义并生成C++结构体》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用Lark解析自定义消息定义并生成C++结构体》有用,将其分享出去将是对创作者最好的鼓励。

在分布式系统开发或者跨语言数据交互场景中,自定义消息定义是常用的数据描述方式,手动编写对应的C++结构体不仅繁琐还容易出错,使用Lark解析自定义消息定义并生成C++结构体可以高效解决这个问题。

如何使用Lark解析自定义消息定义并生成C++结构体

自定义消息定义格式设计

首先需要明确自定义消息定义的语法规则,这里我们设计一种简单的消息定义格式,支持消息名称、字段类型、字段名称的定义,示例如下:

message UserInfo {
    int32 id
    string name
    float score
}

上述格式中,message是消息关键字,后面跟着消息名称,花括号内是字段列表,每个字段由类型、名称组成,每行一个字段。

Lark语法规则编写

Lark支持使用EBNF风格的语法规则定义解析逻辑,我们需要根据自定义消息格式编写对应的语法规则:

from lark import Lark

# 定义Lark语法规则
message_grammar = r"""
    start: message_def+
    message_def: "message" ID "{" field_list "}"
    field_list: field*
    field: TYPE ID
    ID: /[a-zA-Z_][a-zA-Z0-9_]*/
    TYPE: "int32" | "string" | "float" | "double" | "int64"
    %import common.WS
    %ignore WS
"""

上述语法规则中,start是根规则,支持多个消息定义;message_def匹配单个消息的完整结构;field匹配单个字段;IDTYPE是终端规则,分别匹配标识符和字段类型。

解析自定义消息定义

使用编写好的语法规则初始化Lark解析器,然后解析自定义消息文本,得到结构化的解析树:

# 初始化Lark解析器
parser = Lark(message_grammar, parser="lalr")

# 待解析的自定义消息文本
message_text = """
message UserInfo {
    int32 id
    string name
    float score
}

message OrderInfo {
    int64 order_id
    double price
    string goods_name
}
"""

# 解析得到解析树
parse_tree = parser.parse(message_text)

遍历解析树生成C++结构体

解析树是嵌套的结构,我们需要编写遍历逻辑,提取消息名称和字段信息,然后拼接成C++结构体代码:

from lark import Transformer

class MessageTransformer(Transformer):
    def start(self, items):
        # 拼接所有消息的结构体代码
        return "n".join(items)

    def message_def(self, items):
        msg_name = items[0]
        fields = items[1]
        # 拼接结构体头部
        struct_code = f"struct {msg_name} {{n"
        # 拼接字段
        for field_type, field_name in fields:
            # 类型映射:自定义类型转C++类型
            type_map = {
                "int32": "int32_t",
                "int64": "int64_t",
                "string": "std::string",
                "float": "float",
                "double": "double"
            }
            cpp_type = type_map.get(field_type, field_type)
            struct_code += f"    {cpp_type} {field_name};n"
        struct_code += "};n"
        return struct_code

    def field_list(self, items):
        return items

    def field(self, items):
        return (items[0], items[1])

    def ID(self, token):
        return str(token)

    def TYPE(self, token):
        return str(token)

# 使用Transformer遍历解析树生成代码
transformer = MessageTransformer()
cpp_code = transformer.transform(parse_tree)
print(cpp_code)

完整示例代码与输出结果

将上述逻辑整合为完整可运行的脚本,执行后可以得到生成的C++结构体代码:

from lark import Lark, Transformer

# 语法规则
message_grammar = r"""
    start: message_def+
    message_def: "message" ID "{" field_list "}"
    field_list: field*
    field: TYPE ID
    ID: /[a-zA-Z_][a-zA-Z0-9_]*/
    TYPE: "int32" | "string" | "float" | "double" | "int64"
    %import common.WS
    %ignore WS
"""

# Transformer类
class MessageTransformer(Transformer):
    def start(self, items):
        return "n".join(items)

    def message_def(self, items):
        msg_name = items[0]
        fields = items[1]
        struct_code = f"struct {msg_name} {{n"
        type_map = {
            "int32": "int32_t",
            "int64": "int64_t",
            "string": "std::string",
            "float": "float",
            "double": "double"
        }
        for field_type, field_name in fields:
            cpp_type = type_map.get(field_type, field_type)
            struct_code += f"    {cpp_type} {field_name};n"
        struct_code += "};n"
        return struct_code

    def field_list(self, items):
        return items

    def field(self, items):
        return (items[0], items[1])

    def ID(self, token):
        return str(token)

    def TYPE(self, token):
        return str(token)

# 主逻辑
if __name__ == "__main__":
    parser = Lark(message_grammar, parser="lalr")
    message_text = """
    message UserInfo {
        int32 id
        string name
        float score
    }

    message OrderInfo {
        int64 order_id
        double price
        string goods_name
    }
    """
    parse_tree = parser.parse(message_text)
    transformer = MessageTransformer()
    cpp_code = transformer.transform(parse_tree)
    print("生成的C++结构体代码:")
    print(cpp_code)

执行上述代码后,输出的C++结构体代码如下:

struct UserInfo {
    int32_t id;
    std::string name;
    float score;
};

struct OrderInfo {
    int64_t order_id;
    double price;
    std::string goods_name;
};

扩展优化方向

上述实现是基础版本,还可以根据需求进行扩展:

  • 支持更多字段类型,比如数组、嵌套消息等,只需要在语法规则和类型映射中添加对应逻辑即可
  • 添加字段默认值、注释的解析支持,丰富生成的结构体功能
  • 增加代码输出到文件的功能,直接将生成的C++代码写入头文件,方便项目集成
  • 添加语法错误校验,当自定义消息定义不符合规则时给出明确的错误提示

Lark自定义消息定义C++结构体语法解析代码生成修改时间:2026-07-16 01:24:33

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。