基于仿匯編指令的自動(dòng)編程_第1頁
基于仿匯編指令的自動(dòng)編程_第2頁
基于仿匯編指令的自動(dòng)編程_第3頁
基于仿匯編指令的自動(dòng)編程_第4頁
基于仿匯編指令的自動(dòng)編程_第5頁
已閱讀5頁,還剩20頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

基于仿匯編指令的自動(dòng)編程實(shí)驗(yàn)內(nèi)容:運(yùn)用自編程算法,對(duì)基本匯編指令進(jìn)行排列枚舉,從而構(gòu)建出能夠完成用戶指定任務(wù)的復(fù)雜指令。實(shí)驗(yàn)編號(hào):21實(shí)驗(yàn)成功日期:2016年11月12日理論要點(diǎn):自編程算法、帶參數(shù)自編程、層次性自編程、高層指令優(yōu)先搜索法、異進(jìn)制枚舉法編程語言:C++編程環(huán)境:VisualStudio2015回顧上次實(shí)驗(yàn):/p/4839392184上一次,我運(yùn)用自編程算法,在計(jì)算機(jī)上實(shí)現(xiàn)了運(yùn)用加、減、乘、除以及賦值這5種運(yùn)算,生成①“根據(jù)v0、a、t求出v”(v=v0+a*t)、②“根據(jù)v0、v、t求出x”(x=(v0+v)*t/2)以及③“根據(jù)v0、a、t求出x”(x=v0*t+a*t^2/2)的物理運(yùn)算過程。程序在破解①②兩個(gè)公式的時(shí)候,沒有運(yùn)用任何技巧,完全靠盲目地試錯(cuò);而最后程序在破解第3個(gè)公式的時(shí)候,它借助了先前的學(xué)習(xí)結(jié)果,先運(yùn)用①式——根據(jù)v0、a、t求出v,再運(yùn)用②式——根據(jù)v0、v、t求出x,得到x的值。如果程序采用盲目試錯(cuò)法,也可以得出x=v0*t+a*t^2/2的結(jié)果,但是這最多需要29^6+29^5+29^4+29^3+29^2+29=616067010次嘗試,將會(huì)導(dǎo)致程序的不收斂。為了避免這種情況,我采用了“層次性自編程”,讓計(jì)算機(jī)對(duì)高層指令(由底層指令組合出的復(fù)雜指令,比如剛才的①②,它們都是“自編程序”的結(jié)果)進(jìn)行組合,由于高層指令在數(shù)量上遠(yuǎn)少于底層指令,程序的嘗試次數(shù)將會(huì)大大減少,這樣有利于自編程過程的收斂。紀(jì)錄片《RUIAIJUN人工智能理論:自編程學(xué)習(xí)算法與反射算法》截圖(觀看鏈接:/p/4760009643)當(dāng)然,如果自編程系統(tǒng)只對(duì)高層指令進(jìn)行排列組合,那么將會(huì)出現(xiàn)漏解的情況——一些底層的指令也可以構(gòu)成能夠完成任務(wù)的復(fù)雜操作,而程序如果不枚舉底層指令,將不可能發(fā)現(xiàn)這個(gè)結(jié)果。針對(duì)這個(gè)問題,我提出了一個(gè)解決方案,讓程序優(yōu)先枚舉高層指令,我將這種方法命名為高層指令優(yōu)先搜索法。下面我將舉一個(gè)具體例子來說明我的做法:假設(shè)有五個(gè)匯編基本指令:mov(賦值)、add(加)、sub(減)、and(與)、or(或),以及一個(gè)字符串拼接操作(把兩個(gè)字符拼接在一起,存放在一個(gè)十六位變量中,高八位存放第一個(gè)字符,低八位存放第二個(gè)字符),以及一個(gè)“字符轉(zhuǎn)大寫”操作。定義兩個(gè)全局變量char1=’A’,char2=’I’;和一個(gè)十六位變量str,內(nèi)容為空。要求程序運(yùn)用這些操作,讓str變量的高八位等于’a’,第八位等于’i’——也就是說把char1、char2轉(zhuǎn)為小寫,然后把它們分別放進(jìn)str變量的高八位和第八位。我給程序加的限制是:最多只允許三步操作。步驟數(shù)目為3,單個(gè)步驟可以是一個(gè)基本匯編指令,也可以是(由基本匯編指令構(gòu)成的)復(fù)雜指令,我們用1表示復(fù)雜指令,用0表示基本匯編指令,就有如下八種情況:000、001、010、011、100、101、110、111我前面提到:復(fù)雜指令的數(shù)目比基本指令少。為了提高程序的收斂性,需要優(yōu)先嘗試復(fù)雜指令,那么按照“基本匯編指令的數(shù)目多少”(數(shù)碼中含有”0”的個(gè)數(shù)),我們對(duì)剛才的八個(gè)數(shù)碼按照”0”的個(gè)數(shù)從少到多的順序進(jìn)行排序:111(不含零)101(1個(gè)零)110011100(2個(gè)零)001010000(3個(gè)零)就以“001”為例,第三步操作采用的是復(fù)雜指令——程序?qū)?huì)依次嘗試“拼接字符”和“字符轉(zhuǎn)大寫”操作。第一、二步操作采用的是基本匯編指令,程序會(huì)依次嘗試mov、add、sub、and、or操作。最后成功地使得str的高八位值為’a’,第八位值為’i’。得出如下結(jié)果:orchar1,32orchar2,32字符拼接str,char1,char2(科普:對(duì)一個(gè)字符做or32的位運(yùn)算,可使它變?yōu)樾憣?duì)一個(gè)字符做and223的位運(yùn)算,可使它變?yōu)榇髮懀﹦偛耪f到枚舉,枚舉包括兩部分——第一是對(duì)指令的枚舉,第二是對(duì)指令參數(shù)的枚舉。對(duì)參數(shù)的枚舉有一定的限制,比如以下指令是合法的:addAH,56(AH寄存器的值增加56)addAH,BH(AH寄存器加上BH寄存器的值)addAH,var1(AH寄存器加上變量var1的值)addvar1,34(變量var1加上34)addvar1,AH(變量var1加上寄存器AH的值)而這個(gè)指令是不合法的:addvar1,var2(變量var1加上var2的值)根據(jù)匯編語言常識(shí),不允許在兩個(gè)內(nèi)存變量之間直接傳值,所以對(duì)兩個(gè)內(nèi)存變量之間直接進(jìn)行加減運(yùn)算或者位運(yùn)算也是不允許的。所以為了避免出現(xiàn)這樣的情況,自編程系統(tǒng)在枚舉的過程中,不允許不合法的參數(shù)(如:mov、add、sub、and、or指令的兩個(gè)參數(shù)都為內(nèi)存操作數(shù)),這樣做有利于減少嘗試次數(shù),增加了自編程系統(tǒng)的收斂性。除了“不允許不合法的參數(shù)”,我還有一個(gè)方法可以增加自編程系統(tǒng)的收斂性,那就是——參數(shù)不可以是與當(dāng)前問題無關(guān)的變量。這個(gè)方法已經(jīng)在上一個(gè)演示程序(破解物理公式)中得到了應(yīng)用,我就不多解釋了。本程序中用到了mov、add、sub、and、or這五個(gè)基本匯編指令,它們都只接受兩個(gè)參數(shù),其中只有第一個(gè)參數(shù)的值會(huì)被改變。而且它們的規(guī)則也是一致的:不允許兩個(gè)參數(shù)都是變量。但是,用戶自定義的指令,參數(shù)個(gè)數(shù)是任意的,參數(shù)的類型也有限制。我定義一個(gè)指令比如“轉(zhuǎn)大寫”,它只接受一個(gè)參數(shù),這個(gè)參數(shù)必須是八位變量(一個(gè)字符占8位);例如我定義一個(gè)指令“變量傳值”,它接受兩個(gè)內(nèi)存變量作為參數(shù)。簡單地說,用戶自定義指令就相當(dāng)于高級(jí)語言中的函數(shù)(只不過我這里沒有返回值),參數(shù)類型和個(gè)數(shù)都是程序員自定義的。那么,自編程系統(tǒng)在枚舉參數(shù)的過程中,也要考慮兩點(diǎn):①所選的命令接受多少個(gè)參數(shù);②每個(gè)參數(shù)的類型是什么。(程序需要把可以作為參數(shù)的變量全部記錄在一個(gè)數(shù)組中)如圖所示,自編程系統(tǒng)內(nèi)存儲(chǔ)了五個(gè)指令:賦值(參數(shù):2個(gè)八位變量)、轉(zhuǎn)小寫、轉(zhuǎn)大寫、加(參數(shù):2個(gè)八位變量)、字符拼接(參數(shù):十六位變量、八位變量、八位變量)、轉(zhuǎn)小寫并連接(參數(shù):十六位變量、八位變量、八位變量)我用一個(gè)二維矩陣來做到這種枚舉。矩陣的行表示指令參數(shù)個(gè)數(shù),矩陣的列里面存儲(chǔ)所有可以用的變量。假如:要求程序?qū)ふ乙粋€(gè)操作,使得最后word2變量的高八位是’b’,低八位是’d’。現(xiàn)在程序用一個(gè)二維矩陣存儲(chǔ)“轉(zhuǎn)小寫并拼接”所能夠接受的參數(shù),如下圖所示:對(duì)于“轉(zhuǎn)小寫并拼接”這個(gè)指令而言,它的第一個(gè)參數(shù)是一個(gè)十六位變量,用于存儲(chǔ)含有兩個(gè)字符的字符串,由于自編程系統(tǒng)內(nèi)只有word1、word2兩個(gè)十六位變量,故第一行(參數(shù)1)填入兩個(gè)變量word1、word2以供枚舉。而參數(shù)2和參數(shù)3都只能是八位變量,故填入byte1、byte2、byte3、byte4、byte5。其實(shí)用戶可以通過手動(dòng)地排除一些無關(guān)變量,來減少程序的嘗試次數(shù)。將參數(shù)枚舉與指令枚舉結(jié)合起來。程序需要再建立一個(gè)二維矩陣,用于記錄每個(gè)指令可以接受多少個(gè)參數(shù),每個(gè)參數(shù)有多少種可能變量。如下表所示,例如最左上角的格子里面的“5”表示第一個(gè)指令的第一個(gè)參數(shù),有5種不同的選擇。由此可見,在這個(gè)二維數(shù)組中,行下標(biāo)表示第幾個(gè)指令,列下標(biāo)表示第幾個(gè)參數(shù),數(shù)組單元里面的整數(shù)表示有多少個(gè)變量可選。程序在生成了這個(gè)矩陣之后,需要針對(duì)每一個(gè)指令專門再生成一個(gè)二維矩陣(就是我最開始提到的那個(gè)矩陣)。例如對(duì)于第六個(gè)指令“轉(zhuǎn)小寫并拼接”,它接受三個(gè)參數(shù),所以新生成的矩陣就有3列(很明顯,原來矩陣的行下標(biāo),在新矩陣?yán)锩媸橇邢聵?biāo))。兩個(gè)矩陣對(duì)比如下圖所示:現(xiàn)在,我將講解最關(guān)鍵的內(nèi)容——以第二個(gè)矩陣為參考信息,用異進(jìn)制枚舉法生成所有可能的指令參數(shù)組合。就以“轉(zhuǎn)小寫并拼接”為例,參數(shù)1接受2個(gè)變量(中的任意一個(gè)),參數(shù)2接受5個(gè)變量,參數(shù)3也接受5個(gè)變量。那么我們給word1、word2編號(hào)為0、1,給byte1——byte5編號(hào)為0——4。總共有以下幾種可能排列:參數(shù)1參數(shù)2參數(shù)3000001002003004010011012013014020021022023024030031032033034040041042043044100101102103104110111112113114120121122123124130131132133134140141142143144(達(dá)到最大值,不允許再進(jìn)位,因?yàn)橹噶畹膮?shù)個(gè)數(shù)只有3個(gè))大家可以發(fā)現(xiàn),第一位逢二進(jìn)一,第二位和第三位逢五進(jìn)一,“255”正好與參數(shù)1、參數(shù)2、參數(shù)3可以接受的變量的個(gè)數(shù)相一致。由于每一位的進(jìn)制是不一樣的,所以我把這種做法命名為“異進(jìn)制枚舉法”。下面再講講“異進(jìn)制枚舉”的一些細(xì)節(jié)問題。自編程系統(tǒng)首先需要統(tǒng)計(jì)每個(gè)位上的進(jìn)制(基數(shù),radix),然后選取出其中最大的一個(gè)——在此例中,第二、三位是五進(jìn)制,所以最大基數(shù)為5。然后生成[0,5^3)之間的整數(shù),逢五進(jìn)一,把每個(gè)位的值存儲(chǔ)在一個(gè)數(shù)組當(dāng)中,這樣就變成一個(gè)五進(jìn)制數(shù)。由于第一位是二進(jìn)制的,只能取0或1,所以在125個(gè)五進(jìn)制整數(shù)中排除掉一部分——也就是把第一位上的數(shù)值大于1的全部排除掉,這樣便得到了全部有效結(jié)果。使用方法:運(yùn)行程序,界面上會(huì)顯示出所有寄存器及變量的初始值。由于本程序涉及對(duì)字符的操作,所以我規(guī)定,如果某個(gè)八位變量的值在65——90或者97——122之間,程序就把它當(dāng)作字符變量看待,同時(shí)顯示其字符內(nèi)容,以及其ASCII碼值。如圖所示,byte1、byte2、byte3、byte4的右邊顯示了整數(shù)值和字符內(nèi)容。現(xiàn)在開始做第一個(gè)實(shí)驗(yàn)——在兩變量之間進(jìn)行傳值。我們知道,匯編語言中mov指令是不可以對(duì)兩個(gè)變量直接傳值的,即“變量A=變量B”這樣的賦值操作在匯編語言里面是不可以直接實(shí)現(xiàn)的,必須得先把變量B的內(nèi)容放在某個(gè)寄存器內(nèi),再把寄存器的數(shù)值傳給變量A。我們現(xiàn)在要做的就是,讓程序自己尋找指令,最終使得變量byte5的值等于變量byte3的值。輸入目標(biāo)變量的名字:byte5。輸入目標(biāo)值為變量byte3的值——98。最大、最少步驟數(shù)都設(shè)定為2步。常數(shù)枚舉填N。然后,程序要求“輸入與之相關(guān)的變量或寄存器的名字”,這就是說:只有用戶輸入的變量或寄存器會(huì)被用作參數(shù),這樣做將會(huì)排除掉很多無關(guān)的方案,提高程序的收斂性。我們需要程序把byte3的值傳遞給byte5,所以byte3肯定是相關(guān)變量,必須輸入byte3否則程序?qū)⒄也坏秸_的結(jié)果。由于變量間的傳值需要借用一個(gè)寄存器,所以我們隨便輸入一個(gè)八位寄存器比如AH(必須要大寫!?。?。由于byte3是目標(biāo)變量,所以可以輸也可以不輸,反正自編程系統(tǒng)會(huì)自動(dòng)把它加入“相關(guān)變量/寄存器”的集合當(dāng)中。輸入“XX”并回車,程序開始嘗試枚舉。。。一瞬間,程序提示“得到3種方案,為避免偶然性,你需要修改相關(guān)變量的值從而對(duì)方案進(jìn)行檢驗(yàn)”。輸入檢驗(yàn)次數(shù):1次,我們把byte3的原值修改為100,byte5的原值修改為90,把AH寄存器的原值修改為35(注意:AH寄存器值為0時(shí),addAH,byte3、orAH,byte3和movAH,byte3的執(zhí)行效果是一樣的,都可以使AH寄存器的值跟byte3一樣,這就是為什么寄存器值為0的時(shí)候會(huì)產(chǎn)生一大堆結(jié)果)。程序最后得出結(jié)果如下:movahbyte3movbyte5ah輸入“Y”保存當(dāng)前枚舉嘗試結(jié)果,取名為“賦值”。接受的參數(shù)就填:byte5,byte3(注意:以半角逗號(hào)分隔)。參數(shù)的順序最好不要顛倒,把等號(hào)左邊的參數(shù)放在第一個(gè)。程序清屏,并在指令欄下面顯示了剛剛保存的結(jié)果:賦值接受2個(gè)參數(shù)。由于剛才自編程系統(tǒng)通過枚舉試錯(cuò),自己構(gòu)建了一個(gè)新的操作“賦值”,用于把一個(gè)變量直接賦給另一個(gè)變量?,F(xiàn)在自編程系統(tǒng)里面不僅僅有mov、add、sub等基本匯編指令,還有復(fù)雜指令——也就是剛才得到的“賦值”操作。程序詢問用戶,接下來要枚舉的指令是基本指令還是復(fù)雜指令,我們接下來要做的事情是把一個(gè)小寫字母轉(zhuǎn)為大寫字母,這不需要用到兩變量間的賦值,也就是說只需對(duì)基本指令進(jìn)行枚舉就可以了,所以選1。當(dāng)然如果你輸入2,也不會(huì)有大問題,只不過程序會(huì)優(yōu)先考慮復(fù)雜指令,這樣就反倒增加了試錯(cuò)的次數(shù)。我們需要把目標(biāo)變量byte5的值由大寫的Z變?yōu)樾懙膠,大寫Z的ASCII碼是90,小寫z的ASCII碼是122。大家不用急著上網(wǎng)查ASCII碼,我壓縮包里面給了大家一個(gè)字符和ASCII雙向轉(zhuǎn)換的程序,大家可以用它來查詢。最大步驟數(shù)和最少步驟數(shù)都設(shè)置為1。程序詢問是否允許常數(shù)枚舉,這個(gè)地方要填寫:Y。因?yàn)檫@里需要用到對(duì)具體常數(shù)值的位運(yùn)算。(orbyte5,32).由于此程序除了要用到目標(biāo)變量byte5以外,再也不需要用到其他任何變量、寄存器了。所以“相關(guān)變量/寄存器”那欄直接填XX。接下來程序所做的事情就是用mov、add、sub、and、or指令一個(gè)個(gè)試過去,當(dāng)然不僅僅要改變指令,還要改變常數(shù)參數(shù)的值,具體枚舉過程如下:movbyte5,1movbyte5,2movbyte5,3。。。。。。movbyte5,254movbyte5,255andbyte5,1andbyte5,2andbyte5,3。。。。。。andbyte5,254andbyte5,255orbyte5,1orbyte5,2orbyte5,3。。。。。。orbyte5,254orbyte5,255。。。。。。。。。。。。經(jīng)過第一次篩選,程序得到了32種方案,這說明很多不合理的方法混雜在里面。于是我們改變byte5的目標(biāo)值,設(shè)定為121即大寫字母Y,原值設(shè)定為89即小寫字母y。(大寫字母的ASCII碼等于小寫字母ASCII碼加上32).經(jīng)過這次篩選,方案的數(shù)量由32銳減至9。接下來我們?cè)賮砜匆环N情況:如果一個(gè)字母本身就已經(jīng)是小寫字母了,如果再把對(duì)它進(jìn)行“加32”操作,那么得到的結(jié)果將不再是英文字母。所以現(xiàn)在我們把byte5的目標(biāo)值和初始值都設(shè)定為119即字母w,要求程序在執(zhí)行方案以后,變量里面的內(nèi)容仍然是小寫字母w。經(jīng)過這一輪篩選,只剩下4個(gè)方案,然后我們對(duì)四個(gè)方案進(jìn)行挑選,選出合適的指令“orbyte5,32”,保存之并命名為“轉(zhuǎn)小寫”。接下來,我們讓程序構(gòu)建一種能將任意字母轉(zhuǎn)化為大寫形式的復(fù)雜操作,輸入輸出如下:==========================================枚舉基本指令請(qǐng)輸1,枚舉復(fù)雜指令請(qǐng)輸2:1請(qǐng)輸入目標(biāo)變量的名字:byte3請(qǐng)輸入目標(biāo)值:68請(qǐng)輸入最少步驟數(shù):1請(qǐng)輸入最大步驟數(shù):1是否允許常數(shù)枚舉?(Y/N)Y請(qǐng)輸入與之相關(guān)的變量或寄存器的名字,輸入XX結(jié)束:XX得到34種方案,為避免偶然性,你需要修改相關(guān)變量的值從而對(duì)方案進(jìn)請(qǐng)輸入檢驗(yàn)次數(shù):2請(qǐng)輸入目標(biāo)變量的最終值:67byte3原值為:100,現(xiàn)修改為:99開始進(jìn)行第1次篩選......第1次篩選完畢,剩余9個(gè)方案輸入Y可進(jìn)行篩選,輸入N退出篩選過程:Y請(qǐng)輸入目標(biāo)變量的最終值:66byte3原值為:99,現(xiàn)修改為:66開始進(jìn)行第2次篩選......第2次篩選完畢,剩余8個(gè)方案找到8種方案,輸入Y可將方案保存為指令,輸入N放棄當(dāng)前方案,輸入andbyte371是否保存?(Y/N/X)Nandbyte379是否保存?(Y/N/X)Nandbyte387是否保存?(Y/N/X)Nandbyte395是否保存?(Y/N/X)Nandbyte3199是否保存?(Y/N/X)Nandbyte3207是否保存?(Y/N/X)Nandbyte3215是否保存?(Y/N/X)Nandbyte3223是否保存?(Y/N/X)Y為當(dāng)前方案取名:轉(zhuǎn)大寫輸入指令中出現(xiàn)的所有參數(shù)(不要重復(fù)),以半角逗號(hào)分隔:byte3==========================================然后再構(gòu)建“能夠?qū)蓚€(gè)變量直接進(jìn)行加法運(yùn)算”的操作,輸入輸出如圖所示:現(xiàn)在,我們需要構(gòu)建的指令有3個(gè)不同類型的參數(shù)。我們的目標(biāo)是把兩個(gè)字符的內(nèi)容放進(jìn)一個(gè)十六位變量當(dāng)中,變量的高位存放第一個(gè)字符,低位存放第二個(gè)字符。比如byte3=’B’,byte4=’D’,將byte3、byte4的內(nèi)容放進(jìn)十六位變量word1當(dāng)中,word1的值會(huì)變成66*256+68=16964。大家不要自己去算,為了大家的方便,我已經(jīng)編寫了一個(gè)工具專門用來計(jì)算字符、字符串的ASCII碼值,如圖:最大、最少步驟數(shù)都設(shè)定為3。此程序要用到八位寄存器AH、AL來暫存字符串的內(nèi)容,還需要用十六位寄存器AX來存儲(chǔ)字符串內(nèi)容。程序經(jīng)過一段時(shí)間的嘗試,得到了兩個(gè)方案,接下來的輸入輸出如下,大家只要按照我給的步驟去操作就可以了。===================================得到2種方案,為避免偶然性,你需要修改相關(guān)變量的值從而對(duì)方案進(jìn)行檢驗(yàn)。請(qǐng)輸入檢驗(yàn)次數(shù):0找到2種方案,輸入Y可將方案保存為指令,輸入N放棄當(dāng)前方案,輸入X可跳過剩余內(nèi)容。movahbyte3movalbyte4movword1ax是否保存?(Y/N/X)Y為當(dāng)前方案取名:字符拼接輸入指令中出現(xiàn)的所有參數(shù)(不要重復(fù)),以半角逗號(hào)分隔:word1,byte3,byte4movalbyte4movahbyte3movword1ax是否保存?(Y/N/X)N===================================現(xiàn)在,將要進(jìn)行的是最后一次實(shí)驗(yàn):我們需要程序構(gòu)建這樣一種操作:它能夠?qū)蓚€(gè)變量中存儲(chǔ)的英文字符轉(zhuǎn)化為小寫形式,拼接成字符串(存放于一個(gè)16位變量中)。我們還是以word2、byte3、byte4作為操作的對(duì)象,最后word2中存儲(chǔ)的字符串為”bd”,對(duì)應(yīng)的數(shù)值為98*256+100=25188。返回主程序,程序詢問用戶要枚舉基本指令還是復(fù)雜指令,此處填2。目標(biāo)變量為word2,目標(biāo)值填入25188,表示”bd”。最大、最少步驟數(shù)都填3,相關(guān)的變量、寄存器這一欄輸入byte3按回車,輸入byte4按回車,再輸入XX結(jié)束。程序提示如下信息:對(duì)于基本指令,總共有0種排列對(duì)于復(fù)雜指令,總共有10種排列賦值byte3byte4賦值byte4byte3轉(zhuǎn)小寫byte3轉(zhuǎn)小寫byte4轉(zhuǎn)大寫byte3轉(zhuǎn)大寫byte4加byte3byte4加byte4byte3字符拼接word2byte3byte4字符拼接word2byte4byte3請(qǐng)按任意鍵繼續(xù)...我來解釋一下這段信息的含義。對(duì)于基本指令如mov、add而言,參數(shù)不可能是兩個(gè)變量,所以枚舉出的結(jié)果數(shù)目為0。對(duì)于復(fù)雜指令,則要分類討論。“賦值”指令接受兩個(gè)八位變量,所以參數(shù)可以是byte3、byte4而不會(huì)是word2,由于變量位置呼喚后得到的效果是不一樣的,所以參數(shù)可以填{byte3,byte4}或者{byte4,byte3}。其余指令類似,不再贅述。按下任意鍵后,程序得到兩種方法,這些都是合理的方案。接下來請(qǐng)大家按照如下內(nèi)容輸入命令(我們需要保存結(jié)果并且修改word2的值,不用多問為什么,照樣子打字就可以了)===========================================================得到2種方案,為避免偶然性,你需要修改相關(guān)變量的值從而對(duì)方案進(jìn)行檢驗(yàn)。請(qǐng)輸入檢驗(yàn)次數(shù):1請(qǐng)輸入目標(biāo)變量的最終值:25188byte3原值為:66,現(xiàn)修改為:66byte4原值為:68,現(xiàn)修改為:68word2原值為:19755,現(xiàn)修改為:25188找到2種方案,輸入Y可將方案保存為指令,輸入N放棄當(dāng)前方案,輸入X可跳過剩余內(nèi)容。轉(zhuǎn)小寫byte3轉(zhuǎn)小寫byte4字符拼接word2byte3byte4是否保存?(Y/N/X)Y為當(dāng)前方案取名:轉(zhuǎn)小寫并拼接輸入指令中出現(xiàn)的所有參數(shù)(不要重復(fù)),以半角逗號(hào)分隔:word2,byte3,byte4轉(zhuǎn)小寫byte4轉(zhuǎn)小寫byte3字符拼接word2byte3byte4是否保存?(Y/N/X)===========================================================保存命令后,程序界面如下圖所示。可以看到指令欄里面多了一個(gè)“轉(zhuǎn)小寫并拼接指令”,它接受3個(gè)參數(shù)。Word2的值變成了”bd”,有的人可能會(huì)懷疑:word2的值之所以改變?yōu)椤眀d”,是因?yàn)閯偛盼覀冊(cè)跈z驗(yàn)的時(shí)候強(qiáng)制為word2設(shè)定了初值25188。注意,其實(shí)自編程系統(tǒng)第一次在嘗試組合指令的時(shí)候,已經(jīng)成功地用①轉(zhuǎn)小寫byte3;②轉(zhuǎn)小寫byte4;③字符拼接word2byte3byte4這三步操作,成功地將word2的值變成了25188(字符串“bd”)。但由于我們的自編程系統(tǒng)有一個(gè)“變量自動(dòng)恢復(fù)原值”機(jī)制,就是說每次執(zhí)行完一組指令以后,程序會(huì)自動(dòng)將變量恢復(fù)為原值,以免對(duì)下一組指令的執(zhí)行產(chǎn)生影響。我們剛才做的“檢驗(yàn)工作”,真正目的并不是為了檢驗(yàn)得到的方案,而是為了強(qiáng)制地將word2的值設(shè)定為25188(剛才自編程系統(tǒng)自動(dòng)將它恢復(fù)為原本值了),最后大家看到的效果如下圖所示,word2=25188,旁邊還顯示了一個(gè)字符串“bd”。

總結(jié):本程序通過“高層指令優(yōu)先搜索法”提高搜索效率和收斂性,在枚舉的過程中優(yōu)先考慮自編程系統(tǒng)產(chǎn)生的高級(jí)操作,同時(shí)低級(jí)的原始操作也不會(huì)被忽略掉。為了做到這一點(diǎn),我們需要讓程序產(chǎn)生二進(jìn)制數(shù)(每一位都存儲(chǔ)在數(shù)組里面),用1代表高級(jí)操作指令,0代表底層操作指令,最后優(yōu)先選擇含有較少”0”的二進(jìn)制數(shù)組。不同的指令,接受不同數(shù)目、不同類型的參數(shù)。本程序通過“異進(jìn)制枚舉法”(產(chǎn)生不同位上使用不同進(jìn)制的整數(shù)),枚舉出所有的情況。有些時(shí)候自編程序需要對(duì)常數(shù)進(jìn)行枚舉,比如加1、加2、加3、加4……加255,有些時(shí)候則不用。常數(shù)枚舉會(huì)極大地增加枚舉嘗試的次數(shù),為了增加程序的收斂性,應(yīng)讓程序僅僅在必要的時(shí)候啟用常數(shù)枚舉功能(可以由用戶來決定)。本演示程序涉及各種不同的類,比如八位寄存器類、十六位寄存器類、八位變量類、十六位變量類、整數(shù)類。為了對(duì)它們進(jìn)行統(tǒng)一的操作,我規(guī)定程序需要用到的變量(包括用戶自己建立的變量)必須存儲(chǔ)在一個(gè)全局?jǐn)?shù)組內(nèi)。在此基礎(chǔ)上,我定義一個(gè)Object類(學(xué)過JAVA和.NET的人應(yīng)該對(duì)此不陌生),Object對(duì)象里面包含指向(全局?jǐn)?shù)組中)八位寄存器、十六位寄存器、八位變量、十六位變量的指針,還有一個(gè)標(biāo)志“類型”的char變量。函數(shù)在對(duì)Object對(duì)象進(jìn)行處理時(shí),會(huì)先根據(jù)char變量的值來判定對(duì)象的類型,從而對(duì)不同的指針解除引用,執(zhí)行不同的代碼。Object類的定義如下:classObject{public: chartype=-1;//0:8位寄存器;1:16位寄存器;2:8位變量;3:16位變量 Register8*reg8=0; Register16*reg16=0; Var8*var8=0; Var16*var16=0; unsignedshortimmValue=0;//type==4則為8位立即數(shù),type==5則為16位立即數(shù) unsignedshortgetValue() { if(type==0)returnreg8->value; elseif(type==1)returnreg16->getValue(); elseif(type==2)returnvar8->value; elseif(type==3)returnvar16->value; elseif(type==4||type==5)returnimmValue; } boolsetValue(unsignedshortv) { if(type==REG8) { if(v<=255&&v>=0) { reg8->value=v; returntrue; } } elseif(type==VAR8) { if(v<=255&&v>=0) { var8->value=v; returntrue; } } elseif(type==IMM8) { if(v<=255&&v>=0) { immValue=v; returntrue; } } elseif(type==REG16) { reg16->setValue(v); returntrue; } elseif(type==VAR16) { var16->value=v; returntrue; } elseif(type==IMM16) { immValue=v; returntrue; } returnfalse; } stringgetName() { if(type==REG16)returnreg16->name; elseif(type==REG8)returnreg8->name; elseif(type==VAR16)returnvar16->name; elseif(type==VAR8)returnvar8->name; else { chararr[10]; sprintf(arr,"%d",immValue);//數(shù)字轉(zhuǎn)為字符串 stringresult=arr; returnresult; } } unsignedshort_getValue() { if(type==REG16)returnreg16->getValue(); elseif(type==REG8)returnreg8->value; elseif(type==VAR16)returnvar16->value; elseif(type==VAR8)returnvar8->value; elseif(type==IMM16||type==IMM8)returnimmValue; } Object(){} Object(Register8*r) { reg8=r; type=REG8; } Object(Register16*r) { reg16=r; type=REG16; } Object(Var8*v) { var8=v; type=VAR8; } Object(Var16*v) { var16=v; type=VAR16; } Object(shorti,char_type) { if(_type==4||_type==5) { immValue=i; type=_type; } } boolequals(Objectother) { if(type!=other.type)returnfalse; if(type==IMM16||type==IMM8)returnimmValue==other.immValue; else { if(type==REG8)returnreg8==other.reg8; elseif(type==REG16)returnreg16==other.reg16; elseif(type==VAR8)returnvar8==other.var8; elseif(type==VAR16)returnvar16==other.var16; } }};其他部分代碼:1.二進(jìn)制數(shù)組類定義,以及產(chǎn)生二進(jìn)制數(shù)組的方法:classBitArray{public: boolinvalid=false; vector<bool>array; voidpush_front(intbit) { if(bit==0)array.insert(array.begin(),false); elsearray.insert(array.begin(),true); } voidpush_front(boolbit) { array.insert(array.begin(),bit); } intgetNumOfFalse() { intn=0; for(inti=0;i<array.size();i++) if(array[i]==false)n++; returnn; } voidpush_back(intbit) { if(bit==1)array.push_back(true); elsearray.push_back(false); } voidpush_back(boolbit) { array.push_back(bit); } stringtoString() { stringstr=""; for(inti=0;i<array.size();i++) str+=(array[i]?"1":"0"); returnstr; } boolequals(BitArrayother) { if(array.size()!=other.array.size())returnfalse; for(inti=0;i<array.size();i++) if(array[i]!=other.array[i])returnfalse; returntrue; }};vector<BitArray>getBitArrays(intMaxLen,intMinLen){ vector<BitArray>results; inti; for(i=0;i<pow(2,MaxLen);i++) { BitArraycurrentResult; if(i>0) { intn=i,//整除結(jié)果 r=0;//余數(shù) while(n>0)//十進(jìn)制轉(zhuǎn)為二進(jìn)制 { r=n%2; n/=2; currentResult.push_front(r);//余1填true,余0填false } results.push_back(currentResult); } else { currentResult.array.push_back(false); results.push_back(currentResult); } //補(bǔ)全 if(currentResult.array.size()<MaxLen) { BitArraycurrentBackup=currentResult;//備份原本的數(shù)組 for(inti=1;i<=MaxLen-currentBackup.array.size();i++) { currentResult=currentBackup;//恢復(fù)到開頭沒有插入false時(shí)的狀態(tài) //cout<<"原本長度:"<<currentResult.array.size()<<",需要補(bǔ)上" // <<i<<"個(gè)零\n"; for(intj=1;j<=i;j++)//在開頭插入i個(gè)false currentResult.push_front(false); if(getIndex(results,currentResult)==-1) results.push_back(currentResult); } } } //剔除位數(shù)過少的 vector<BitArray>temp; for(inti=0;i<results.size();i++) if(results[i].array.size()>=MinLen)temp.push_back(results[i]); results=temp; //False數(shù)目由小到大排序 for(inti=0;i<results.size()-1;i++) { for(intj=i+1;j<results.size();j++) { if(results[i].getNumOfFalse()>results[j].getNumOfFalse()) { BitArraytemp=results[i]; results[i]=results[j]; results[j]=temp; } } } returnresults;}2.全排列-異進(jìn)制枚舉-二維矩陣轉(zhuǎn)化vector<vector<Object>>completelyArrange(vector<vector<Object>>choices)//全排列{ //注:參數(shù)choices里面存儲(chǔ)了每一個(gè)參數(shù)的所有選項(xiàng), //外層下標(biāo)表示第幾個(gè)參數(shù),內(nèi)層表示該參數(shù)的第幾個(gè)選擇 //↓內(nèi)層下標(biāo)表示第幾個(gè)參數(shù)(☆等同于choices的外層下標(biāo)),外層下標(biāo)表示第幾種排列情況 vector<vector<int>>allAvailableIndexes;//排列得到的所有下標(biāo)情況 intlength=choices.size();//數(shù)字長度 intradix=0;//進(jìn)制 for(inti=0;i<choices.size();i++) if(choices[i].size()>radix)radix=choices[i].size();//最大參數(shù)個(gè)數(shù) longlongmaxValue=pow(radix,length)-1;//長度為length的radix進(jìn)制數(shù)所能表示的最大數(shù)值 for(longlongi=0;i<=maxValue;i++) { //進(jìn)制轉(zhuǎn)換 longlongn=i; longlongr=0; vector<int>temp;//radix進(jìn)制的數(shù)碼 if(n==0)temp.push_back(0); while(n>0) { r=n%radix; n/=radix; temp.push_back(r); } intoriginalSize=temp.size();//高位補(bǔ)零之前,這個(gè)radix進(jìn)制數(shù)的位數(shù) if(originalSize<length)//如果小于最大長度 { for(intm=1;m<=length-originalSize;m++) temp.push_back(0);//高位補(bǔ)零(暫時(shí)放在末尾) } reverse(temp.begin(),temp.end());//倒置 for(intj=temp.size()-1;j>=length-originalSize;j--)//從個(gè)位到第一個(gè)非補(bǔ)零位 { if(temp[j]>=choices[j].size())//比如數(shù)字是10進(jìn)制,而實(shí)際上只有7個(gè)參數(shù) { //例如:0024700 i+=(radix-choices[j].size())*pow(radix,temp.size()-1-j)-1; //跳到:0025000-1跨越了(10-7)*10^3-1個(gè)數(shù),3表示當(dāng)前位后面還有3位 gototryNext;//進(jìn)入下一個(gè)for(i....)循環(huán) } elseallAvailableIndexes.push_back(temp); } tryNext:; } //修正錯(cuò)誤 vector<int>bitMaxes;//每個(gè)位上的最大值 for(inti=0;i<length;i++) bitMaxes.push_back(choices[i].size()-1); vector<vector<int>>indexesTemp; for(inta=0;a<allAvailableIndexes.size();a++) { boolabandon=false; if(a>0&&indexesTemp.size()>0)//這個(gè)地方要好好看看?。。? { if(allAvailableIndexes[a].size()>allAvailableIndexes[a-1].size()) continue; } for(intb=0;b<allAvailableIndexes[a].size();b++) { //逐位比較 if(allAvailableIndexes[a][b]>bitMaxes[b]) { abandon=true;//只要有一位超出最大值,就丟棄掉整個(gè)方案 break; } } if(!abandon) addInto3(&indexesTemp,allAvailableIndexes[a]); } //修正完畢 allAvailableIndexes=indexesTemp; vector<vector<Object>>allAvailableArgs; //把下標(biāo)值轉(zhuǎn)化為具體的對(duì)象 for(inti=0;i<allAvailableIndexes.size();i++)//外層下標(biāo)i表示方案編號(hào) { //內(nèi)層下標(biāo)j表示第幾個(gè)參數(shù)(☆等同于choices的外層下標(biāo)) //allAvailableIndexes[i][j]表示枚舉選定的選項(xiàng) vector<Object>inner; for(intj=0;j<length;j++)//內(nèi)層下標(biāo)j表示第幾個(gè)參數(shù)(☆等同于choices的外層下標(biāo)) { intindex_choice=allAvailableIndexes[i][j]; inner.push_back(choices[j][index_choice]); } allAvailableArgs.push_back(inner); } returnallAvailableArgs;}3.產(chǎn)生二維數(shù)組的代碼:vector<ComplexOperation>complexOperations; for(inti=0;i<global_complexInstruction

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論