摘 要:本文分析了開放式工控組態軟件系統的優勢和不足,介紹了自定義的Child-C語言編譯和解釋系統。使用該系統可以較大地增強組態軟件系統在流程控制和應急處理方面的能力。同時還引進了事件的概念。文章重點介紹了在解釋執行環境中處理二進制可執行代碼的一種有效方案。
關鍵詞:編譯;解釋執行;事件;COM;自動化;工控;組態
1 基于COM的工控組態軟件的框架分析
傳統的工控組態軟件[1]一般可以分為兩部分:組態設計系統和組態運行系統。組態設計系統可以按照實際工業流程的需要選擇工控功能模塊,設置各個模塊間的關聯和數據流向等系統參數,從而建立一套完整的控制系統。組態運行系統建立在組態設計系統基礎之上,它按照設計系統設定的參數啟動相應的工控功能模塊,并負責模塊之間數據的傳輸和并發控制等。
基于COM的工控組態軟件[2]以面向對象的柔性設計與控制理論為基礎[3],將面向對象技術應用于控制領域,把控制領域中的功能模塊和對應的控制數據抽象封裝成COM組件,按照開放式軟件平臺的原則將這些COM組件以插件的形式被加載到軟件系統中。COM組件是與語言無關的二進制組件,使用任何語言開發的符合接口規定的COM組件都可以在組態軟件系統中使用,因此提高了組態軟件的開放性和收縮性,在系統設計階段,設計人員可以像搭積木一樣快速而直觀的搭建出一條控制流水線。
每個COM組件是被單獨開發的高度抽象的功能模塊,它偏重于數據的計算處理而缺乏對系統環境變化的應變能力,組件之間的數據交互能力也較差。它與系統和其它的控制組件的耦合性較小,要完全同其它組件融合在一起并在大的系統環境中良好地運轉和適度靈活的應變系統的變化是比較困難的。這就需要在組態設計系統中使用輔助控制語言對這些組件的活動加以控制,規范控制流程。如圖1所示,在組態設計系統中引入事件(Event)的概念,在事件的響應函數中使用輔助控制語言規范控制流程和組件的活動,經過編譯后生成中間代碼提交給組態運行系統。相應地在組態運行系統中建立解釋環境對中間代碼進行解釋執行,從而達到規范流程控制的目的。
[align=center]

圖1 編譯和解釋運行原理圖[/align]
2 COM組件和自動化對象
COM是用于開發分布式軟件模型的組件化程序設計模型,它是建立在二進制可執行代碼級基礎上的。支持IDispatch接口的COM組件對象稱為自動化對象,該接口允許將一個函數的名稱以字符串的形式提交給組件,組件根據函數的名稱自動調用相應的函數。該接口提供的這種機制可實現對COM組件的統一調度。本文介紹的編譯器和解釋器的工作就建立在該機制之上,它為如何在解釋執行環境中啟動二進制可執行代碼提供了很好的解決方案。
3 編譯器和解釋器體系的框架分析
3.1 控制語言功能的選擇
C語言功能豐富,表達能力強,目標程序效率高,可移植性好,控制靈活,普及面廣,非常適用于工業控制領域。C語言功能強,語法規則也很龐大,但是要構造一個完整的C語言編譯器用于流程的控制則顯得過于浪費。我們構造了C語言語法規則的一個子集——Child-C,該子集保留了C語言的分支、循環、賦值、常量和變量的定義以及函數調用等基本語法規則,去掉了匯編語言的處理能力。
3.2 中間代碼編譯器與二進制代碼編譯器邊界的劃分
由上面的分析可以看出,整個控制系統要實現的功能代碼要經過中間代碼編譯器與二進制代碼編譯器兩種編譯器共同編譯。如圖2所示,我們可以把完整編譯器所具備的功能看成是一個大的集合,在這個集合中可以找到一條分界線:分界線左邊的功能是中間代碼編譯器必須具備的,它需要我們自己設計實現;分界線右邊的功能是二進制代碼編譯器所具備的,可以編譯出高效的具有數據運算處理等功能的二進制機器碼,它不需要我們動手實現。這條分界線是可以移動的,我們需要盡量使它向左移動,壓縮中間代碼編譯器的功能,從而減少開發的工作量。把復雜的數據處理能力和底層訪問能力放到右邊。
[align=center]

圖2 兩類編譯器的分界[/align]
3.3 運行時存儲空間組織
Child-C能夠處理的數據類型除了C語言中傳統的長短整形、浮點、實數、字符、數組、指針和結構體外還有COM對象。如圖3a所示,它描述了操作系統、組態軟件運行系統和解釋器運行時三者存儲空間之間的關系。它們是包含的關系,解釋器是被組態軟件運行系統建立的,所以它實際上屬于組態軟件運行系統的一部分。如圖3b所示,解釋器運行時存儲空間可以分為6部分。第一部分占64個字節,它存儲了兩組共16個虛擬寄存器,名稱為R0,R1,R2…依次類推。第一組包含8個寄存器,它用來完成除了變長字符串之外的所有中間指令數據操作。第二組包含8個寄存器,它專門用來完成變長字符串相關指令的操作。第二部分占12個字節,它存儲了3個32位的無符號整數,分別記錄了全局堆基址、全局變量基址和運行時堆基址。第三部分是COM組件地址映射區,該區的作用將在后面詳細描述。第四部分是全局堆存儲區,它用來存儲Child-C代碼中用 new 操作符動態申請的數據空間以及所有的變長字符串數據,該區的大小是在解釋器啟動前設定的,解釋器一但運行該值就不能改變。第五部分為全局變量存儲區,該區存儲的是可以被所有函數訪問的全局參數,如控制環境的平均溫度和濕度等。第六部分為運行時棧存儲區,Child-C編寫的函數全部運行在這個空間之上,它不但存儲函數體定義的形參、變量和返回值,還要存儲過程調用和返回時所需的控制鏈數據。
[align=center]

