程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編語言套裝軟件制作(2)

匯編語言套裝軟件制作(2)

編輯:匯編語言

第三節 程式合並

我所見過的各種組合程式雖不算多,但至少有百余個了。毛病最多的當然是缺乏完整的規劃,其次則是信馬游缰,一份不折不扣的流水帳!明明大門口在東邊,程式硬要朝西,直到游完了大觀園,天黑了,才出東門!
這種程式我收集了一大疊,可是舉來做例子,卻心有余而力不足。原因無他,實在不耐煩照抄一遍,一見到就頭痛!
電腦最強的功能,便是處理繁雜重復的工作,為什麼一般程式師居然存心與電腦爭風吃醋呢?不說別的,光把程式輸入到電腦中,就要花上幾個月寶貴的光陰,真值得這樣做嗎?
有一份程式,足足有四十多頁,我只略作調整,便縮小到十頁,處理速度則快了五倍。為什麼會差這樣遠呢?很簡單,有些人不喜歡用大腦,久而久之,習慣成自然,大腦就生了鐵銹!除了等因奉此,什麼都不會想了。
要想做一個優秀的程式師,第一個條件是不能偷懶,第二個條件則要有分析觀察的習慣,第三個也是最重要的,則是要有追求完美的精神。程式師要像藝術家,不論是自己的或是別人的程式,都要一而再、再而三地玩味改良。
我曾見過一個掃地的婦人,她不管在哪裡,見不得有任何髒亂。這種人才值得尊敬,這種精神是偉大的,與她的職業絲毫無關!
程式寫得不夠精簡,有三個原因,第一個是程式師無能,這種程式能夠寫完,可以運行,已算相當難得了;第二個原因是不懂技巧,硬橋硬馬的干, 不知什麼是效率,也不知道如何達成。自己寫的程式都不見得看得懂,遑論他人的?第三則是根本缺乏敬業精神,敷衍塞責,這種人我最瞧不起。
寫程式之初,如果把任務瞭解清楚,然後分析因素,分割模組。所有類似的情況都合並到一處,再以變數代替,統一執行。這原本是份內的工作,前述的情況根本不可能發生!
問題是發生了以後怎麼辦呢?我建議最好重寫,如果一定要改,只好采用程式合並的技巧,濃縮一下。
合並的目的是為了增進效率,而合並的方法則因情況不同而異,就像人生了病,必須先查出病因,否則無法下藥。我試著以所知道的一些例證,簡要地解說如後。

一、過程的合並:

要做過程的合並,首先要查明下列各點:
1,首先找出過程類似的,全部移到一堆,如果找不到,那就沒救了。
然而,這種程式要就是太小,根本不可能有類似的情況,再不就是寫作時雜亂無章,信馬游缰。分明有類似的過程,但沒有共通的原則,無從濃縮。當然,也可能有些程式,因工作量及處理的細節太多,以致無法濃縮。

2,在類似的程式中,找尋相異的指令或流程,再若沒有,那就是重復了,正宜合並。

3,把相異的指令或流程用變數取代,或將不同程式之入口放在暫存器裡。

4,將各程式在應用該流程前,設好變數及使用的暫存器。

5,合並相似的程式段,不同處應用變數取代之。

下面舉一實例,系一繪圖程式之片斷,茲改變原用標題,並將分散在各處若干不同之段,列述如下:
189: MASK PROC NEAR
190: MOV DX,3C4H
191: MOV AL,2
192: OUT DX,AL
193: MOV DX,3C5H
194: MOV AL,PCOLOR
195: OUT DX,AL
196: RET
197: MASK ENDP

380: MOV DX,03CEH
381: MOV AL,3
382: OUT DX,AL
383: MOV AL,18H
384: INC DX
385: OUT DX,AL
386: RET

490: MOV DX,3CEH
491: MOV AL,3
492: OUT DX,AL
493: MOV DX,3CFH
494: MOV AL,0H
495: OUT DX,AL
496: RET

589: CROSS PROC NEAR
590: MOV DX,3C4H
591: MOV AL,2
592: OUT DX,AL
593: INC DX
594: MOV AL,0FH
595: OUT DX,AL
596: RET
597: CROSS ENDP

