宏展开过程

此处描述的宏展开过程最初由 Paul Mensonides 开发并实现于Wave。C++ 标准 [1] 中提供的所需宏展开算法的描述更为易懂。

宏替换从左到右进行。

如果在扫描(或重新扫描)过程中找到标识符,则在符号表中查找该标识符。如果在符号表中未找到该标识符,则它不是宏,扫描继续。

如果找到该标识符,则使用与该标识符关联的标志的值来确定该标识符是否可用于展开。如果不可用,则将特定标记(即标识符的特定实例)标记为禁用,并且不展开。如果该标识符可用于展开,则使用符号表中与该标识符关联的另一个标志的值来确定该标识符是对象类宏还是函数类宏。如果它是对象类宏,则进行展开。如果它是函数类宏,仅当下一个标记是左括号时才进行展开。
标识符可用于展开,前提是它未被标记为禁用,并且与该标识符关联的标志的值未被设置,该标志用于确定标识符是否可用于展开。

(如果宏是对象类宏,请跳过接下来的两个段落。)

如果要展开的宏是函数类宏,则必须具有与宏定义所需的实际参数数量完全相同的形式参数数量。每个参数都会被递归扫描和展开。在替换列表中找到的每个参数名称都将被展开后的实际参数替换,前提是已删除前导和尾随空格以及所有占位符标记,除非参数名称紧跟在字符串化运算符('#')之后,或者与令牌粘贴运算符('##').

如果参数名称紧跟在字符串化运算符('#')之后,则插入字符串化的未展开实际参数版本。如果参数名称与令牌粘贴运算符('##')相邻,则在删除所有占位符标记后插入未展开的实际参数。

所有连接都在替换列表中进行。(如果单个连接产生多个标记,则行为未定义。此外,Wave在正常的 C++98 和 C99 模式下,如果连接的结果产生多个标记,则会发出错误。在 C++0x 模式下,Wave将不相关的标记的令牌粘贴视为良好定义,并将连接标记的重新解析字符串表示插入到替换列表中。)

将标志设置为表示正在展开的宏不可用,该标志位于与正在展开的宏名称关联的符号表条目中。

将重新扫描替换列表以进行进一步的宏展开。删除替换列表中的所有前导和尾随空格标记(占位符标记保持不变)。

重新扫描完成后,将符号表中与正在展开的宏名称关联的条目中的标志清除,以指示宏已再次可用于展开,并将构成重新扫描替换列表的标记序列返回到宏调用的点。

如果此标记序列为空,则将其替换为占位符标记。如果在扫描(或重新扫描)过程中找到占位符,则忽略它。(同样,如果唯一分隔参数与字符串化运算符或令牌粘贴运算符的字符是占位符,则在该上下文中也会被忽略。)

此标记序列将被插入到宏被调用的原始点,并且扫描将从新插入序列的最后一个标记开始继续。即,扫描会回溯一个标记(可能是占位符标记)并继续。


 

2006 年 2 月 25 日,星期六,15:46