免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

【分享】用VB寫一個(gè)"腳本"引擎

 quasiceo 2013-11-21

【分享】用VB寫一個(gè)"腳本"引擎 [問題點(diǎn)數(shù):100分]

etherdream
etherdream
etherdream
等級(jí):Blank
結(jié)帖率:90.48%
樓主 發(fā)表于: 2012-07-28 16:54:47
本帖最后由 bcrun 于 2013-07-16 08:39:07 編輯
  提到腳本,腦海里馬上閃過一大堆:Python,Perl,Ruby,PHP,JS,VBS,LUA。。。 不過你有沒聽說過,用經(jīng)典的C++做腳本語言嗎?先不多說,上個(gè)圖。



  或許你在想這一定是瘋了,用世界上最復(fù)雜的語言做腳本,寫的人累不說,腳本引擎先累壞了。各種復(fù)雜的模板庫,要邊解釋邊運(yùn)行,得有多強(qiáng)大的虛擬機(jī)才撐得住。
  好吧,那么我們退一步,不強(qiáng)求解釋執(zhí)行,回歸到原始的編譯后執(zhí)行?!?nbsp;不過那還算腳本嗎?
  
編譯速度

  事實(shí)上如今高性能的腳本都是先編譯后運(yùn)行的,大名鼎鼎的JavaScript V8引擎,號(hào)稱速度最快的LUA-Jit,以及眾所周知的ActionScript。。。預(yù)先編譯不僅能大幅提高運(yùn)行速度,更重要的是能夠提前發(fā)現(xiàn)腳本中顯式的錯(cuò)誤。
  
  但腳本中所謂的編譯,和傳統(tǒng)語言的編譯,還是很大區(qū)別的。腳本的編譯,不過是代碼上的深度優(yōu)化,很快就可以完成。相比復(fù)雜了多的C++來說,似乎是望塵莫及的。提到C++的編譯速度,大家的映象莫過于在VC里按下F5之后,看著輸出框內(nèi)一條一條的“Compiling...”緩緩出現(xiàn)。有時(shí)僅僅測試一個(gè)微小的修改,也要等上好幾秒的時(shí)間。緩慢的編譯速度備受煎熬,以至于簡單的程序往往選擇VB或C#這樣可以快速調(diào)試的語言。
  
  對(duì)于龐大的MFC程序來說,緩慢的編譯是理所當(dāng)然的。但簡單的小程序出現(xiàn)過長的編譯時(shí)間,那一定是頭文件引用的不合理了。事實(shí)上,使用預(yù)處理頭文件的小程序,編譯僅僅是一瞬間的,之后的各種停頓往往是IDE引起的。
  
  那么我們就來測試下,不用IDE,僅用純命令編譯個(gè)C++小程序。我們使用VC6.0的編譯器:CL.exe
  為了確保純凈的編譯環(huán)境,我們把CL.exe必須依賴的文件復(fù)制到新建的文件夾里。對(duì)于VC6的版本,只要有如下5個(gè)文件,就可以完成.cpp到.exe的編譯了。
Visual Basic code?
1
2
3
4
5
CL.exe
  C1XX.DLL
  C2.DLL
  MSPDB60.DLL
Link.exe

  打開cmd,設(shè)置好環(huán)境變量,對(duì)應(yīng)到VC6的頭目錄和庫目錄
Visual Basic code?
1
2
SET INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\VC98\Include
SET LIB=C:\Program Files (x86)\Microsoft Visual Studio\VC98\Lib

  就可以調(diào)用命令編譯了:
cl test.cpp
  一眨眼的工夫,編譯和鏈接完成,生成了test.exe,一切正常。而這還是在沒有使用預(yù)編譯頭的情況下編譯的。



  由此可見,即使語言本身很復(fù)雜,但只要用它寫的代碼不復(fù)雜,編譯還是非常快的。
  仔細(xì)想想也應(yīng)如此。以如今的硬件配置,運(yùn)行98年的編譯器,編譯一個(gè)才幾行代碼的程序,自然是一瞬間的。
  命令行編譯簡單的C++程序是如此的快速,利用這個(gè)優(yōu)勢(shì),繼續(xù)我們的腳本探索。。。

