robot
最新文章(10)
Mqskit 和其它相關工具
CPython 的 GC 二、三事
寫 Mecurial Extension 是件快樂的事!
Mozilla 台灣辨公室徵人啟事
關於 Apple 的兩項專利
core dump 之前的 frame
怎麼發出 beep 聲?
先承認你要找的是奴才吧!
程式碼要清的多乾淨?
FreeBSD 的 Thread-Local Storage 實作
首頁
新編
最新留言
Entries RSS
重要關鍵字(10)
coding (122)
Python (93)
FreeBSD (71)
WEB (61)
URL (48)
hardware (46)
javascript (36)
Linux (34)
blog (30)
C++ (16)
所有關鍵字
新增 URL
M4 巢狀巨集參數問題
by thinker
2 Columns
關鍵字:
coding
M4 是一個蠻有趣的巨集語言,透過不斷的巨集取代,達成豐富的執行效果。在$台灣$,會寫 M4 的人也許不多,但 M4 充斥著 OSS 的世界。例如, sendmail 就透過 M4 ,簡化那火星文般的設定檔。或許你不使用 sendmail ,或者都抄別人的設定檔,而不知如何設定大名頂頂的 sendmail 。那麼,另一種設定就更嚇人了。 許多 project 使用 autconf 產生 source code 目錄下 configure 程式,autoconf 也是基於 M4 ,以巨集的方式產生大量的 $shell$ script 。好吧!! 這兩個例子都很複雜, M4 寫起來確實很複雜。尤其是一層又一層的括號,絕對足以使你眼花。 像 M4 這種語言,之前因 autoconf 而學一點皮毛,但事後也不碰。最近,因為 MadButterfly 的緣故,讓我想起 M4 的威力,於是重拾文件猛啃。在使用的過程中,發現了一個複雜的問題,如何在巨集裡定義其它巨集,達到依據參數動態產生巨集的效果。其複雜的地方,在於如何使用參數。例如: {{{#!raw define(`foo', `define(`bar', `eval(`$$1 + 1')')') }}} 我們希望 foo 這個巨集能產生另一個巨集 bar ,使 bar 能做 +1 的動作。但實際使用結果如下 {{{#!raw foo ==> bar ==> 1 bar(2) ==> 1 foo(2) ==> bar ==> 3 }}} 可以看到 $$1 會被 foo 的參數所取代,而非 bar 的參數所取代。依據 M4 文件所寫,我們可以透過 quote (括號)將 $$ 和 1 分隔,以避免取代。 {{{#!raw define(`foo', `define(`bar', `eval(`$$`'1 + 1')')') }}} 結果 {{{#!raw bar ==> m4: bad constant in expr $$`'1 + 1. ==> 0 bar(1) ==> m4: bad constant in expr $$`'1 + 1. ==> 0 foo(2) ==> bar ==> m4: bad constant in expr $$`'1 + 1. ==> 0 }}} 結果, 參數並不會發生取代,而且造成錯誤。 == 以括號分隔 == 於是,我將 $$1 往括號外面移一層。並將括號在 $$ 和 1 之間做切割,使 $$ 和 1不會接在一起,但在外面一層進行取代之後,又會連接成一個字串,使 $$ 和 1 連接在一起。 {{{#!raw define(`foo', `define(`bar', `eval($$'`1` + 1')')') ==> foo ==> bar ==> 1 bar(2) ==> 3 }}} 原理是這樣的,字串 {{{#!raw `xxx$$'`1 ......' }}} 在巨集取代之後會變 {{{#!raw xxx$$1 ...... }}} 於是巧妙的安排,使 $$ 和 1 於執行內層的 define 之前,都是分離的,被括號分隔的。但在執行完內層 define 之後,定義巨集的 bar 的內容,恰將括號移除,使 $$ 和 1連接在一起。於是,使用 bar 巨集進行取代時,就會將 $$1 的內容取代成參數。 define 的一般使用形式為 {{{#!raw define(`foo', `......') }}} 由上面得知,如果我們將 $$ 和 1 以 define 指令該層的括號分隔,能避免外層 define 指令所定義的巨集對 $$1 進行取代,又剛好讓本層 define 指令所定義的巨集進行取代。這個原則,同樣適用於其它參數 $$1, $$2, ......。 {{{#!raw define(`foo', `.. $$'`1 ....') }}} == 括號裡的括號 == 有時侯,你可能會需要寫下這類的巨集 {{{#!raw define(`foo', ` ... `.. $$1 ..' ...') }}} 如果這又是另一個巢狀巨集時,那該怎麼辨??難道是 {{{#!raw define(`foo', `... `.. $$''``1 ..' ...') }}} 錯!! 因為 {{{#!raw `` .. $$''``1 ..'' ==> `.. $$'`1 ..' }}} foo 的內容裡, $$ 和 1 還是被分隔,因此不會發生取代。我們必需讓取代發生,但又必需在兩重的括號裡,那該如何是好?幾經嘗試之後,發覺可以使用另一個巨集產生括號,又能正確的取代。 {{{#!raw define(`quote', ```$$1''') ==> quote($$`'1) ==> `$$1' }}} 透過 quote ,我們能寫下巨集如下 {{{#!raw define(`foo', `... `.. ''quote($$`'1)`` ..' ..') }}} 於是 foo 的內容為 {{{#!raw `... `.. ''quote($$`'1)`` ..' ..' ==> ... `.. '`$$1'` ..' .. }}} 也就是等於 {{{#!raw ... `.. $$1 ..' .. }}} == 結論 == * 以定義巨集的 define 指令的同層括號,分隔 $$ 和 1 或其它數字。 * 如果有必要,使用 quote() 產生額外的括號。
最後更新時間: 2008-09-30 13:21:06 CST |
引用
查詢:
COMMENTS: