宏是一系列組合在一起的命令和指令,組合后形成一個(gè)單獨(dú)的命令,以實(shí)現(xiàn)任務(wù)執(zhí)行的自動(dòng)化。宏嵌套分為嵌套調(diào)用和嵌套定義。嵌套宏調(diào)用,又稱(chēng)宏嵌套調(diào)用,允許宏的定義體中包含著對(duì)其它宏的調(diào)用,且宏處理器遵循LIFO(Last In FirstOut)規(guī)則實(shí)現(xiàn)嵌套的宏的擴(kuò)展,一個(gè)宏的過(guò)程中,可能需要轉(zhuǎn)去擴(kuò)展其它宏;當(dāng)其它宏的擴(kuò)展結(jié)束時(shí),又要繼續(xù)之前中斷的宏擴(kuò)展1。
簡(jiǎn)介調(diào)用是將程序的執(zhí)行交給其他的代碼段,通常是一個(gè)子例程,同時(shí)保存必要的信息,從而使被調(diào)用段執(zhí)行完畢后返回到調(diào)用點(diǎn)繼續(xù)執(zhí)行。嵌套調(diào)用是指某個(gè)程序調(diào)用另一個(gè)程序。嵌套宏調(diào)用即宏程序中包含著對(duì)其它宏的調(diào)用,宏嵌套定義即宏程序中包含著其它宏的定義。現(xiàn)代宏處理器一般都支持宏的嵌套調(diào)用和嵌套定義。宏處理器主要完成宏的擴(kuò)展(macro expansion)和宏命令(macro directive)的執(zhí)行,這些工作可在單獨(dú)的一遍中完成。宏處理器的輸出做匯編器的輸入,宏處理器也常稱(chēng)預(yù)處理器。
宏宏(Macro),是一種批量處理的稱(chēng)謂。計(jì)算機(jī)科學(xué)里的宏是一種抽象(Abstraction),它根據(jù)一系列預(yù)定義的規(guī)則替換一定的文本模式。解釋器或編譯器在遇到宏時(shí)會(huì)自動(dòng)進(jìn)行這一模式替換。對(duì)于編譯語(yǔ)言,宏展開(kāi)在編譯時(shí)發(fā)生,進(jìn)行宏展開(kāi)的工具常被稱(chēng)為宏展開(kāi)器。宏這一術(shù)語(yǔ)也常常被用于許多類(lèi)似的環(huán)境中,它們是源自宏展開(kāi)的概念,這包括鍵盤(pán)宏和宏語(yǔ)言。絕大多數(shù)情況下,“宏”這個(gè)詞的使用暗示著將小命令或動(dòng)作轉(zhuǎn)化為一系列指令。宏的用途在于自動(dòng)化頻繁使用的序列或者是獲得一種更強(qiáng)大的抽象能力。
計(jì)算機(jī)語(yǔ)言如C語(yǔ)言或匯編語(yǔ)言有簡(jiǎn)單的宏系統(tǒng),由編譯器或匯編器的預(yù)處理器實(shí)現(xiàn)。C語(yǔ)言的宏預(yù)處理器的工作只是簡(jiǎn)單的文本搜索和替換,使用附加的文本處理語(yǔ)言如M4,C程序員可以獲得更精巧的宏。Lisp類(lèi)語(yǔ)言如Common Lisp和Scheme有更精巧的宏系統(tǒng):宏的行為如同是函數(shù)對(duì)自身程序文本的變形,并且可以應(yīng)用全部語(yǔ)言來(lái)表達(dá)這種變形。一個(gè)C宏可以定義一段語(yǔ)法的替換,然而一個(gè)Lisp的宏卻可以控制一節(jié)代碼的計(jì)算。
獲得了控制代碼的執(zhí)行順序(見(jiàn)惰性計(jì)算和非限制函數(shù))的能力,使得新創(chuàng)建的語(yǔ)法結(jié)構(gòu)與語(yǔ)言內(nèi)建的語(yǔ)法結(jié)構(gòu)不可區(qū)分。例如,一種Lisp方言有cond而沒(méi)有if,就可以使用宏由前者定義后者。Lisp語(yǔ)法的去部主要擴(kuò)展,比如面向?qū)ο蟮腃LOS系統(tǒng),可以由宏來(lái)定義。
應(yīng)用程序也可以使用一種和宏類(lèi)似機(jī)理的系統(tǒng)來(lái)允許用戶將一系列(一般是最常使用到的操作)自定義為一個(gè)步驟。也就是用戶執(zhí)行一系列操作,并且讓?xiě)?yīng)用程序來(lái)“記住”這些操作以及順序。更高級(jí)的用戶可以通過(guò)內(nèi)建的宏編程來(lái)直接使用那些應(yīng)用程序的功能。
當(dāng)使用一種不熟悉的宏語(yǔ)言來(lái)編程時(shí),比較有效的方法就是記錄一連串用戶希望得到的操作,然后通過(guò)閱讀應(yīng)用程序記錄下來(lái)的宏文件來(lái)理解宏命令的結(jié)構(gòu)組成。
宏的處理分為兩部分:宏定義的處理和宏調(diào)用的處理。宏的處理過(guò)程需要用到四個(gè)數(shù)據(jù)結(jié)構(gòu):P(Parameters)、A(Arguments)、MNT(MacroName Table)和MDT(Macro Definition Table)。表P在處理宏的定義時(shí)使用,它存放宏定義命令的形參名以及它們出現(xiàn)的順序號(hào)。表A在擴(kuò)展宏時(shí)使用,它存放宏調(diào)用的實(shí)參。MDT保存宏定義的代碼,其中出現(xiàn)的形參已用相應(yīng)的形參序號(hào)代替。MNT將宏的名字與它們?cè)贛DT中的定義關(guān)聯(lián)起來(lái)。
宏嵌套調(diào)用處理為實(shí)現(xiàn)該種宏的處理,我們所建立的算法數(shù)據(jù)結(jié)構(gòu)包含:宏擴(kuò)展棧MES(Macro Expansion Stack)。棧中自棧底至棧頂依次保存外層至內(nèi)層各當(dāng)前所擴(kuò)展的各層宏當(dāng)前擴(kuò)展位置(即MDT的代碼指針)。
擴(kuò)充表A為棧結(jié)構(gòu),棧中存放各次宏調(diào)用的實(shí)參。棧MES和棧A的數(shù)據(jù)出入同步。當(dāng)宏處理器遇到一次宏調(diào)用時(shí),將MDT的代碼地址壓入棧,再將宏調(diào)用的實(shí)在參數(shù)壓入棧A。當(dāng)宏的擴(kuò)展結(jié)束時(shí)(碰到MEND命令),棧MES和棧A的棧頂元素同時(shí)彈出。為支持宏的嵌套增加一個(gè)工作模式:擴(kuò)展定義模式(ED)。 ED模式下,宏處理器從MDT中讀取語(yǔ)句行,將它們輸出至MDT。
處理非嵌套宏時(shí),形參可用其序號(hào)替代。替換處理嵌套宏時(shí),形參要使用數(shù)對(duì)(定義層次,序號(hào))來(lái)替換。定義層次表示形參所在的最內(nèi)層宏的嵌套深度,序號(hào)含義則相同。例如:
# 源語(yǔ)句行 MDT1 P MACRO A, B2 A, B #(1, 1),#(1, 2)3 Q MACRO B QMACRO#(2, 1)4 A, B #(1,1),#(2,1)5 ENDM Q ENDM Q6 A, B #(1,1),#(1,2)7 ENDM P ENDM P宏P(guān)的定義中出現(xiàn)了宏Q的定義,且P的第二個(gè)形參與Q的第一個(gè)形參的名字相同。當(dāng)處理第4行語(yǔ)句時(shí),B所在的最內(nèi)層宏是Q,傳統(tǒng)替換方法中它的嵌套深度是2,所以B用#(2,1)替換。它仍使用單一序號(hào)替換形參。由于處理一個(gè)宏時(shí),僅需關(guān)心這個(gè)宏的定義(第一層或最外層的定義),而不需關(guān)注任何內(nèi)層宏的定義,其作為單獨(dú)的宏存入MDT,因此G. Revesz提出了一種更好的方法。采用這種方法,上面的宏定義在MDT的代碼為:
MDT2 #1,#23 QMACRO B4 #1, B5 ENDM Q6 #1,#27 ENDM P采用前述數(shù)據(jù)結(jié)構(gòu)來(lái)支持該種宏的處理。將參數(shù)表P擴(kuò)充為棧,棧中自底向上存儲(chǔ)各層宏定義的形參名(注:對(duì)于外層宏,棧存放的是數(shù)對(duì)(形參名,序號(hào)))。宏處理器在替換宏定義中的單詞(token)時(shí),由棧頂至棧底掃描P的形參名,若發(fā)現(xiàn)有某個(gè)非棧底的參數(shù)名與單詞匹配,則不予替換;若發(fā)現(xiàn)僅僅棧底的某個(gè)參數(shù)與單詞匹配,則用相應(yīng)的序號(hào)替換;若不匹配,則不替換。
本詞條內(nèi)容貢獻(xiàn)者為:
王慧維 - 副研究員 - 西南大學(xué)