運(yùn)行環(huán)境

  如果要寫一個(gè)生成100個(gè)隨機(jī)序列號(hào)的小程序,你會(huì)使用哪類語言?
  相比傳統(tǒng)語言要先創(chuàng)建一個(gè)工程項(xiàng)目,我們直接在桌面新建個(gè)文本文件就可以寫腳本了。
  雖然用文本編輯器寫代碼沒任何優(yōu)勢(shì),但對(duì)于簡單的程序足矣。之后程序交給其他人使用時(shí),腳本優(yōu)勢(shì)就淋漓盡致的體現(xiàn)出來了:當(dāng)他們自己想簡單修改一些邏輯規(guī)則時(shí),只需用記事本打開就可以,而記事本每臺(tái)電腦上都有。
  相反,傳統(tǒng)語言寫的程序,即使有源代碼,用戶想簡單的修改下也無法生效,還需安裝并配置好相應(yīng)的開發(fā)環(huán)境才行,這對(duì)不熟悉的人來說頗費(fèi)周折。
  
  所以腳本必須足夠簡單 —— 簡單到用戶只管修改和運(yùn)行就可以,其他步驟都交給腳本宿主自動(dòng)完成了。
  
  如果想用C++寫腳本,那么代碼的編譯和鏈接當(dāng)然必須是全自動(dòng)的,這并不復(fù)雜。
  但僅僅依靠CL.exe等幾個(gè)命令還是不夠的,因?yàn)樵谄渌碾娔X上并沒有相應(yīng)的開發(fā)環(huán)境 —— Include和Lib文件夾,因此就無法通過編譯和鏈接了。
  而這些頭文件庫文件,一共多達(dá)上千個(gè),全都帶上則有近百兆!顯然,我們的腳本只用到幾個(gè)基本功能就可以了,那些復(fù)雜的windows頭文件就沒必要了。
  
  事實(shí)上,程序的頭文件只是函數(shù)和結(jié)構(gòu)的定義,僅僅用來給編譯器分析而已,最終并不生成實(shí)際的指令。所以,我們把常用的頭文件,事先生成一個(gè).pch預(yù)編譯頭文件就可以。以后編譯時(shí),將他對(duì)應(yīng)到某個(gè)頭文件就可以了,例如stdafx.h。這樣就無需使用任何頭文件了。即使stdafx.h也不在,編譯仍然能通過,因?yàn)檫@一切都打包在.pch里面了。并且大量的頭文件經(jīng)過事先的分析,編譯時(shí)就無需再編譯它們了,速度大幅提升。
  
  至于Lib文件,里面都是庫函數(shù)的內(nèi)容。除非整個(gè)程序不使用任何C運(yùn)行時(shí)庫,那么我們可以不帶上任何lib,但那樣只能寫最基本的代碼了。對(duì)于一般的簡單腳本程序,只需幾個(gè)必要的lib即可:KERNEL32.LIB,LIBCMT.LIB,LIBCPMT.LIB,OLDNAMES.LIB??偣膊?M多。
  
  我們把這幾個(gè)lib文件以及.pch文件,放在cl.exe同個(gè)目錄下,這樣就無需指定INCLUDE和LIB環(huán)境變量。
  至此,我們有了一個(gè)精簡版的VC6編譯器。通過它們,我們可以不依賴任何環(huán)境,獨(dú)立編譯C++程序了。

實(shí)際運(yùn)行
  現(xiàn)在,我們可以動(dòng)態(tài)產(chǎn)生C++代碼文件,并且自動(dòng)編譯的能力了。但是如何將最終的二進(jìn)制文件運(yùn)行在實(shí)際的腳本宿主里呢?
  顯然,exe程序運(yùn)行在獨(dú)立的進(jìn)程里,數(shù)據(jù)交互只能通過匿名管道,要實(shí)現(xiàn)回調(diào)什么的就非常困難了。
  但若換成dll就可以大顯身手了,不僅運(yùn)行在同一進(jìn)程空間內(nèi),更重要的是dll是可以動(dòng)態(tài)加載卸載的,這一點(diǎn)太符合腳本程序的特性了。當(dāng)我們更新了腳本之后,就可以把先前的dll釋放掉,換上最新的。而這一切都是動(dòng)態(tài)的,無需重啟宿主即可完成!
  而且dll可以導(dǎo)出內(nèi)部的函數(shù),宿主用GetProcAddress()就可以獲得某個(gè)函數(shù)地址即可調(diào)用;至于回調(diào),傳遞一個(gè)宿主的函數(shù)地址給腳本就可以了。只要約定好函數(shù)聲明,雙方都可以用最簡單原始的方法互相調(diào)用,甚至共享同一塊內(nèi)存空間。
  
  為了讓函數(shù)導(dǎo)出更簡潔,本例中定義了個(gè)叫function的宏:
C/C++ code?
1
#define function extern "C" __declspec(dllexport) void

  于是就可以簡單的定義一個(gè)導(dǎo)出函數(shù)了:
C/C++ code?
1
2
3
4
function Test()
{
      // some code here
}

  是不是很有腳本的感覺呢:)
  
語法檢查
  一個(gè)用文本編輯器編寫的代碼,拼寫錯(cuò)誤自然是很難避免的。所以一個(gè)好的腳本引擎,會(huì)在運(yùn)行前做一次全面的語法檢查,事先排除明顯的錯(cuò)誤。
  C++就是將其做到了極限,不僅能查出致命的錯(cuò)誤,甚至不規(guī)范的代碼也會(huì)有警告提示。這是非常值得的,一個(gè)小bug浪費(fèi)的時(shí)間,足夠幾萬次編譯了。
  想要在我們的C++腳本里實(shí)現(xiàn)這個(gè)功能,其實(shí)是非常簡單的。因?yàn)樵谡{(diào)用cl.exe編譯時(shí),要是有編譯錯(cuò)誤就會(huì)反饋出來。我們根據(jù)對(duì)應(yīng)的錯(cuò)誤行號(hào),提示用戶就可以了。


調(diào)試環(huán)境
  一個(gè)強(qiáng)大的腳本引擎,往往帶有調(diào)試器。雖然編譯器能夠預(yù)先排除一些錯(cuò)誤,但是邏輯上的錯(cuò)誤只有在運(yùn)行時(shí)才能出現(xiàn)。
  對(duì)于簡單的腳本程序,這項(xiàng)功能似乎不那么重要。畢竟在調(diào)試狀態(tài)下運(yùn)行,性能會(huì)有所影響。
  在C++腳本里,我們可以通過宏來擴(kuò)展調(diào)試功能,決定是否輸出調(diào)試信息。不過對(duì)于異常錯(cuò)誤,處理就比較講究了。
  由于我們最終運(yùn)行的是二進(jìn)制dll模塊,這和普通的腳本有著天壤之別。dll模塊是和宿主共用一個(gè)進(jìn)程的,所以一旦當(dāng)dll內(nèi)異常觸發(fā)時(shí),整個(gè)進(jìn)程包括宿主一塊進(jìn)入調(diào)試狀態(tài)了(系統(tǒng)裝有開發(fā)環(huán)境的話)。如果錯(cuò)誤過于嚴(yán)重,會(huì)導(dǎo)致整個(gè)進(jìn)程的崩潰。這是個(gè)非常值得注意的地方,也是C++作腳本在權(quán)限上的隱患。所以盡可能少用指針特性,使用更安全的代碼,讓代碼風(fēng)險(xiǎn)降到最少。
  對(duì)于致命的錯(cuò)誤,宿主記錄下dump文件是非常重要的,方便調(diào)試。
  
  不過出于簡單,本例的宿主是用VB寫的,也就無法在調(diào)用前使用__try{}進(jìn)行SEH捕捉。如果宿主也是C++實(shí)現(xiàn)的話,則盡可能捕捉dll內(nèi)的異常。
 
開發(fā)環(huán)境
  有別于腳本語言,C++本身就是用于大型程序的開發(fā),所以開發(fā)環(huán)境是非常完善的。
  但作為一個(gè)腳本,往往都是單個(gè)的文本文件,而不是一個(gè)項(xiàng)目組。任何版本的VC編輯單個(gè)cpp文件,和編輯純文本文件幾乎沒有區(qū)別。因此我們事先得建立一個(gè)模板項(xiàng)目,將需要編輯的cpp移到此項(xiàng)目內(nèi)開發(fā),這樣才會(huì)有下拉框智能提示等功能。
  不過既然選擇它作為腳本來使用,那就應(yīng)該用來處理一些簡單的,經(jīng)常變更的邏輯事務(wù)。對(duì)于復(fù)雜的腳本程序,還不如直接寫在宿主里面了。
  
  事實(shí)上,“程序”和“腳本”之間從沒一條固定的界限。用純粹的程序也可以寫一個(gè)復(fù)雜的游戲故事情節(jié),用純粹的腳本也可以開發(fā)一個(gè)大型項(xiàng)目。只不過太過死板,或太過靈活,都會(huì)增加額外的工作量。
 
總結(jié)
  與其稱之為C++腳本,倒不如說是插件———可以根據(jù)需求,動(dòng)態(tài)產(chǎn)生指令的插件。
  雖然可以玩轉(zhuǎn)出一些腳本的特征,然而C++終究是門嚴(yán)格的語言。相比腳本的靈活性,C++固然更為嚴(yán)謹(jǐn)和死板。當(dāng)然,憑借強(qiáng)大的宏、模版、運(yùn)算符重載,我們可以充分?jǐn)U展,為腳本提供豐富多樣的特征和語法糖。
  當(dāng)然,它的優(yōu)勢(shì)也是顯而易見的:性能超高,交互簡單。
  事實(shí)上,不僅僅是C++,任何一門高級(jí)語言都可以當(dāng)“腳本”使用,只要調(diào)用它們的編譯器即可。如果喜歡C#,或者Java風(fēng)格,只需稍作修改就可以。
  
  為了簡單演示,本例使用VB寫了個(gè)簡單的宿主程序,包括基本的編譯,鏈接,加載,語法檢查功能。
  宿主提供了一個(gè)叫“Print”的接口,可以輸出字符串。要實(shí)現(xiàn)更多接口和擴(kuò)展功能,修改cl文件夾內(nèi)的T.h即可。
  
  源碼可以在這里下載:http://files.cnblogs.com/index-html/CppScript.rar
  
  其中有一個(gè)DLLTmpl的工程,沒有任何用處,僅僅為了生成一個(gè).pch預(yù)編譯頭文件而已。如果想在腳本里使用更多的頭文件,就得在StdAfx.h內(nèi)添加。編譯之后的release/MyDll.pch復(fù)制到cl文件夾,覆蓋原有的即可。
分享到:
回復(fù)次數(shù):8
JiLuoXingRen
JiLuoXingRen
幾羅星人
等級(jí):Blank
#1 得分:0 回復(fù)于: 2012-07-28 16:57:35
強(qiáng)人~~,收源碼+接分~~
caozhy
caozhy 版主
caozhy
等級(jí):Blank
5
4
更多勛章
#2 得分:0 回復(fù)于: 2012-07-29 08:45:25
暈,這不是“腳本”,不過是實(shí)現(xiàn)了一個(gè)簡陋的IDE。
yiguangqiang88
yiguangqiang88
神馬被哪個(gè)妞占用了呢
等級(jí):Blank
#3 得分:0 回復(fù)于: 2012-07-29 08:48:07
話說樓主很強(qiáng)悍的樣子……
wwc7654321
wwc7654321
wwc7654321
等級(jí):Blank
#6 得分:0 回復(fù)于: 2013-07-15 17:26:32
額啊,的確不算是腳本,不過還是很有啟發(fā)意義的
問題是“宿主”和腳本之間的交互、“腳本”的動(dòng)態(tài)功能以及安全性的考慮了,無疑這“腳本”對(duì)“宿主”穩(wěn)定和安全性威脅挺大的



曾經(jīng)想過這損招,不過因?yàn)椴欢幾g細(xì)節(jié)放棄了
SupermanKing
SupermanKing
人類
等級(jí):Blank
#8 得分:0 回復(fù)于: 2013-07-15 22:33:27
不知道這東西的實(shí)際意義在哪?學(xué)習(xí)?實(shí)用?參考?
要用現(xiàn)成的東西運(yùn)行腳本,有現(xiàn)成的js,vbs解釋器,想玩得復(fù)雜點(diǎn)可以用java引擎。
要用現(xiàn)成的編譯器,可以用 gcc for win,整套體系都非常完備。當(dāng)然,只要有需要,VB、VC...的編譯環(huán)境都可拆分提出來實(shí)現(xiàn)拼接代碼實(shí)現(xiàn)編譯。
如果想用現(xiàn)成的IDE,可以改裝eclipse,當(dāng)然自己做個(gè)代碼加亮的ide也不難。
如果只是想了解語言分析技術(shù),網(wǎng)上一堆的這類代碼,分析c語言的是最多的,因?yàn)檫@個(gè)最簡單,應(yīng)為c語言不像basic格式可以那么混亂,但即使是basic語言的分析也有很多例子和范例,這么說吧,要做這種語言分析,弄basic語言的難度要比c語言大。
如果是為了了解編譯原理,那么那些編譯器的源代碼也是滿天飛,gcc就是個(gè)開源的,還有n多C語言、basic的編譯器源碼,包括從操作系統(tǒng)解析bas腳本的源碼都還有,MikeOS就是個(gè)很好的例子,包括整個(gè)操作系統(tǒng)的源代碼以及他是如何解析明碼的basic程序的過程,基本上可以說是系統(tǒng)級(jí)解釋過程。
所以我才搞不清楚這東西的實(shí)際意義在哪?

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多