這樣的段落有十多處,看來每個都略有不同,似乎不能合並。然而仔細分析,顯然是程式師訓練不夠,把一個非常有規則的程式,安排得非常紊亂,以致到這個地步。

我們先歸納問題,決定如何合並。第一,上述各段程式,應該統一作為子程式;第二,全部變數只有四個,其中兩個是傳送值,兩個是輸出入埠。後者有連續關系,等於只有一個。因此,在調用此子程式前,應先令DX為輸出入埠,再將變數裝入AX中,一次調用即可。此子程式如下:
300: SUB:
301: OUT DX,AL
302: INC DX
303: MOV AL,AH
304: OUT DX,AL
305: RET
這樣簡短的子程式,有無必要,端視時空的效益而定。不論怎樣整理,都遠比原來的要好。
另外有種情況,更為可怕,就是在鍵盤輸入後,用流程方式,一一比較輸入碼,再一一分別處理。
比如說,為了檢查游標鍵的左、右、上、下等八個方向的移動,以便作相應的處理,程式居然寫成:
100: PP1: MOV AH,0
101: INT 16H
102: CMP AX,4800H ;↑鍵
103: JNE NEXT1
104: CALL MOVDATA ;SET BUFFERS
105: CALL SETDLT ;SET INCREMENT
106: NXT01:
107: CALL DOTUP
108: LOOP NXT01
109: CALL XORDOT ;SET NEW DOT
110: CALL XYDISP ;DISP NEW XXX,YYY
111: JMP PP1
112: NEXT1:
113: CMP AX,5000H ;↓鍵
114: JNE NEXT2
115: CALL MOVDATA ;SET BUFFERS
116: CALL SETDLT ;SET INCREMENT
117: NXT02:
118: CALL DOTDOWN
119: LOOP NXT02
120: CALL XORDOT ;SET NEW DOT


121: CALL XYDISP ;DISP NEW XXX,YYY
122: JMP PP1
123: NEXT2:
124: CMP AX,4B00H ;←鍵
125: JNE NEXT3

這段程式總共要檢查八次,才能確定是否有游標移動以及哪個游標在移動。然後,還要一一檢查其他變化,共有十八種有效碼。我實在佩服這種程式師,不但有無比的耐性,還有非凡的想像力,居然能把一段極為簡單平凡的程式,寫得這樣的精彩動人!
如果是我,我會寫得毫無趣味:
100: PP1: SUB AH,AH
101: INT 16H
102: OR AL,AL
103: JNZ PP1 ;AL 非0無效
104: MOV BH,AL
105: MOV BL,AH
106: SUB BL,47H ;最小之字標鍵
107: JLE PP1 ;非處理范圍
108: SHL BX,1
109: CALL FUNC[BX]
110: JMP PP1
這是主流程,程式短,速度快,維護容易,一眼看過去,有什麼錯誤立刻分明。

1000: FUNC DW NEXT02 ;↖
1001: DW NEXT0 ;↑
1002: DW NEXT04 ;↗
1003: DW PPRET ;無效
1004: DW NEXT2 ;←
1005: DW PPRET ;無效
1006: DW NEXT4 ;→
1007: DW PPRET ;無效
1008: DW NEXT12 ;↙
1009: DW NEXT1 ;↓
1010: DW NEXT14 ;↘

因為這是子程式,加一段、減一段容易非常。
即使是子程式,也有很大的考究,就以前段來說,在 104至110 之間,就值得三思。
104: CALL MOVDATA ;SET BUFFERS
105: CALL SETDLT ;SET INCREMENT
106: NXT01:
107: CALL DOTUP
108: LOOP NXT01
109: CALL XORDOT ;SET NEW DOT
110: CALL XYDISP ;DISP NEW XXX,YYY
首先,104 和105 會重復多次,109 及110 亦然,為什麼不合並為一呢?這也是很常見的程式合並手法,兩次調用合為一次,速度及空間都較為經濟。
在子程式 SETDLT 之前,先調用一次 MOVDATA,另XYDISP也是一樣,首先備妥:
3000: SETDATA:
3001: CALL MOVDATA ;假設本程式有他用
3002: SETDLT:
3003: …

3100: XYDIDOT:
3101: CALL XORDOT ; 同上
3102: XYDISP:
3103: …

