<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 難以駕馭的引號 對于自己定義的宏,建議先在你的大腦中對它進行逐步展開,確信自己完全理解這個展開過程。如果大腦的堆棧不夠用,可以用紙和筆記錄展開過程。這樣可以在很大程度上提高宏定義的正確性。 m4 宏調用的復雜之處在于嵌套的宏調用——在一個宏的展開結果中調用了其他宏。例如,宏?`A`?的展開結果中調用了宏`X`,如果期望?`X`?先于?`A`?被 m4 展開,那么在?`A`?的定義中就不要在?`X`?的外圍加引號。如果在期望?`A`?展開后,當 m4 再度讀取?`A`?的展開結果的過程中再展開?`X`,那么?`X`?的外圍必須要有引號。再復雜一些,如果宏?`X`?的展開結果中又調用了宏?`Y`,并且期望?`Y`?是在 m4 再度讀取?`X`?展開結果的過程中被展開,那么?`Y`?的外圍也必須要有一重引號,此時因為?`X`?外圍已經有了一重引號,那么?`Y`?實際上是處于兩重引號的包裹之中。 m4 處理引號的基本規則是:在讀取帶引號的文本片段 S 時,無論 S 中含有多少重引號,m4 只消除其最外層引號,然后將剩余的文本直接發送到輸出流。這個規則很簡單,之前已經提到過一次。需要注意的是,如果在宏的參數列表中出現了引號,一定要記住宏的參數列表總是在宏展開之前被處理的。看下面的例子: ~~~ define(`echo', `$1') define(`test', echo($1)) test(test) ~~~ 在?`test`?宏定義過程中,`echo($1)`?先被 m4 展開了,結果為空字串,導致?`test`?宏定義語句中的宏體變成空字串,即: ~~~ define(`test', `') ~~~ 接下來,`test(test)`?是嵌套的宏調用,括號內的?`test`?會先被展開,展開結果是空字串,導致括號外面的?`test`?被展開之前的形式變為: ~~~ test() ~~~ 此時,`test`?宏接受了一個參數——空字串,然后它會被 m4 展開,展開結果為空字串。這個結果并非是因為?`test`?宏接受了空字串參數所導致的。 現在改動一下?`test`?的定義: ~~~ define(`echo', `$1') define(`test',`echo($1)') test(test) ~~~ 由于引號的抑制作用,`test`?宏體中的?`echo`?不會先于?`test`?定義完成之前被 m4 展開。`test(test)`?的宏展開次序依然同上,m4 先展開括號里面的?`test`,得到: ~~~ test(echo()) ~~~ 然后,m4 不會去展開括號外層的?`test`,而是先去展開括號里面的?`echo`?宏,因為它認為括號里面的文本是括號外面的`test`?宏的參數,結果變為: ~~~ test() ~~~ 接下來,`test()`?會被展開為空字串。 下面改動一下?`test`?宏調用語句: ~~~ define(`echo', `$1') define(`test',`echo($1)') test(`test') ~~~ 這時,括號里面的?`test`?就不再是宏調用了,而是括號外面的?`test`?宏的一個參數。`test(`test`)`?宏會被展開為: ~~~ echo(test) ~~~ 由于 m4 會將宏的展開結果插入到剩余的輸入流中繼續讀取并處理,所以上述結果被進一步處理為: ~~~ echo(echo()) ~~~ 再進一步處理為: ~~~ echo() ~~~ 最終的處理結果依然是一個空字串。 雖然這兩次改動并沒有得到新的結果,但是顯然宏展開的過程并不相同。宏參數中的引號的作用并不是那么顯而易見。大部分 m4 宏出錯,宏參數中的引號往往是首惡元兇。要駕馭它,只能憑借自己的明確的逐步推導。這也導致了一個問題,很難用 m4 描述復雜的宏邏輯。 作為一次小挑戰,請用筆在紙上推導下面 m4 宏的展開結果: ~~~ define(`echo', `$1') define(`test',`echo($1)') test(``test'') ~~~ 然后使用?`m4 -dV your-m4-file`?印證自己的推導。注意,?`m4 -dV`?所顯示的宏展開過程,會對每個宏的展開結果包裝一層引號,這其實是多余的引號,它只代表 m4 對宏的展開結果總是字符串。 ## 非法的宏名 下面這個宏定義: ~~~ define(`?N?', 1) ~~~ m4 會認為?`?N?`?這個宏是不合法的,因為合法的宏的名字必須要遵守正則表達式?`[_a-zA-Z][_a-zA-Z0-9]*`。不過,GNU m4 是仁慈的,對于不合法的宏,它依然能展開,前提是借助 m4 內建的?`defn`?宏: ~~~ ?N? # -> ?N? defn(`?N?') # -> 1 ~~~ 非法的宏名可以用來模擬數組或 Hash 表,例如: ~~~ define(`_set', `define(`$1[$2]', `$3')') define(`_get', `defn(`$1[$2]')') _set(`myarray', 1, `alpha') _get(`myarray', 1) # -> alpha _set(`myarray', `alpha', `omega') _get(`myarray', _get(`myarray',1)) # -> omega defn(`myarray[alpha]') # -> omega ~~~ ## 外援 GNU m4 內建了幾個與 Shell 交互的宏,諸如?`syscmd`,?`esyscmd`,?`sysval`,?`mkstemp`?等,其中最有用的是?`esyscmd`,因為它不僅能訪問 Shell,而且還能獲取 Shell 命令產生的輸出。例如,下面這行 m4 代碼可以借助 Shell 調用 GNU guile——GNU 的 Scheme 解釋器來計算階乘: ~~~ esyscmd(`guile -c "(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) (display (factorial 100))"') ~~~ 如果你的系統中安裝了 GNU guile,并且有一個 Shell 可用(既然是 m4 用戶,系統中沒有 Shell 說不過去的),那么 m4 對上述?`esyscmd`?宏的展開結果為: ~~~ 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 ~~~ 這樣寫也行: ~~~ define(`scheme_code', `"`(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) (display (factorial 100))'"') esyscmd(`guile -c' scheme_code) ~~~ 凡是能在 Shell 中運行并產生輸出的程序,皆能被 GNU m4 所用,這是不是很神奇? ## 文本處理 我一直都忍著不去談 GNU m4 針對文本處理提供的幾個內建宏,主要是因為既然有?`esyscmd`?這樣的宏可用,那么類 Unix 系統中那些很無敵的文本處理工具,諸如 tr, cut, paste, wc, md5sum, sed, awk, grep/egrep 等等,它們皆能被 m4 所用,那么何必再多此一舉? 倘若是為了讓 m4 腳本更具備可移植性,那么最好是將一個比較完整的 Shell 環境移植到目標平臺……對于主流操作系統而言,這并不是太困難的事,因為已經有了很多針對不同操作系統的完整的 Shell 環境實現。 如果依然堅持用 m4 的方式處理文本,建議閱讀:『[GNU m4 Text Handling](http://www.gnu.org/savannah-checkouts/gnu/m4/manual/m4-1.4.17/html_node/Text-handling.html#Text-handling)』。 ## 結束語 這份 GNU m4 指南至此終結。作為學習者,務必要記住 m4 官方手冊的告誡之語:有些人對 m4 非常著迷,他們先是用 m4 解決一些簡單的問題,然后解決了一個比一個更大的問題,直至掌握如何編寫一個復雜的 m4 宏集。若癡迷于此,往往會對一些簡單的問題寫出復雜的 m4 腳本,然后耗費很多時間去調試,反而不如直接手動解決問題更有效。所以,對于程序猿中的強迫癥患者,要對 m4 有所警惕,它可能會危及你的健康。 如果不想讓 m4 危及你的健康,永遠要記住:宏是用來縮寫那些復雜但是又經常重復出現的文本模式的。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看