The Macro Expansion Process 宏展開過程

The macro expansion process described here was initially developed by Paul Mensonides and is implemented in Wave. It is much more understandable as the description of the desired macro expansion algorithm provided in the C++ Standard [1].
這裡所描述的宏展開過程,起初是由 Paul Mensonides 開發的,並在 Wave 中實現。它比在C++標準[1]中提供的宏展開算法說明更容易理解。

Macro replacement proceeds left-to-right.
宏替換是從左到右進行處理的。

If, during scanning (or rescanning) an identifier is found, it is looked up in the symbol table. If the identifier is not found in the symbol table, it is not a macro and scanning continues.
如果在掃瞄(或重掃瞄)期間,發現一個標識符,則在符號表中對其進行查找。如果該標識符未能在符號表中找到,則它不是一個宏,且繼續掃瞄。

If the identifier is found, the value of a flag associated with the identifier is used to determine if the identifier is available for expansion. If it is not, the specific token (i.e. the specific instance of the identifier) is marked as disabled and is not expanded. If the identifier is available for expansion, the value of a different flag associated with the identifier in the symbol table is used to determine if the identifier is an object-like or function-like macro. If it is an object-like macro, it is expanded. If it is a function-like macro, it is only expanded if the next token is an left parenthesis.
如 果該標識符被找到,則使用一個與該標識符相關聯的標誌的值來決定這個標識符是否可以展開。如果不可以,則特定的單詞(即這個標識符的特定實例)被標記為禁 用且不展開。如果該標識符可以展開,則使用符號表中的另一個與該標識符相關聯的標誌的值來決定這個標識符是類似於對象的宏還是類似於函數的宏。如果它是一 個類似於對象的宏,則展開它。如果它是一個類似於函數的宏,則僅當下一個單詞為左括號時對其進行展開。

An identifier is available for expansion if it is not marked as disabled and if the the value of the flag associated with the identifier is not set, which is used to determine if the identifier is available for expansion.
一個標識符如果沒有被標記為禁用,且與該標識符相關聯的標誌值(該標誌用於判斷標識符是否可以展開)未設置時,就可以展開。

(If a macro is an object-like macro, skip past the next two paragraphs.)
(如果一個宏是類似於對象的,則跳過以下兩段。)

If a macro to be expanded is a function-like macro, it must have the exact number of actual arguments as the number of formal parameters required by the definition of the macro. Each argument is recursively scanned and expanded. Each parameter name found in the replacement list is replaced by the expanded actual argument after leading and trailing whitespace and all placeholder tokens are removed unless the parameter name immediately follows the stringizing operator ('#') or is adjacent to the token-pasting operator ('##').
如果被展開的宏是類似於函數的,那麼它必須具有和這個宏的定義中所要求的形參數量正好相同數量的實參。每個參數都被遞歸掃瞄和展開。在替換列表中發現的每一個參數名都在前後加上空白然後替換為展開後的實參,且所有佔位符單詞都被刪除,除非參數名緊跟在字符串化操作符('#')後或在單詞聯接操作符('##')前後。

If the parameter name immediately follows the stringizing operator ('#'), a stringized version of the unexpanded actual argument is inserted. If the parameter name is adjacent to the token-pasting operator ('##'), the unexpanded actual argument is inserted after all placeholder tokens are removed.
如果參數名緊跟在字符串化操作符('#')之後,那麼就插入一個未展開實參的字符串版本。如果參數名在單詞聯接操作符('##')前後,則在去除所有佔位符單詞後插入未展開的實參。

All concatenation takes place in the replacement list. (If a single concatenation yields multiple tokens, the behavior is undefined. Moreover, Wave in normal C++98 and C99 modes issues an error, if more then one token is produced as the result of the concatenation. In C++0x mode Wave treats token-pasting of unrelated tokens as well defined and inserts the reparsed string representation of the concatenated tokens into the replacement list.).
所有串接都發生在替換列表中。(如果一次串接產生多個單詞,那麼行為是未定義的。此外,如果串接的結果產生一個以上的單詞,Wave 在普通C++98和C99模式下會引發一個錯誤。在C++0x模式下 Wave 則會對無關的單詞進行單詞聯接,並將串接後的單詞的字符串表示插入到替換列表中)。

The flag in the symbol table entry associated with the name of the macro being expanded is set to indicate the that the macro is not available for expansion.
在符號表項中,與被展開宏的名字相關聯的標誌被設置,以表示該宏不可展開。

The replacement list is rescanned for further macro expansion. All leading and trailing whitespace tokens in the replacement list are removed (the placeholder tokens are left intact).
對替換列表重新掃瞄,進行下一步宏展開。在替換列表中的所有前導和後置空白單詞被刪除(佔位符單詞則被原封不動地保留)。

After rescanning completes, the flag in the symbol table entry associated with the name of macro being expanded is cleared to indicate that the macro is again available for expansion, and the sequence of tokens that constitutes the rescanned replacement list is returned to the point of invocation of the macro.
在完成重掃瞄後,符號表項中與被展開宏的名字相關聯的標誌被清除,以表示該宏可以再次展開,且組成重掃瞄後的替換列表的單詞序列被返回至該宏的調用點。

If this sequence of tokens is empty, it is replaced by a placeholder token. If a placeholder is found during scanning (or rescanning) it is ignored. (Also, if the only thing separating a parameter from the stringizing operator or token-pasting operator is placeholder, it is also ignored in that context.)
如果這個單詞序列為空,則替換為佔位符單詞。如果在掃瞄(或重掃瞄)時發現佔位符,則忽略它。(還有,如果參數與字符串化操作符或單詞聯接操作符之間只用了佔位符來分隔,則在這個上下文中也會忽略該佔位符)。

This sequence of tokens is inserted at the original point that the macro was invoked, and scanning continues starting with the last token of the newly inserted sequence of tokens. I.e. scanning looks back a single token (possibly a placeholder token) and continues.
這個單詞序列將被插入到該宏被調用的原始點,然後從剛插入的單詞序列的最後一個單詞開始繼續掃瞄。即,掃瞄動作會回讀一個單詞(可能是佔位符單詞)並繼續。


 

Saturday, February 25, 2006 15:46