再來設計NEXT0 的子程式:
110: NEXT0:
111: CALL SETDATA
112: NXT01:
113: DOTUP 應搬至此,無需設為子程式。

120: LOOP NXT01
121: JMP XYDIDOT ; 如有必要,可先
; 設好參數
這樣合並一下,效果決不止高上十倍,等到真正學會了程式的技巧,寫作時速度也可以提高數倍。

二、分支的處理:

分支是程式中不可避免的手段,使用得好,整個程式氣勢一貫,有行雲流水之妙。
前面的例子根本不具分支的條件,故不能算是分支不良,而是程式師觀念錯誤。
下面再舉一例,由於分支不良,以致程式支離破碎。這是一則計算拋物線的快速程式,妙在沒有用乘除法,也沒有任何函數。其中有幾段是這樣的:
100: BEG00:
101: CMP BP,BUFY
102:? JLE BE7
103: OR CX,CX
104: JG BE20
105: MOV AX,BP
106:? SHL AX,1
107: DEC AX
108: JL BE10
109: BE2:
110: CALL BE1
111: JC BEG00
112: CALL BE3
113: JMP BEG00

120: BE14:
121:? LODSW
122: CMP AH,1FH
123: JGE BE141
124: LOOP BE14
125: POP DI
126: POP CX
127: MOV SI,DI
128: JMP BE142
129: BE141:
130: POP DI
131: POP CX
132: MOV SI,DI

150: BE10:
151: CALL BE1
152: JMP BEG00
153: BE20:
154: MOV AX,CX
155:? SUB AX,DX
156: SHL AX,1
157: DEC AX
158: JLE BE2
159:? CALL BE3
160: JMP BEG00
161: BE1:
162:? INC DX
163: ADD CX,DX
164: ADD CX,DX
165: INC CX
166: ADD DI,BUFX
167: CMP DI,BX
168: JLE BE1RET
169: CALL BE01
170: SUB DI,BX
171: BE1RET:
172: RET

190: BE01:
191:? MOV AL,1
192: CMP [SI+1],AL
193: JNZ BE011
194: INC BYTE PTR [SI+1]
195: RET

200: BE141:

全部程式並不大,不過一百多條指令,但是稍加改進,卻可以省卻廿多條指令,速度也會加快。重點在於106 到113 的分支錯誤,以致於多出BE10 BE20 BE3 BE01等段程式出來。
照理,BE1 BE3 BE01都不該另設子程式,BE14也應改寫,如此,整個程式就完全不同了。


原來由 105為:
105: MOV AX,BP ;★無必要
106: SHL AX,1 ;★無必要
107: DEC AX ;★無必要
108: JL BE10
109: BE2:
110: CALL BE1 ;★合並後,無需調用
111: JC BEG00 ;★另作分支
112: CALL BE3 ;★也無必要調用
113: JMP BEG00
現改為:
107: BE1: ;原為DEC AX分支處理
108: INC DX ;原161子程式作主流程
109: ADD CX,DX
110: ADD CX,DX
111: INC CX
112: ADD DI,BUFX
113: CMP DI,BX
114: JLE BE11
115: ; CALL BE01 ;本子程式重寫如下:
116: CMP BYTE PTR[SI+1],1
117: JNE BE1A
118: INC BYTE PTR[SI+1]
119: BE1A:
120: SUB DI,BX
121: JC BEG00 ;原111
122: … ;原BE3 程式

又 125條三個指令也是分支錯誤,白白浪費。
120: BE14:
121: LODSW
122: CMP AH,1FH
123: JGE BE141
124: LOOP BE14
125: POP DI ;★可以省略
126: POP CX ;★可以省略
127: MOV SI,DI ;★可以省略
128: JMP BE142 ;★可以省略
129: BE141:
130: POP DI
131: POP CX
132: MOV SI,DI ;127移到此
133: JNZ BE142 ;128移到此
134: …

第四節 定案包裝

一、手冊:

