首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于包结构自动生成代码

基于包结构自动生成代码
EN

Stack Overflow用户
提问于 2016-09-24 01:08:26
回答 1查看 59关注 0票数 1

我们有不同结构的数据包。它们应该是用不同的语言读写的。示例:

代码语言:javascript
复制
| ClassId | Data |

ClassId = "datapoint" (Data structure):
  temperature - 1bytes
  elevation - 2bytes
  gradient - 1bytes
ClassId = "config" (Data structure):
  frequency - 1bytes
  deviceId - 3bytes
ClassId = "accelerometer" (Data structure):
  time - 2bytes
  x - 2bytes
  y - 2bytes
  z - 2bytes

我希望先有一个配置文件,然后再编写代码(python/c/etc),而不是手动编写根据数据包的类来解析每个数据包的代码(这容易出错且耗时)。是自动生成的,可以读写数据包。大致是这样的:

代码语言:javascript
复制
lib.set(packet, "datapoint", {
  elevation: 933,
  temperature: 18,
  gradient: 20
});
lib.get(packet, "datapoint");
=>
{
  elevation: 933,
  temperature: 18,
  gradient: 20
}

在谷歌上搜索它并没有带给我任何地方。任何指针都会非常有帮助。

EN

回答 1

Stack Overflow用户

发布于 2016-09-24 03:14:22

您需要一个代码生成系统,它将数据包规范编译成代码来解析/解析包。

您可以使用解析器生成器构建一个ad hoc,并编写ad hoc代码来按程序遍历解析树并输出相关代码。

或者,您可以使用program transformation system (PTS),它将您的包规范视为源代码,并转换为目标语言的源代码。向PTS解释数据包的语法几乎与向解析器生成器解释语法的方式相同。

但是使用PTS,您可以在表层语法表示法中编写转换规则,识别包系统语法并将其映射到目标语言函数语法。这使得编写和维护这样的工具变得容易得多,特别是当数据包语法发生变化,和/或您更改目标语言基础设施以以不同的方式解析数据包时。

EDIT 10/3: OP询问一个具体的例子,大概有一个PTS。

我将展示我们的DMS软件再工程工具包的样子(有关DMS的更多信息,请参阅bio )。

首先,您需要包语言的(与DMS兼容的)语法。根据我所看到的,这很简单:

代码语言:javascript
复制
Packets = Packet ;
Packets = Packets Packet ; -- allow a list of packet defintions

Packet = 'ClassID' '=' STRING members ;

 members = ;
 members = members member ; -- allow list of members

 member = IDENTIFIER '-' NATURAL 'bytes' ;

您还需要针对各种目标语言的语法。我将假设您已经掌握了这些语法(这是一个很好的假设);让我们暂时使用C语言。DMS确实有很多这样的东西。

我们还必须假设传输的数据的表示形式。OP提出了一些建议,但我认为他是在试图暗示生成的代码("lib.set...")。相反,我将假设从Stream中读取的数据包内容是简单地附加在一起的二进制字节;这使得数据包的大小尽可能最小,从而缩短了传输时间。

因此,现在我们需要指定我们的代码生成器,作为一组将数据包定义映射到代码的重写规则。

作为背景,PTS的重写规则通常如下所示:

代码语言:javascript
复制
          if you see *this*, replace it by *that*

因此,您实际上是在用另一个结构替换一个结构。它们通常在ASTs上操作,但为了可读性使用了表面语法。

下面是DMS的源代码到源代码重写规则;它们看起来像是在文本上操作,但实际上它们是在DMS的解析器生成的AST上操作的。DMS有自己的规则语法,但它基本上遵循上面的典型样式:

代码语言:javascript
复制
 rule rule_name( pattern_variables ): 
      source_syntax_category -> target_syntax_category =
      " this_pattern "  ->  " that_pattern " ;

源模式和目标模式包含在*metaquotes“中;因此,实际的文字引号字符被转义为\"

对于DMS规则,这始终是数据包符号的片段,并且始终是我们选择的目标语言(C)的片段。规则头中的模式变量名称被赋予语法类型,并且只能与AST中的相应类型匹配。metaquotes中的模式变量被写为\variable。元函数可以计算派生结果;它们在模式中被调用为"\function( args )“。有关更多详细信息,请参阅DMS Rewrite Rules

代码语言:javascript
复制
    source domain Packet; -- the little language we defined
    target domain C; -- what we will generate code for
            -- you'll write one of these rulesets for each target language

    rule top_level(pl: Packets): Packets -> Statements =
      " \pl "
     -> " ReadPacketType(stream, packet_type);
          switch(packet_type) {
              \pl
             default: Panic(\"unrecognized packet type\");
          }"  if  IsRoot(pl); -- do this once [at root of tree]


    rule translate_packet_definitions(p: Packet, pl: packet_list): Packets -> switch_case_list
         " \p  \pl ";

    rule translate_packet_definition(s:STRING, ms: members, pl: Packets): Packets -> switch_case =
       " ClassID = \s \m \pl "
        -> " case \concatenate\(\"enum_\"\,\string_to_identifier\(\s\)\): { 
                \string_to_identifier\(\s\)* p=malloc(sizeof(\string_to_identifier\(\s\)));
                \m
                return p;
             }
            ";

     rule translate_members(m: member, ms: members) : members -> Statements
        = " \m \ms ";

     rule translate_member(i: IDENTIFIER, n: NATURAL) = member -> StatementList =
          " \i - \n bytes " ->
          "  p-> \toCIdentifer\(\i\) = ReadNByteValue(stream,\toCNatural\(\n\)) ; "

这是不完整的(特别是,我需要另外一组规则来为数据包类型集生成枚举声明),我怀疑它是否完全正确,但它给出了规则的风格。使用这些规则,OP的示例输入将生成以下C代码:

代码语言:javascript
复制
ReadPacketType(stream, packet_type);
switch(packet_type) {
    case enum_datapoint: {
       datapoint* p=malloc(sizeof(datapoint));
       p->temperature=ReadNByteValue(stream,1);
       p->elevation=ReadNByteValue(stream,2);
       p->gradient=ReadNByteValue(stream,2);
       return p;
    }
    case enum_config: {
       config* p=malloc(sizeof(config));
       p->frequency=ReadNByteValue(stream,1);
       p->deviceId=ReadNByteValue(stream,3);
       return p;
    }
    case enum_accelerometer: {
       accelerometer* p=malloc(sizeof(accelerometer)); 
       p-time>=ReadNByteValue(stream,2);
       p->x=ReadNByteValue(stream,2);
       p->y=ReadNByteValue(stream,2);
       p->z=ReadNByteValue(stream,2);
       return p;
     }
     default: Panic(\"unrecognized packet type\");
} 
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39666127

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档