前段時間有個項目,因為其中需要使用腳本做模板數據的計算,因此讓我對腳本引擎產生了興趣,於是上網到處尋找資料,於是找到了《龍書》、CodeDom。於是又找了半天,找不到開源的腳本引擎源碼,腦袋一熱,干脆自己寫一個,於是就有了這個用純c#(非CodeDom)編寫的腳本引擎。編寫過程中收獲良多,目前還不是很完善,效率也不高,僅供學習用,后面會上傳源代碼。
下面說明一下:語法參考Javascript,基本的javascript語法都已實現,但是有些內建對象沒實現,例如 Date,數據類型支持 數值,字符串(考慮到在代碼中執行代碼,所以字符串的定義用 '字符串' 而非 "字符串"),對象,布爾值,數組。語法方面基本參考Javascript就行了。在編寫這個東西的時候順帶學習了下CodeDom(感嘆枉費我弄C#也4年多了,現在才知道這東西,看來水還是太深了),在考慮語法分析的時候就參考了CodeDom的對象結構,如下:
命名空間定義:
ScriptEngin.Code :詞法分析器
ScriptEngin.CodeDom:編譯后的解釋模型,就是上圖的結構(都說了是參考CodeDom)
ScriptEngin.Exceptions:自定義的異常類
ScriptEngin.Parser:語法分析器
ScriptEngin.RunTime:運行時解釋執行器
ScriptEngin.RunTimeType:處理c#對象和腳本對象的映射(還未完善)
下面貼一段調用代碼:
1 string code1 = @" 2 3 var str='字符串申明'; 4 var obj={name:'對象申明',num:100,fun:function(a,b){return a+b;}}; 5 var arr=['這個是數組','123']; 6 var arr2=[['多維數組','111'],['222','223']]; 7 8 function testClass() 9 { 10 this.name='成員屬性'; 11 this.MemFun=function(){ 12 return '成員函數'; 13 } 14 } 15 var newObj=new testClass(); 16 var nameMem=newObj.name; 17 18 19 function testFun(a,v) 20 { 21 count=0; 22 for(i=0;i<v;i++) 23 { 24 count+=a; 25 } 26 return count; 27 } 28 29 30 "; 31 Script scr = new Script(); 32 //設置傳入腳本的參數,這里傳入的參數在腳本中可做變量用 33 scr.Paramers.Set("testbool", true); 34 scr.Paramers.Set("testString", "abc"); 35 36 //編譯並運行全局代碼 37 scr.Run(code1); 38 39 //獲取運行時變量,PS:暫時只能返回數值、字符串、Boolean值 40 object varValue = scr.Paramers.Get("str"); 41 42 //調用指定函數,能返回的數據同上 43 object value= scr.Call("testFun",300,200);
目前未做大量測試,可能會存在些許Bug,如果大家發現了請告訴我,謝謝。
(第一次寫博,大家見笑了)
呵呵,感謝大家的支持!
關於有人問這個東西在實際項目中的用處這個問題,這個嘛其實還是很多的,例如在項目中有些地方是需要用戶自定義的,比如報表模板,界面模板等等。當用戶需要做一些簡單計算的時候,腳本引擎的作用就可以體現出來了。總不可能當用戶需要在模板中做計算的時候,你來給他修改代碼然后重新發布吧(這里我說的不是很清楚)。另外,作為一個程序員,多了解一些編譯原理的東西總沒壞處的。
呵呵,如果對腳本引擎和編譯原理感興趣的人多的話,我也許會寫一系列的博文,用最淺顯的語言給你解釋原理,用較簡單的方法讓你知道如何寫一個腳本引擎。其實看了《龍書》快4個多月的時間了,其中的很多東西也還不是很明白,最快樂的就是某天的某個時刻忽然領悟其中某部分知識的時候,那種好心情能讓自己高興一整天,恨不得馬上坐下寫出代碼來驗證自己的想法。
希望和大家一起學習,一起研究,我們是程序員,是計算機的靈魂工程師~~~呵呵