手冊寫作本來與程式寫作無關,但由於一般程式師都不知道手冊的重要性,往往程式寫得極佳,而市場口碑卻不良,以致慘遭滑鐵泸之敗。
實際上,當今市場的趨勢,都傾向於螢幕提示,以致於手冊僅具輔助作用,幫助使用者理解各種功能的發揮而已。
問題就出在這裡,一個功能的介紹、說明,與該功能應用的發揮,完全是不同的層次。「螢幕提示」經常由程式師自行制作,而程式師對文字概念的應用及理解能力,往往並不太高明,其結果可想而知。
手冊應該有專人寫作,這種人既要對文字概念應用裕如,又要充份瞭解電腦的功能。難的是,培養一個程式師,了不起三個月到半年,而一個能達意的作家,起碼需要三至五年。遺憾的是,一般電腦公司沒有這種眼光,以為寫程式需要技術,手冊則隨便找人應付了事。
手冊的重要性,並非僅止於此,一個有價值的程式,一定有周詳的計劃,有制作的藍圖。這種計劃及藍圖,經過文字概念上的整理,應該就是手冊本身。換句話說,有良好規劃的程式,必然是先有手冊作為藍圖,再根據手冊制作程式。

二、版本:

程式完成以後,除非一些特殊的原因,只要有實用價值,必然需要不斷改進、強化。
這一來就面臨版本更新的問題,程式師在制作之初,必須事先考慮周全。不要希望一次把程式寫得盡善美,完整無缺,不僅那是不可能的夢想,也是自找麻煩。
任何一個人,即使是不世天才,也不可能經歷人間所有的事件。而程式所需要適應的范圍,則是動態的、隨著人的知識及經驗不斷增長。因此,一個嶄新的程式一旦問世,就成為人世間的新生事物,人的經驗擴展後,新的需求即接踵而至。剛剛完成的程式,在完成的那一剎,就已成為過去式。
所以在程式規劃時,必須高瞻遠矚,考慮得越是周全,程式的生命力越是旺盛。同時,在另一方面,程式必須交到使用者手中,才有實際的價值。是以如何在周全的規劃,和盡快的完成工作之間,作有效的斟酌取捨,則是個難題。
解決的方法之一,就是利用「版本」觀念,將產品分為數個時期。這樣,不僅產品可以很快地交到使用者手中,而且使用者可以提供其應用經驗的回饋,更有利的,是程式得以不斷地增長、成熟、完善。
有了版本的觀念,還需要對版本的制作有明確的計劃,每一個版本的檔案維護,修訂更正,都要有專人負責。否則,當已經上市的版本還需要修改,而新的版本業已開始設計,若是一個不小心,分不清檔案屬於哪個版本時,其後果之不堪,將非局外人所能領會的了。

三、包裝:

此處所提的「包裝」,不是商業上所謂的如何將產品美化偽裝起來。而是指一個程式交到使用者手中時,應該具備哪些必備的,哪些選用的「配備程式」。
一般大型的應用程式,經常提供很多片磁盤,要先執行一個很復雜的「初始化」程式,才能使用。如果采用組合語言制作,其目的本就是為了節省空間。空間小了,應該可以避免這種多余的手續。
這就是包裝所要考慮的問題,比如說,在我們的“聚珍整合系統”中,附有如下一些配備程式及手冊:
1,功能、操作提示或手冊:
1-1 sm.hlp:在功能提示態下,說明各功能、操作方式及注意事項。
1-2 smvqoq.exe:聚珍整合系統操作手冊閱覽程式
smvqo1.dat--smvqod.dat :操作手冊資料檔。
2,smjooh.exe:繁、簡體檔互轉程式
smjooh.tab:繁、簡體轉換對照表。
3,smjopa.exe:本系統與park文書檔資料互轉用。
4,smjob5.exe:為轉換其他系統生成的文書檔資料用。
5,smjib5.exe:轉換dbase iii 資料檔。
這些程式及檔案,都要放在同一片磁盤中,不僅為了方便省事,也可降低成本。
在我們的經驗中,這些工作說來容易,做來卻大費周章。唯有在事先做好妥善的規劃,最後才能省時省事,達到理想的預期效果。
僅以螢幕提示為例,由於資料所占空間太大,就導致了極大的困難。如果事先有准備,將資料作適當的壓縮,顯然會省卻不少麻煩。
此外,手冊的印刷,磁盤的復制,所有一切應行考慮的,都要事先想清楚。要知道,一個應用軟件,其成本完全在開發及最後的包裝過程,為了成功,代價是必須先付出的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved