2016-09-23 53 views
1

我們有不同結構的數據包。他們應該用不同的語言閱讀/書寫。例如:基於數據包結構自動生成代碼

| 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 

與其手動編寫解析是根據它的類中的每個數據分組中的代碼(其是容易出錯並且耗時),我期望有一個配置文件,然後將代碼(蟒/ c/etc)是自動生成的,可以讀取和寫入數據包。沿着這些線:

lib.set(packet, "datapoint", { 
    elevation: 933, 
    temperature: 18, 
    gradient: 20 
}); 
lib.get(packet, "datapoint"); 
=> 
{ 
    elevation: 933, 
    temperature: 18, 
    gradient: 20 
} 

谷歌搜索它並沒有帶給我任何地方。任何指針都會非常有幫助。

回答

-1

您需要一個代碼生成系統,將數據包規範編譯爲代碼以解析/解析數據包。

您可以使用解析器生成器構建一個ad hoc,並編寫專用代碼以程序化地遍歷解析樹並吐出相關代碼。

或者您可以使用program transformation system (PTS),它將您的數據包規範視爲源代碼,並轉換爲目標語言的源代碼。您向PTS解釋數據包的語法與解析器生成器的語法解釋非常相似。

但是對於PTS,您可以使用表面語法表示法編寫轉換規則,以識別包系統語法並將其映射到目標語言函數語法。這使得編寫和維護這樣一個工具變得更加容易,尤其是在數據包語法發生變化的情況下,和/或您更改目標語言基礎結構以不同方式解析數據包。

編輯10/3:OP要求一個具體的例子,可能與PTS。

我將展示DMS Software Reengineering Toolkit的外觀(有關DMS的更多信息,請參閱bio)。

首先,您需要一個(DMS兼容)語法的分組語言。根據我所看到的,這是很簡單的:

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' ; 

我覺得這個語法是在實踐中的分組成員天真可能有不同類型的(也許字符串,浮點數,布爾值,...); OP的例子只顯示我假定的是N字節的二進制整數。您還需要各種目標語言的語法。我會假設你有這些語法(這是相當的假設);讓我們暫時與C一起工作。 [DMS確實有很多這些]。

我們還必須假設傳輸數據的表示。 OP建議了一些東西,但我認爲他試圖暗示生成的代碼(「lib.set ...」)。 相反,我將假定數據包內容正在從Stream讀取,因爲二進制字節只是簡單地附加在一起;這使得儘可能小的分組大小以及因此快速的傳輸時間成爲可能。因此,現在我們來指定我們的代碼生成器,作爲將分組定義映射到代碼的重寫規則的集合。

爲背景,對PTS重寫規則通常是這樣的:

  if you see *this*, replace it by *that* 

所以你基本上是由另一個更換一個結構。這些通常在AST上運行,但爲了便於閱讀,使用這個的表面語法來表示

以下是DMS的源代碼重寫規則的來源;他們看起來像是對文本進行操作,但實際上他們使用DMS的解析器生成的AST。 DMS有它自己的語法規則,但基本上遵循上面的典型風格:

rule rule_name(pattern_variables): 
     source_syntax_category -> target_syntax_category = 
     " this_pattern " -> " that_pattern " ; 

源和目標模式是封閉在*邁達克「;因此,實際的文字引號字符轉義爲\」

對於DMS規則總是分組符號的片段,並始終是我們選擇的目標語言(C)的片段。模式規則頭部中的變量名稱是語法類型,只能匹配AST中的相應類型,在metaquotes中找到的模式變量被寫爲\ variable。元函數可以計算派生結果;它們在模式內被調用爲「\ function args)「,詳見DMS Rewrite Rules

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代碼:

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\"); 
} 
+0

Downvoter:我不認爲你會禮貌地解釋你的理由。答案是事實和有用的。 –

+0

基於問題中的示例結構,您能否給出一個具體的例子? – vohtaski