岳 萍
(電子科技大學成都學院電子工程系,四川 成都611731)
組態軟件以集中式控制系統為基礎,由此發展而來的。體現了“分散控制、集中操作、組態方便、分級管理”的思想。作為集散控制系統軟件平臺出現的組態軟件,具有友好的人機功能,采用圖像顯示,能在線進行系統組態和參數設置。而嵌入在組態軟件中的腳本模塊則能夠為其提供二次開發功能,使系統的開發更加靈活,組態更加地方便,功能更加地豐富和完善。
綜合多種流行的組態軟件分析,其中的腳本語言實現方式大致有以下三種:第一種是內置的類似于C或者Basic的語言;第二種是采用VBA的編程語言;第三種是目前來講只有少數組態軟件所采用的面向對象的腳本語言。本文以目前在瀏覽器Mozilla FireFox上用到的底層引擎SpiderMonkey為技術基礎,實現基于SpiderMonkey的腳本引擎功能,并實現腳本模塊與組態軟件各模塊間的實時通訊。
腳本模塊在組態軟件中的地位非常關鍵,它是連接前臺的圖形界面開發/運行模塊和臺的數據庫模塊的紐帶。圖形界面開發模塊通過調用腳本模塊進行配置,而腳本模塊又從數據庫中讀取或寫入實時數據。當圖形界面的運行模塊進入運行時,就會周期性的執行在開發模塊中配置好的腳本程序。
本設計中設計腳本模塊是基于SpiderMonkey的,而SpiderMonkey是一個JavaScipt解釋器引擎的API庫。它最大的特點是其開放性和可移植性。這使得該腳本模塊可以在多種平臺上運行。
應用程序腳本模塊的設計的根本在于怎樣將JavaScript引擎嵌入到應用程序中去。嵌入的過程如下:
JavaScript引擎利用Runtime來管理對象、上下文和與JavaScript的函數及腳本相關的變量,為應用程序需要的對象、上下文句柄、變量和腳本分配所需要的內存。該引擎在執行函數或腳本程序之前,首先要通過調用JavaScript引擎的API函數JS_NewRuntime來初始化一個RunTime,語句為:JSRuntime*rt=JS_NewRuntime(1000000L);
Runtime可以創建一個,也可以創建多個。當不再需要Runtime時,則通過調用其API函數JS_DestroyRunTime來釋放內存資源。
定義上下文句柄的目的在于保護同時存在的腳本執行狀態和程序結果。而定義多少個上下文取決于需要在應用程序中同時使用的腳本數。一個上下文代表應用程序中的一個腳本,JavaScript引擎傳遞上下文信息給運行腳本的線程。可以通過調用JavaScript中的API函數JS_NewContext來創建新的上下文,一個上下文和一個Runtime關聯,語句為:JSContext*cx=JS_NewContext(rt,8192);
釋放上下文的函數為JS_DestroyContext。
首先,通過調用JS_NewObject函數創建全局對象,創建完畢后,則調用JS_InitStandardClasses函數初始化全局對象。
通過創建Runtime,創建上下文,創建全局對象三步之后,就可以把JavaScript引擎嵌入到應用程序中了,這時的應用程序就可以對輸入的JavaScript語言進行編譯運行了。
此時只是完成了JavaScript引擎嵌入的最基本的工作,而如果想使該腳本引擎更加靈活,則需要用到自定義的對象屬性方法。
可以采用將定義了對象的性質和方法的代碼插入到應用程序中的方法,調用引擎來初始化一個新的對象。這種方式適用于實時性較高的工業自動化領域。
創建自定義對象的步驟如下:
1)創建一個JSPropertySpec以及一個JSFunctionSpec數據類型。
2)調用JS_NewObject和JS_ConstructObject函數來實例化該對象。
3)調用JS_DefineFunctions函數來創建對象的方法。
4)調用JS_DefineProperties函數來創建對象的屬性。
JavaScript有自己獨特的數據類型,這些數據類型,有的可以直接應用于C語言,但是有的需要經過轉換才能夠被C語言所識別。可以通過JavaScript引擎提供的API函數將數據類型在JavaScript和C之間進行轉換。這些API函數包括:JS_ValueToString函數、JS_GetStringChars函數、JS_NewStringCopyN函數、STRING_TO_JSVAL函數等。讀者可以自行查找各個函數的用法。
在執行腳本之前,可以調用API函數JS_CompileScript來進行預編譯:
JS_CompileScript(Context(),GlobalObject(),lines,strlen(lines),0,0);
編譯正確,返回JS_TRUE,否則,返回JS_FALSE。編譯正確后,通過調用JS_EvaluateScript方法進行對腳本執行:
JS_EvaluateScript(Context(),GlobalObject(),lines,strlen(lines),0,0,rr);
同樣,如果執行正確,則返回JS_TRUE,否則,返回JS_FALSE。
跟其它的程序運行過程一樣,在程序結束前,需要對腳本引擎進行清理,SpiderMonkey采用的是自動內存管理機制,調用下面兩個函數就可以將垃圾清理干凈:JS_DestroyContext(cx);JS_DestroyRuntime(rt);
通過對組態軟件進行JavaScript引擎的嵌入,使得組態軟件的可擴展性得到了更好的發揮,靈活性更進一步得到了提高。