nesC 1.1 語言參考手冊 (1)

來源:互聯網
上載者:User
1 簡介nesC 是對 C 的擴充 [2] ,它基於體現 TinyOS 的結構化概念和執行模型而設計 [1] 。 TinyOS 是為感應器網路節點而設計的一個事件驅動的作業系統,感應器網路節點擁有非常有限的資源 ( 舉例來說., 8K 位元組的程式儲存器,512個位元組的隨機存取儲存器) 。TinyOS 用 nesC 重新編寫。本手冊描述 nesC 的 1.1 版本, 在第 3 段中概述了它與1.0版的不同。 nesC 基本概念如下:       結構和內容的分離 :程式由組件構成, 它們裝配在一起 (" 配線 ") 構成完整程式. 組件定義兩類域, 一類用於它們的描述 ( 包含它們的介面請求名稱) ,另一類用於它們的補充。組件內部存在作業形式的協作。控制線程可以通過它的介面進入一個組件。這些線程產生於一件作業或硬體中斷。根據介面的設定說明組件功能。介面可以由組件提供或使用。被提供的介面表現它為使用者提供的功能,被使用的介面表現使用者完成它的作業所需要的功能。      介面有雙向性 :它們敘述一組介面供給者 (指令)提供的函數和一組被介面的使用者(事件)實現的函數。這允許一個單一的介面能夠表現組件之間複雜的互動作用 (舉例來說.,當某一事件在一個回調之前發生時,對一些事件的興趣登記)。 這是危險的,因為 TinyOS 中所有的長指令 (舉例來說. 發送包)是非中斷的; 他們的完成由一個事件( 發送完成)標誌。 通過敘述介面,一個組件不能調用發送指令除非它提供 sendDone 事件的實現。通常指令向下調用,比如, 從應用組件到那些比較靠近硬體的調用,而事件則向上調用。特定的原始事件與硬體中斷是關聯的 (這種關聯是由系統決定的,因此在本參考手冊中不作進一步描述)。       組件通過介面彼此靜態地相連。 這增加運行時效率,支援 rubust 設計, 而且允許更好的程式靜態分析。     nesC基於由編譯器產生完整程式碼的需求設計。這考慮到較好的代碼重用和分析。這方面的一例子是 nesC 的編譯-時間資料競爭監視器。      nesC 的協作模型基於一旦開始直至完成作業 , 並且中斷遠源可以彼此打斷作業. nesC 編譯器標記由中斷源引起的潛在的資料競爭。 本文是 nesC 的一本參考手冊並非個別指導。TinyOS tutorial1給出了對 nesC 的更貼切的介紹.本文的其餘部分構成如下: 第 2 節給出了本參考手冊中使用的記號。. 第 3 節概述 nesC 1.1 的新特徵。 第 4,5 節,6, 和 7介紹 nesC 介面和組件. 第 8 節給出 nesC的協作模型和資料競爭監視. 第 9 節解釋 C檔案, nesC 介面和組件是怎樣被裝配成一個應用. 第 10 節包含 nesC 的保留的各種特徵. 最後,附錄A完全定義 nesC 的文法 (來自Kernighan and Ritchie (K&R) [2, pp234–239]附錄A的對 C 文法述說的擴充),而附錄 B 是本參考手冊中所使用術語的專業詞彙詞典。  2 符號打字機字型作為 nesC 代碼和檔案名稱,帶任意下標的單個斜體字元用於表示 nesC 實體,舉例來說., " 組件 K" 或 " 數值 v"。nesC文法是ANSI C 文法的擴充. 我們選擇來自 Kernighan and Ritchie (K&R) 的附錄A的 ANSI C 文法[2, pp234 –239]作為我們介紹的基礎。在這裡我們將不重複ANSI C文法。. 斜體字是非終端機和非文字的終端機,打字機字型和符號是文字的終端機。 下標 opt 表示可選擇的終端機或非終端機。在一些情形中,我們改變一些 ANSI C 文法規則. 我們用下面的方式表示:also 為現存的非終端機指出新增的內容,replaced by表示替換一現有的非終點的.nesC 的結構解釋給出對應的文法片段。在這些片段中,我們有時使用 . . . 表現省略( 與當前不相關的解釋). 附錄A給出完整的 nesC 文法.一些例子使用來自 C99 標準 inttypes.h 檔案的 uint8 t 和 uint16 t 類型.  3 變化nesC 1.0版本同1.1版本的變化如下:1. 原子的陳述. 這些單一化協同資料結構的實現,能夠被新的編譯- 時間資料競爭監視器識別。2. 編譯- 時間資料競爭監視為可能的協同的二個中斷操作者 , 或一個中斷操作者和一件作業同時存取變數提出警告3. 指令和事件必須明確地標出儲存類型說明才能安全地被中斷操作者執行。4. 對指令或"扇出"事件的調用返回結果自動地被新的類型- 特性的組合器執行聯合。5. uniqueCount 是一個新的 " 常數功能 ", 具有獨特的作用.6. NESC 預先處理程式符號指出語言版本. 對於 nesC 1.1版本它是 110 。 4 介面nesC 的介面有雙向性: 它們在兩個組件之間建立了一個由多個函數組成的介面的通道,分為provider(供給)和use(使用)。介面聲明了一組函數,分為兩種,一種函數叫做commands, 由介面的供給者實現。另一種叫做events,留給介面的使用者實現。本節解釋介面如何被說明, 第 5 節解釋組件如何描述它們提供和使用的介面, 第 6 節解釋在 C代碼中指令和事件如何被調用和實現,而第 7 節解釋組件介面如何被一起聯編.介面被介面類型指定,如下:nesC-file:includes-listopt interfaceinterface:interface identifier { declaration-list }storage-class-specifier: also one ofcommand event async這聲明介面類型標識符. 這一標識符有全域的作用範圍並且屬於分開的命名空間,組件和介面類型命名空間。 如此所有介面類型都有清楚的名字以區別於其它介面和所有組件, 同時能不和一般的 C的聲明發生任何衝突。聲明列表中,每個介面類型都有一個分開的聲明範圍。聲明列表必須由有指令或事件儲存類型的功能描述組成( 否則, 會發生編譯-時間錯誤). 可選的 async 關鍵字指出指令或事件能在一個中斷處理者中被運行。通過包含列表,一個介面能可選擇地包括 C 檔案 (見第9節)。一個簡單的介面如下:interface SendMsg {command result_t send(uint16_t address, uint8_t length, TOS_MsgPtr msg);event result_t sendDone(TOS_MsgPtr msg, result_t success);}SendMsg 介面類型提供者必須實現發送指令, 而使用者必須實現 sendDone 事件.註:純粹的介面其實就是一組函式宣告的集合。其本身沒有實現任何功能。它的函數功能的實現是在module中去實現的。 5 組件說明一個 nesC 組件或是一個模組 (第 6 節) 或一個結構 (第 7 節):nesC-file:includes-listopt moduleincludes-listopt configurationmodule:module identifier specification module-implementationconfiguration:configuration identifier specification configuration-implementation組件的名字由標識符指定. 這一標識符有全域的作用範圍並且屬於組件和介面類型命名空間. 一個組件介入兩個分組件的範圍::一個規格範圍,屬於 C 中全域的範圍,和一個實現範圍屬於規格範圍。通過包含列表,一個組件能可選擇地包括 C 檔案 (見第9節).組件規格列出該組件提供或使用的規格元素 (介面請求,指令或事件)。就如我們在第 4 節中見到的,一個組件必須實現它提供介面的指令和它的使用的介面事件。另外,它必須實現它提供的指令和事件。典型地,指令向下調用硬體組件,而事件向上調用應用組件 (這表現為nesC應用如一個應用組件處於頂端的組件曲線圖)。 一個控制線程只有通過它的規格元素越過組件。每種規格元素有一個名字 (介面執行個體名,命令名或事件名).這些名字屬於總組件-規格範圍的變數命名空間。specification:{ uses-provides-list }uses-provides-list:uses-providesuses-provides-list uses-providesuses-provides:uses specification-element-listprovides specification-element-listspecification-element-list:specification-element{ specification-elements }specification-elements:specification-elementspecification-elements specification-element一個組件說明中可以有多個使用和提供指令。多個使用和提供規格元素可以通過包含在{ and}中而組合在一個指令中。舉例來說,下面兩個說明是一樣的:module A1 {                            module A1 {uses interface X;                     uses {uses interface Y;                             interface X;} ...                                                        interface Y;}} ...一個介面執行個體描述如下:specification-element:interface renamed-identifier parametersoptrenamed-identifier:identifieridentifier as identifierinterface-parameters: [ parameter-type-list ]介面執行個體聲明的完整文法是 interface X as Y,明確地指明Y作為介面的名字。interface X是interface X as X.的一個速記.如果介面沒有參數, 那麼interface X as Y 聲明一個簡單的介面執行個體,對應這一組件的一個單一介面。 如果一個帶參數的介面 (如: interface SendMsg[uint8 t id]) ,那麼這就是一個帶參量介面的執行個體聲明。對應這一組件的多個介面, 每個介面對應不同參數值(因此interface SendMsg[uint8 t id]聲明了最多256個SendMsg類型介面)。參數的類型必須是整數類型 (這裡enums 是不允許的)。commands或event事件能夠作為一個特殊的元素,被使用command或event關鍵字的標準C語言函式宣告,包含到類聲明中來:specification-element:declarationstorage-class-specifier: also one ofcommand event async如果該函式宣告沒有command或event關鍵字,那麼就會產生“編譯—時間”錯誤。在介面中,async (非同步)表示command或event事件允許中斷髮生並執行此中斷程式。作為介面執行個體, 如果沒有指定介面參數,指令 (事件)就是簡單的command (簡單的event)。如果介面參數是已經被指定,就是參數化的指令command (參數事件event)。介面參數被放置在一般的函數參數列表之前,舉例來說,command void send[uint8 t id](int x):direct-declarator: alsodirect-declarator interface-parameters ( parameter-type-list )注意介面參數只在組件說明裡面的指令或事件上被允許, 而不允許在介面類型裡面.這兒有一個完整的規格例子:configuration GenericComm{     provides {               interface StdControl as Control;// 該介面以當前訊息序號作參數               interface SendMsg[uint8_t id];               interface ReceiveMsg[uint8_t id];               }     uses {             //發送完成之後為組件作標記             //重試失敗的發送            event result_t sendDone();            }} ...在這個例子中,一般:      提供簡單的介面執行個體類型 StdControl 的控制.      提供介面類型 SendMsg 和 ReceiveMsg 的參數執行個體; 參數執行個體分別地叫做 SendMsg 和 ReceiveMsg.      使用事件 sendDone.我們說,在組件component K 的規範中提供的一個command (event) F 是component K的provides  command(event)F; 同樣地,一個被組件 K 的規範中使用的command (event) 是K 的uses command (event) F。    如果組件K中有介面執行個體X, command F是介面X的一個函數稱之為 X.F,我們是可說X.F屬於K; 6 模組模組用C代碼實現組件說明:module-implementation:implementation { translation-unit }這裡編譯基本單位是一連串的 C 聲明和定義 ( 見K& R[2 , pp234 –239])。模組編譯基本單位的頂層聲明屬於模組的組件說明域。這些聲明的範圍是模糊的而且可以是: 任意的標準 C聲明或定義,一種作業聲明或定義,指令或事件實現.6.1 實現模組的說明編譯基本單位必須實現模組的所有的提供指令 (事件)a (例如., 所有的直接提供指令和事件, 以及提供介面的所有指令和使用介面的所有事件). 一個模組能調用它的任一指令和它的任一事件的訊號.這些指令和事件的實現由如下的 C 文法擴充指定:storage-class-specifier: also one ofcommand event asyncdeclaration-specifiers: alsodefault declaration-specifiersdirect-declarator: alsoidentifier . identifierdirect-declarator interface-parameters ( parameter-type-list )簡單指令或事件a由帶有儲存類型指令或事件的C 函數定義的文法實現 (注意允許在函數名中直接定義的擴充)。另外,文法關鍵字必須被包含如果它被包含在a的聲明中。舉例來說,在SendMsg類型的提供介面Send的模組中:command result_t Send.send(uint16_t address, uint8_t length, TOS_MsgPtr msg) {return SUCCESS;}帶有介面參數P的參數指令或事件a,由帶有儲存類型指令或事件的函數定義的C文法實現,這時,函數的普通參數列表要以P作為首碼,並帶上方括弧 ( 這與組件說明中聲明參數化指令或事件是相同的文法)。這些介面三數聲明P 屬於a的函數三數範圍而且和普通的函數參數有相同的範圍。舉例來說,在SendMsg類型提供介面Send[uint8 tid]的模組中:command result_t Send.send[uint8_t id](uint16_t address, uint8_t length,TOS_MsgPtr msg) {return SUCCESS;}以下情況將報告編譯- 時間錯誤:     提供指令或事件沒有實現。    類型標誌,可選擇的介面三數和指令或事件文法關鍵字的存在或缺失,或與模組說明不匹配6.2 調用命令和事件訊號對 C 文法的下列擴充用於呼叫事件和向指令發出訊號:postfix-expression:postfix-expression [ argument-expression-list ]call-kindopt primary ( argument-expression-listopt )call-kind: one ofcall signal post命令函數的command a ,使用call a(...)調用, 事件函數使用signal a(...)發送訊號。例如:在一個模組中使用SendMsg類型介面Send:call Send.send(1,sizeof(Message), &msg1)。如果是帶有n個參數的command a(或者是一個事件event),參數的類型為t1,t2....tn,參數的值是e1...en.那麼調用的方式如下:call a[e1...en](...) (特別地,signal a[e1...en](...))。介面參數值運算式 ei 的類型為ti; 實際的介面參數值ei影射到ti。 例如, 在一個組件中使用類型 SendMsg 的介面Send[uint8 t id]:int x = ...;call Send.send[x + 1](1, sizeof(Message), &msg1);commands和events的執行是立即的,也就是,call和signal調用行為是立即的。實際的command或event事件是由調用還是訊號表達運行取決於程式結構聯絡說明。這些聯絡說明可能指定0,1 或更多的實現將被運行。當超過 1個實現被運行, 我們說模組的指令或事件為"扇出"。一個模組能為一使用指令或事件a指定預設的調用或訊號實現。提供指令或事件的預設實現會引起編譯-時間錯誤。如果a未與任何指令或事件實現聯絡,預設的實現將被執行。預設的指令或事件由帶有預設關鍵字的指令或事件實現首碼定義:declaration-specifiers: alsodefault declaration-specifiers舉例來說, 在一個類型 SendMsg使用介面Send的模組中:default command result_t Send.send(uint16_t address, uint8_t length,TOS_MsgPtr msg) {return SUCCESS;}... call Send.send(1, sizeof(Message), &msg1) ...第 7.4 節敘述實際上什麼指令或事件實現被運行以及調用和訊號表達返回什麼結果.6.3 作業作業是一個獨立的控制點,由一個返回空儲存類型的無二義性地函數定義:task void myTask() { ... }。作業也能預先聲明,舉例來說., task void myTask();作業通過首碼post調用通知,舉例來說., post myTask()。通知返回迅速;如果獨立執行通知成功則返回1,否則返回0。通知運算式的類型是unsigned char。storage-class-specifier: also one oftaskcall-kind: also one ofpostnesC的協作模型,包括作業,在第8節中詳細陳述。6.4 原子的陳述原子的陳述:atomic-stmt:atomic statement確保陳述被運行 " 好像 " 沒有其它的運算同時發生。它用於更新並發的資料結構的互斥變數,等等。一簡單的例子是:bool busy; //全域void f() {bool available;atomic {available = !busy;busy = TRUE;}if (available) do_something;atomic busy = FALSE;}原子的區段應該很短, 雖然這常常並不是必須的。控制只能" 正常地 " 流入或流出原子的陳述: 任何的 goto, break或continue,跳轉入或出一原子陳述都是錯誤的。返回陳述決不允許進入原子陳述。第 8 節討論原子和 nesC協作模型和資料競爭監視器之間的關係。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.