圖3 存儲空間關系圖(a)和運行時存儲空間示意圖(b)[/align]
3.4 中間代碼操作數的定義
Child-C程序被編譯成中間代碼指令被解釋器執行,如以下的Child-C語句執行相加操作:
int a,b,c; a=b+c;
它被編譯為如下幾條中間代碼指令:
LOD R0 Ox00000010 4; ①—— 加載變量a到寄存器R0,Ox00000010是變量a在運行時堆存儲區內的偏移地址,4表示加載的數據為4個字節
LOD R1 Ox00000014 4; ②—— 加載變量b到寄存器R1
ADD ③—— R1+R0->R2,三個寄存器的意義是固定的
STR R2 Ox00000018 ④— 將寄存器R2的值保存到變量c中
其中指令③的ADD指令是二元操作數指令,但是它的操作數固定為R0和R1寄存器,計算結果也固定放到R3中。
3.5 字符串的兼容和特殊處理
C語言中的字符串是通過字符數組進行處理的,Child-C繼承了這種字符串處理方法。字符數組是長度固定的字符串,而在使用Child-C與COM組件交互時經常要處理COM標準的BSTR類型變長字符串,為了兼容該數據類型,在Child-C中增加了bstr類型的變長字符串數據類型。bstr由頭尾兩部分組成:頭部信息由head和len兩個32位無符號整形組成,頭部信息代表了字符串實體,它可以作為局部和全局變量存儲,head是一個指針,它指向字符數據在全局堆中的首地址,len記錄了字符串的長度。尾部信息保存在全局堆存儲區中,字符信息在該區中并不是連續的,這也適應了字符串長度變化的需要。bstr可以直接代替BSTR類型,中間代碼指令集中有專門的轉換指令COMTOC和CTOCOM進行數據轉換。當需要將bstr轉換成BSTR時,編譯器自動添加COMTOC指令,該指令根據bstr的頭信息讀取字符數據組裝成BSTR數據提交給COM組件,而CTOCOM是一個逆過程。這兩條指令使用特設的第二組虛擬寄存器進行轉換操作。
3.6 COM組件的訪問
COM對象的訪問需要進行特殊處理,它是在解析運行環境建立之前就已經存在的。如圖3a所示,它存儲在組態軟件系統的存儲空間中,它不會隨著解釋運行環境的消亡而消亡。而除此之外的數據都存儲在解釋器的存儲空間中,它們會隨著解釋運行環境的消亡而消亡。為了便于編譯器和解釋器統一存儲空間的處理,需要將COM組件映像到解釋器存儲空間中,圖3b中的COM組件地址映射區就用來保存COM組件地址的映像。在編譯器和解釋器的運行過程中,所有對COM組件的訪問都被映射到該區域,從而避免了存儲空間的交叉訪問。
3.7 解釋器環境中對COM組件方法的調用
COM組件的各種函數已經被編譯成可被計算機直接執行的機器代碼,自動化COM對象允許使用IDispatch接口的統一調度函數Invoke()調用組件的函數,被執行的函數可以當作一個字符串參數被傳送。因此在構造的中間代碼指令集中有一條INVOKE指令,該指令格式為:INVOKE ComOffset FuncOffset ParaOffset;該指令有三個操作數:ComOffset為要訪問的COM組件在COM組件地址映射區的偏移,FuncOffset為被調用函數的名稱bstr變量地址,ParaOffset是該函數參數的個數和參數的存儲單元地址,該存儲區之后是一個4字節的單元,它用來保存Invoke()函數執行的返回值。就是說,對COM組件的所有操作,解釋器只需通過執行Invoke()函數就能完成。
4 事件體系的構造
Child-C函數是通過事件觸發而被調用的。事件包含兩種類型,一種是組件運行系統定義的事件,該類型事件屬于整個系統,它與具體組件無關,但可以被COM組件和系統觸發。另一種是COM組件自定義的事件,該類型事件屬于COM組件,它只能被組件自身觸發。事件發生時觸發解釋器解釋運行事件的相應函數。事件的處理工作全部交給事件槽來處理,事件槽實際上是一個可鏈接對象接收器[5],它可以接受系統和COM組件觸發的事件,同時它還維護了一張事件映射表,該表記錄了所有添加了響應函數的事件和該事件響應函數的入口地址以及有關參數信息。當有事件到達時,首先檢查事件映射表該事件是否有被注冊,如果有則根據響應函數的參數信息分配存儲空間并調用響應函數。
5 結束語
在實際的生產應用中可以證明,Child-C完全可以勝任絕大部分流程控制的需要,提高了工控組態軟件的靈活性。解釋器環境開發難度小但是程序執行效率低,自動化COM組件的函數調度機制可以很好的解決這種矛盾,該機制還可以廣泛地應用于其它領域。
參考文獻:
[1] 李志剛.工控組態軟件及其在工業控制中的應用[J].微機算計信息,1998;14(3)
[2] 夏坤,張建國,蔣洪. COM+及其在組態軟件中的應用研究[J].計算機工程與應用,2002,20.117-119
[3] 王培進.面向對象的柔性設計與控制理論(I)[J].計算機工程與應用,2001;36(16):17-19
[4] 潘愛民.COM原理與應用[M].北京:清華大學出版社,1999.12
[5] KennethCLouden.編譯原理與實踐[M].北京:機械工業出版社,1998.
[6] 熊清平,張正勇,李作清.CNC系統巨量NC程序解釋實現的方法[J].中國機械工程,1999,10(6):673-675.