Worst-case scenario: the UEd Goblin wipes the map and burns down your house.

Legacy:Preprocessor

From Unreal Wiki, The Unreal Engine Documentation Site
Revision as of 02:49, 10 January 2008 by DarthMushak (Talk)

Jump to: navigation, search

Using the UT3 PreProcessor

Introduction

The UT3 PreProcessor is functional and while it seems to be lacking in documentation (at least that is available to the mod community) it works ok as a basic pp.

There are other preprocessors of course. I believe I've seen several UnrealScript specific ones and there are always things like filepp which is just totally awesome. You could use a C preprocessor as well, or something like perl's Template Toolkit.

However, should you choose to use the inbuilt preprocessor, here is a guide to what has been discovered so far.

features

* Basic if/else/elsif/endif directives
* Include capability
* Define preprocessor symbols
* Simple "literal" macro replacement
* Macros that can take arguments
* Multi-line Macros
* Some integration with Editor.Make 
* ??? There must be more - please contribute your knowledge!

usage

The usage is simple and rather straight forward. All directives are initiated with the backtick ( ` ) symbol.

Defining Macros...

Here are some examples of defining macros and symbols:

 
`define MyVersion "1.3.20" 
`define MyClass class'MyPackage.MyClass' 
`define LogError(txt) LogInternal( GetFuncName()$":"$ `txt , 'Error') 
`define LogDebug(txt) LogInternal( GetFuncName()$":"$ `txt , 'Debug') 
`define MyAssert(condition) if( `condition ) { `LogError("Assert failed: `condition"); }
`define NameOf(var) ( ( `var == `var ) ? '`var' : '`var' )

Conditional...

Standard if/elsif/else/endif clauses can be used. At the moment, the conditions that can be evaluated by these clauses seem to be somewhat limited to the following:

`notdefined( SYMBOL )
`isdefined( SYMBOL )

There must be other preprocessor functions that can be used as well - but those are all you need to accomplish quite a bit:

`define MyVersion "1.3.20" 
`define MyClass class'MyPackage.MyClass' 
`define LogError(txt) LogInternal( GetFuncName()$":"$ `txt , 'Error') 
`define MyAssert(condition) if( `condition ) { `LogError("Assert failed: `condition"); }
 
`if(`isdefined(DEBUG))
 
`define LogDebug(txt) LogInternal( GetFuncName()$":"$ `txt , 'Debug') 
`define NameOf(var) ( ( `var == `var ) ? '`var' : '`var' ) 
 
`else
 
`define LogDebug(txt) 
`define NameOf(var) '`var' 
 
`endif

Including Source...

You may use the include directive to incorporate content. The convention for "header files" seems to be to use the extension: .uci

class MyMutator extends Mutator;
 
`include( MyPackage/Classes/MyStdInc.uci )
 
function PostBeginPlay()
{
    `MyDbg("MyCoolMutator, Version: " $ `MyVersion );
    // whatever....
}

Things to investigate

The '#' symbol seems to be recognized:

// Not sure what this is - it may be for positional arguments or number of arguments supplied to macros.  More investigation is needed.
 
`#()

Enclosing symbols in '{' and '}' seems to have some purpose, not sure what it is but, I think it may mean "evaluate to empty string and do not produce an error if the symbol/macro is not defined." like so:

`if(`isdefined(MY_UNIT_TEST))
`define FuncScope public
`endif
 
`{FuncScope} MyCoolFunction()
{
   // whatever...
}

Line Continuation and Multi Line Macros

You may wish to continue long lines or create multi-line macros. You can continue lines with a backslash. If you want your macros to be "multi-line" then you can place a "\n" at the end of the line.

Example source:

var int SwapTmp;
`define SwapInt(a,b) SwapTmp = `a; \
                     `a = `b; \
                     `b = SwapTmp
 
var array<string> Messages;
`define DefaultMessages \
  Messages(0)="Hello World" \n \
  Messages(1)="Headshot!!!" \n
 
class MyClass extends Info;
 
function PostBeginPlay()
{
  Swap(MyKills,MyHealth);
}
 
defaultproperties
{
  `DefaultMessages
}

The above would result in something like:

var int SwapTmp;
 
 
 
 
 
 
class MyClass extends Info;
 
function PostBeginPlay()
{
  SwapTmp = MyKills; MyKills = MyHealth; MyHealth = SwapTmp;
}
 
defaultproperties
{
  Messages(0)="Hello World"
  Messages(1)="Headshot!!!"
}

Caveats

Line Numbers in warning/error output

Unless you use the `include() directive, you should not have a problem with this. If however, you choose to

use the `include() directive then when your code has a warning or error it is quite likely that the line

number reported by the compiler will be inaccurate.

_[BIA]DarthMushak_ : I have written a perl script that will launch "ut3 make" and parse the resulting output before displaying it, adjusting line numbers as necessary. If anyone is interested, let me know.

white space

  • Caution* you must be aware of how the UT3 preprocessor interprets whitespace! If there is no whitespace between the end of your macro definition and the newline, then when the preprocessor inserts the result, it will *eat all the whitespace on its RHS* - so:
1: `define MyType int\n
2: \n
3: var `MyType Foo;\n
4: \n
5: `define MyOtherType string \n
6: \n
7: var `MyOtherType Bar;\n

Assuming that the "\n" chars in the code above are the newlines, the above code would effectively produce the following:

1: 
2: 
3: var intFoo;
4:
5: 
6:
7: var string Bar;

So, be careful with the whitespace!

Integration with Editor.Make ( ut3 make ... )

While you are free to define symbols such as DEBUG and FINAL_RELEASE via preprocessor directives it is probably best if you leverage the inbuilt support for these two via command line switches to the "make" Commandlet.

Here is an example snippet of a class file that will be used to clarify the following examples:

DEBUG

By supplying the switch *-debug* to make, the symbol "DEBUG" will be defined globally in all classes during the parsing phase.

ut3 make -debug

FINAL_RELEASE

By supplying the switch *-final_release* to make, the symbol "FINAL_RELEASE" will be defined globally in all classes during parsing phase.

RELEASE

If you supply neither *-final_release* or *-debug* then the code will be built for "release".


More to come

Stay tuned! If you learn more, please update this page. Thanks!