fpp [ options ] [ input-file [ output-file ] ]
fpp 是 FORTRAN 77 和 Fortran 95 的预处理程序。fpp 选择性地接受两个文件名作为参数。输入文件和输出文件分别是预处理程序读取的输入文件和预处理程序写入的输出文件。缺省情况下,使用标准输入和输出。可将 fpp 代替 cpp 预处理程序与 Oracle Solaris Studio Fortran 编译器结合使用。
缺省情况下,可识别 C 样式的注释。指定 -c_com=no 可将其关闭
将预处理程序变量 name 定义为 1(一)。这如同将 -Dname=1 选项用在 fpp 命令行上,还等效于将
#define name 1
行放在 fpp 处理的源文件中。
定义 name,如同通过 #define 指令进行定义。这如同将
#define name def
行放在 fpp 正在处理的源文件中。-D 选项的优先级低于 -U 选项。也就是说,如果在 -U 选项和 -D 选项中使用了相同的名称,则无论这两个选项顺序如何,名称均未定义。
采用固定格式的输入源。
采用自由格式的输入源。
将 directory 插入名称不是以 '/' 开头的 #include 文件的搜索路径。directory 将被插入 "include" 目录的标准列表之前。因此,将首先在具有 #include 行的文件的目录中搜索其名称括在双引号 (") 中的 #include 文件,然后在由 -I 选项指定的目录中搜索,最后在标准列表中的目录中搜索。对于其名称括在尖括号 (<>) 中的 #include 文件,不会搜索具有 #include 行的文件的目录。
生成 makefile 依赖项的列表并将其写入到标准输出。此列表指示将基于输入文件生成的目标文件取决于输入文件以及所引用的包含文件。
缺省情况下,宏在任何位置扩展。指定 -macro=no_com 可关闭注释中的宏扩展,指定 -macro=no 可完全关闭宏扩展。
不将行编号指令放到输出文件中。此指令显示为
#line-number file-name
删除 name 的任何初始定义,其中 name 是由特定预处理程序预定义的 fpp 变量。下面是可能已预定义的符号的部分列表,具体取决于系统的体系结构:
Operating System: unix, __unix, and__SVR4 Hardware: sun, __sun, sparc, and__sparc
删除所有预定义的符号的初始定义。
不将来自 fpp 的警告输出到标准错误。
将大写字母转换为小写,但在字符串常量中时除外。缺省设置是不将大写字母转换为小写。
对于固定格式的源文件(请参见下文),fpp 假定符号 ' '(空格)无关紧要。缺省情况下,对于这种格式,空格符号是标记的分隔符。
搜索文件时,使用指定的 directory 代替标准的目录列表。
fpp 还理解一些 f95 编译器选项(请参见 f95(1)):
接受扩展的源代码行(最多包含 132 个字符)。
不将警告输出到标准错误。
fpp 可对固定格式和自由格式的源文件进行操作。缺省情况下,带有 '.F' 扩展名的文件假定为采用固定格式,带有 '.F90' 和 '.F95' 扩展名的文件(以及其他所有文件)假定为采用自由格式。存在一个在 Fortran 95 中使用固定格式的 '-fixed' 选项。在固定模式下时,fpp 可识别源代码行的标签格式。
源文件可能包含 fpp 标记。fpp 标记接近 Fortran 的标记。它们包括:
fpp 指令名称。
符号名称,包括 Fortran 关键字。fpp 允许在名称中使用 Fortran 允许的所有符号。
常量。整数、实数、双精度和四精度值、二进制值、八进制值、十六进制值,包括备用记数法、字符和霍尔瑞斯代码。
注释,包括 Fortran 注释和 fpp 注释。
其他。特殊字符,空格、制表符、换行符等。
输出包含输入的修改副本以及如下形式的行:
#line_number file_name
插入来表示原始源代码行号和后跟输出行的文件名。有一个 '-P' 选项(请参见上文),它可禁止生成这些行。
fpp 指令的语法和语义与 cpp 指令相同(请参见 cpp(1))。
所有 fpp 指令都以井号 (#) 开头,该符号是行上的第一个字符。可以在初始 '#' 之后使用空格(SPACE 或 TAB 字符)以实现合适的缩排。指令可分为以下几组:
宏定义
条件源代码选择
包含外部文件
行控制
#define 指令用于定义简单的字符串变量和更为复杂的宏:
#define name token-string
这是 fpp 变量的定义。无论 'name' 出现在定义后面源代码行中的什么位置,'token-string' 都会替代 'name'。
#define name(argument [, argument] ... ) token-string
这是函数式宏的定义。出现的宏 'name'(后跟括号中的参数逗号分隔列表)将由从宏定义生成的标记字符串替换。每一次出现的宏定义参数列表中的参数标识符都将由表示相应宏实际参数的标记序列替换。
除宏替换运算符 # 和 ## 的操作数之外的宏参数将在替换标记列表中相应的替换项之前递归扩展。
要允许文本字符串中的参数替换,请使用 # 宏替换运算符:
#define a(x) #x ... a(actual argument)
生成:
'actual argument'
要将两个标记(其中一个是参数或两个都是参数)组合到一个宏定义中,请使用 ## 宏替换运算符:
#define cat(x,y) x##y x##b a##y #define ab ok ... cat(a,b)
生成:
ok ok ok
在这些定义中,禁止在宏名称与 '(' 符号之间使用空格,以防止将指令解释为 fpp 变量定义,将以 '(' 符号开头的行的其余部分解释为标记字符串。
#undef name
删除 'name' 的任何定义(由 'D' 选项、#define 指令或在缺省情况下生成)。在指令行上在 name 后不允许存在任何额外的标记。
文件包括指令分为两种形式:
#include "filename" #include <filename>
在此位置读入 filename 的内容。从文件读入的行由 fpp 处理,如同它是当前文件的一部分。
使用 <filename> 表示法时,仅在标准 "include" 目录中搜索文件名。有关更多详细信息,请参见上文的 'I' 和 'Y' 选项。指令行中最后的 '"' 或 '>' 后不允许出现任何其他标记。
#line-number "filename" 或 #line line-number "filename"
为编译器的下次传递生成行控制信息。将整数常量解释为下一行的行号,将文件名解释为来源文件的名称。如果未指定 "filename",则当前文件名不会改变。
源文本的条件选择分为两种形式:
1) #if condition_1 block_1 #elif condition_2 block_2 #else block_n #endif 2) #ifdef name block_1 #elif condition block_2 #else block_n #endif or #ifndef name block_1 #elif condition block_2 #else block_n #endif
else 和 elif 部分是可选的。可能有多个 elif 部分。条件是一个表达式,涉及 fpp 常量、宏和内部函数。条件表达式类似于 cpp 表达式,可能包含任何 cpp 运算和操作数,但 c 长型、八进制和十六进制常量除外。此外,fpp 将接受 Fortran 逻辑运算 .NOT.、.AND.、.OR.、.EQV.、.NEQV.、.GT.、.LT.、.LE.、.GE. 等以及逻辑常量 .TRUE.、.FALSE. 并对其求值。
定义的范围从定义的位置开始,包括从该定义行到当前文件结束的所有源代码行(以及所含文件中的源代码行)。
受 fpp 定义影响的范围有以下例外情况:
Fortran INCLUDE 语句包含的文件
fpp 和 Fortran 注释
IMPLICIT 单字母规范
FORMAT 规范
数字、无类型和字符常量
可以通过 #undef 指令对宏影响的范围进行限制。
宏定义可以是任意长度,仅受“换行符”符号限制。一个宏可以在多个行中定义。插入 '\',一个宏便可继续到下一行。所以,如果出现“换行符”但没有宏继续标记,表示宏定义结束。
例如:#define long_macro_name(x, y) x*y
对于 Fortran 77 固定格式的源文件,可能需要生成多个行或语句作为宏扩展。使用 ';' 分隔要在单独的行上生成的语句:
#define init_i_j(x,y) i=x; j=y ... init_i_j(1,2)
生成:
i=1 #2 j=2
宏调用参数数量应该与相应宏定义中的参数数量相同。如果不同,会标记一个错误。
#undef name
在此指令后面,fpp 不会将 'name' 解释为宏或变量名称。如果之前未将此名称定义为宏名称,则指定的指令没有作用
常量表达式
仅当常量表达式生成 true 值时,后续行(直至匹配的 #else、#elif 或 #endif 指令)才会出现在输出中。
只有满足以下所有条件时,位于 #elif 指令后的行才会出现在输出中:
前面的 #if 指令中的常量表达式求值为 .FALSE.,或前面的 #ifdef 指令中的名称未定义,或前面的 #ifndef 指令中的名称已定义。
所有中间 #elif 指令中的常量表达式都求值为 .FALSE.。
当前的常量表达式求值为 .TRUE.。
如果常量表达式求值为 .TRUE.,则后续 #elif 和 #else 指令将被忽略,直至匹配的 #endif。在 #if 指令中允许使用的任何常量表达式也允许在 #elif 指令中使用。
内部函数 'defined' 也可用在常量表达式中。
允许以下项目:
C 语言运算:<、>、==、!=、>=、<=、+、-、/、*、%、<<、>>、&、~、|、&&、||。fpp 根据 C 语言语义对它们进行解释(提供此工具是为了与使用 cpp 的“旧”Fortran 程序兼容)
Fortran 语言运算:.AND.、.OR.、.NEQV.、.XOR.、.EQV.、.NOT.、.GT.、.LT.、.LE.、.GE.、.NE.、.EQ.、**(幂值)。
Fortran 逻辑常量:.TRUE.、.FALSE.。
只有这些项目、整数常量和名称可用在常量表达式中。未借助 'D' 选项、#define 指令或在缺省情况下定义的名称将获得 0 作为值。C 运算符 '!='(不等号)可用在 #if 或 #elif 指令中,但是不能用在 #define 指令中,在此指令中将符号 '!' 视为 Fortran 注释符号。
仅当由 #define 指令或 'D' 选项(没有中间的 #undef 指令)定义了名称时,后续行(直至匹配的 #else、#elif 或 #endif)才会出现在输出中。在指令行上在 name 后不允许存在任何额外的标记。
仅当未定义名称或者已使用 #undef 指令删除了其定义时,后续行(直至匹配的 #else、#elif 或 #endif)才会出现在输出中。在指令行上在 name 后不允许存在任何额外的标记。
在 #if、#ifdef 或 #ifndef 指令与匹配的 #else 或 #endif 指令之间可能会出现任意数目的 #elif 指令。
这将颠倒否则会生效的条件指令的意义。如果前面的条件指示将包括这些行,则位于 #else 与匹配的 #endif 之间的行将被忽略。如果前面的条件指示将忽略这些行,则在输出中将包括后续行。条件指令和对应的 #else 指令可以嵌套。
结束以条件指令 #if、#ifdef 或 #ifndef 之一开头的行区域。每个这样的指令必须有一个匹配的 #endif。
与 cpp 的相同。文件的搜索如下所示:
对于 #include "file_name":
在找到处理的文件的目录中;
在 -I 选项指定的目录中;
在缺省目录中。
对于 #include <file_name>:
在 -I 选项指定的目录中;
在缺省目录中。
fpp 指令(在行的第一个位置以 # 符号开头)可放置在源代码中的任何位置,尤其是在 Fortran 续行前面。唯一的例外情况是,在通过继续符号分到多行的宏调用中禁止使用 fpp 指令。
fpp 允许两种类型的注释:
Fortran 语言注释。在第一个位置包含符号 'C'、'c'、'*'、'd' 或 'D' 之一的源代码行被视为注释行。在此类行中,不执行宏扩展。将 '!' 符号解释为扩展到行结尾的注释的开头。唯一的例外情况是,此符号出现在 #if 和 #elif 指令中的常量表达式中(请参见上文)。
使用 '/*' 和 '*/' 段落符号引起来的 fpp 注释。它们不在输出中,在这些符号中不执行宏扩展。fpp 注释可嵌套,对于每个段落符号 '/*',必须有一个相应的段落符号 '*/'。fpp 注释适合排除编译大部分源,而不是使用 Fortran 注释符号对每行进行注释。
内部函数
defined(name) 或 defined name
.TRUE.-如果名称定义为宏。
.FALSE.-如果名称未定义。
如果在宏扩展期间,行的列宽超过列 72(对于固定格式)或列 132(对于自由格式),则 fpp 会插入相应的续行。
对于固定格式,对标签字段(位置 1-5)中的宏扩展有所限制:
宏调用(连同可能的参数)不得扩展超过列 5 的位置;
名称以 Fortran 注释符号之一开头的宏调用被视为注释的一部分;
宏扩展生成的文本可能会扩展超过列 5 的位置。在这种情况下,将发出警告。
对于固定格式,指定 '-Xw' 选项后,如果宏调用发生在语句位置且宏名称以 Fortran 关键字开头或与其一致,可能会出现歧义。例如,在以下文本中:
#define callp(x) call f(x) call p(0)
fpp 无法明确地确定如何解释 'call p' 标记序列。可将其视为宏名称。当前的实现执行以下操作:
选择较长的标识符(在本例中是 callp);
从此标识符中提取最长的宏名称或关键字;
如果提取了宏名称,则执行宏扩展。如果名称以某个关键字开头,则 fpp 会输出相应的警告;
将标识符的其余部分视为完整的标识符。
在以上示例中,将执行宏扩展并输出以下警告:
warning: possibly incorrect substitution of macro callp
应注意,仅当预处理固定格式的源代码且空格符号未解释为标记分隔符时,才会出现这种情况。还要注意,如果宏名称与关键字开头部分一致,如以下示例中所示:
#define INT INTEGER*8 INTEGER k
则根据描述的算法,先于 INT 宏名称找到 INTEGER 关键字。因此,处理此类宏定义时,不会发出警告。
共有三种类型的诊断消息:
警告。继续预处理源代码,返回值仍为 0。
错误。fpp 继续预处理,但是将返回代码设置为非零值,即错误数。
致命错误。fpp 取消预处理,返回非零返回值。
fpp 生成的消息不需要加以说明。将随诊断消息一起输出发生错误的行号和文件名。
cpp(1)、f95(1)
可从 NetLib 下载 fpp 的源代码。
http://www.netlib.org/fortran/