UDN
Search public documentation:

UnrealScriptPreprocessorCH
English Translation
日本語訳
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 主页 > 虚幻脚本 > 虚幻脚预处理器 (UPP)

虚幻脚本预处理器 (UPP)


概述


在虚幻引擎 3 中,虚幻脚本编译器现在支持预处理器。预处理器的工作方式和 C++ 的预处理器类似,它支持通过 macros(宏指令) 进行的条件编译。

基础


Macro(宏指令)处理是在虚幻脚本编译 之前 发生的。因为它是一个单独的阶段,所以它和虚幻脚本的词法约定没有联系。

作用范围


Macro 的作用范围是在文件范围内,意味着脚本类中的 X 行上的宏指令仅能在该文件中的 X+n 行中可以使用(除非它被包含在另一个 .uc 文件内)。但是,您可以在您的工程的根文件夹中创建一个 Globals.uci 文件(也就是 Development\Src\MyProject\Globals.uci),这样这些宏指令便可以自动地被这个包中的所有类使用。

使用宏


通过在宏指令的名称之前使用 ` (反引号字符)来引入宏。所以,要想展开没有参数的 hello 宏,可以使用以下代码:

`hello

同样,可以把由大括号包围的宏的名称放到*`* (反引号字符)后面:

`{hello}

这样便可以在不方便放置空白处的文本中间“插入”宏指令扩展:

hippo`{hello}potamus

但,如何定义 hello 宏? 内置的宏 定义 和 C++ 中的宏定义方式非常类似:

  1. 使用 `define 关键字,并且后面至少跟随一个空白字符
  2. 新的宏指令的名称(及可选的函数参数列表),后面至少跟随一个空白字符
  3. 宏指令的主体的定义

所以 hello 宏定义为:

`define   hello   "Hello, World!"

之后, `hello 将会被 "Hello, World!" 所代替(包括引号在内)。宏扩展的结果是在所有可能的机会下扩展宏指令。宏指令扩展可以包含那些需要被扩展的宏指令,然后依次对其进行扩展;这意味着您可以书写“无穷递归”的宏指令。

您可以通过使用"\n"标记将新的命令行嵌入到宏指令表达式中,这样可以帮助您调试您的预处理器宏指令,而且与预计在 DefaultProperties 中使用的宏指令结合在一起使用时起着至关重要的作用。 示例:

`define EndComboBox(Name) \
    End Object \n\
    MenuObjects.Add(`Name)

宏参数


宏参数是按照位置进行传递的,位置由宏指令名称后面圆括号内的由逗号分隔的列表中的参数位置决定。为了将参数列表识别为宏指令的一部分,这个列表的开始圆括号必须立即出现在宏名称的后面。请参照关于内置宏 定义以下注意事项来了解有关宏参数的更多详细信息。

内置宏


定义

`define <macroname>[<(paramA[,paramB...])>] [<macrodefinition>]

定义命名的宏来扩展为给定的定义。如果没有提供定义,那么定义的宏指令将会扩展为空字符串。

宏的参数是在宏名称后面的无类型的函数参数列表中指定的。 在宏定义中,参数是通过名称进行引用的,并且参数的前面会有一个反单引号前缀。 比如:

`define DeclareInt(x) var int `x;

特殊的宏指令`# 代表了指定的参数的数量并且它仅可以在宏定义的内部进行引用。

if / else / endif

`if(<value>)
`else
`endif

这三个宏指令一起用于支持条件编译。处理 <value> 参数,如果它被扩展为非空字符串,那么 if 判定等于真;否则它等于假。

如果条件判定为真,那么在 `if`else (如果存在)或 `endif 之间存在的文本将会被作为处理后的输出;如果条件判定为假,那么则仅会产生行尾的字符,以便处理的文本中的行数和原始文本中的行数相匹配。

如果原始条件为假,那么将会产生 `else`endif 之间的文本(可选项)。

注意,不会计算未执行的代码中的宏指令(除了用于追踪嵌套层次的 `if 分组外)。

include

`include(<filename>)

在当前位置包含文件 <filename> 中的文本。默认情况下, <filename> 是相对于您的游戏的 .ini 文件中的 Editor.EditorEngine 部分的 EditPackagesInPath 中说明的目录来指定的。 如果您仅指定了文件名(也就是,没有目录),它将会在类的目录中为当前正在编译的包搜索该 include 文件。

isdefined

`isdefined(<macroname>)
`notdefined(<macroname>)

无论宏定义是什么,如果定义这个宏,则是 `isdefined(<macroname>) 计算结果为字符串“1”。如果没有定义那个宏,则是 `notdefined(<macroname>) 计算结果为字符串“1”。

undefine

`undefine(<macroname>)

删除 <macroname> 的当前定义。这对于宏参数名称(`cond, `txt, `# 等等)无效。

log / warn

`log(string OutputString, optional bool bRequiredCondition, optional name LogTag);
`warn(string OutputString, optional bool bRequiredCondition);

在 Object.uc 中声明了 LogInternal 和 WarnInternal 函数的封装宏。 如果指定了 bRequiredCondition ,则仅当条件判定为真时记录该信息。

如果是使用 -final_release 开关来编译脚本的,那么两个宏指令都将会被禁用。

logd

`logd(string OutputString, optional bool bRequiredCondition, optional name LogTag);

除了仅在 debug 模式下编译脚本时启用该宏指令外,其它功能和 `log 一样。

如果使用 -final_release 开关来编译这个脚本则会禁用这个宏指令。

assert

`assert(bool bCondition);

内在表达式 Assert 的封装宏指令。

如果使用 -final_release 开关来编译这个脚本则会禁用这个宏指令。

命令行交互


可以传入一些命令开关来影响脚本预处理器。

debug
使 UPP 定义宏指令 `debug
final_release
使 UPPer 定义宏指令 `final_release,并且会禁用所有封装宏 (`log, `logd, `warn, `assert)。
nopreprocess
关闭所有宏指令和注释的预处理,从输入文件中向类工厂中传入精确的文本。这对于时间和速度测试是非常重要的,但是如果要求的文本文件包含了宏指令外面的宏指令引入字符,那么可以使用这种方式来编译该文件。
intermediate
通知 UPP 保存它编译的文件的处理后的版本。对于整个源码树来说,这个过程是很消耗时间和空间的,但是在跟踪宏指令错误时,它可能是非常有用的。文件存储在这里:
GameDirectory/PreprocessedFiles/<PackageName>/<ClassName>.uc。