Introduction
A preprocessor is a program that processes it's data, to produce output that is used as input to another program. It can range from something as simple as being able to include additional source files in another, to being a full language extension. In other words, it is able to process additional commands in a script that perform special features before being compiled.
Editor Modes
The script editor works in three main modes.
Normal script mode
Any scripts loaded from the menus (or includes tab) are in normal mode. Scripts here are not
processed, unless included in a script in work mode. In other words, just
a really cool script editor.
Master - or Second Life Mode
This shows preprocessed script text, and raw script text from Second Life.
This mode is selected automatically if you are loading a script directly from Second Life,
or if preprocessor tags are detected in the file.
Any edits saved directly in this window are saved directly (or sent to Second Life) and are not processed
by the editor in any way. Handy if you just want to make a quick change. This
mode is primarily for debugging.
Work Mode
Scripts that have a master mode also have a work mode. This is the text that
you will usually want to work with, and is an in-memory only file. It is created when a
master script is loaded, or if preprocessor tags are detected in the file.
It is considerably more readable than the master script. When the work script is saved, lots of preprocessing happens,
the master is updated and saved back to Second Life (or hard disk).
Preprocessor Commands
These can be added to a script, and allow for additional functions to occur before the script is saved.
They are processed in the order they are in the code.
#include
Using #include will insert a source code file from your hard disk into the
script you are working on. It will check the current folder, the default
folder for includes set in preferences (as well as the folder the program is
installed in.) Different levels of folders are allowed.
You do not need to use include guards, the file will be included exactly where
you want it to be, and not included twice. Include is currently case sensitive.
#transclude
Using #transclude will insert a souce code file from your hard
disk into the script you are working on. The file will be added exactly
where you want it to be, and WILL be included multiple times if you let it.
This allows you to for example, repeat code sections for events for different states, and is
not intended for standard function includes.
#define
Using #define will create a macro which will be replaced when a script is
processed. This is a literal lexical replace. Generally used for
constant numbers or strings without taking up variable space. It can also
be used to inline functions, and functions with parameters. Defines can be
used in included files, in fact, that's a great place to put them. The
preprocessor allows for redefines, but processes defines/redefines sequentially
as they appear in the code.
Special Defines used by the preprocessor
#define example, Input | Output |
// simple replace
#define LocalChat 0
llSay(LocalChat,"Hello, Avatar!");
// simple string replace
#define Intro "Hello, Avatar!"
llSay(LocalChat,Intro);
// inline function, this example uses other replaced defines
#define Greet() llSay(LocalChat,Intro)
Greet();
// function with parameters.. in this case, "value" appears on
// the left and is replaced where it appears on the right.
#define Greeting(value) llSay(LocalChat,value)
Greeting(Intro);
| // simple replace
//| Defining LocalChat as 0
llSay(0,"Hello, Avatar!");
// simple string replace
//| Defining Intro as "Hello, Avatar!"
llSay(0,"Hello, Avatar!");
// inline function, this example uses other replaced defines
//| Defining Greet as llSay(LocalChat,Intro)
llSay(0,"Hello, Avatar!");
// function with parameters.. in this case, "value" appears on
// the left and is replaced where it appears on the right.
//| Defining Greeting as llSay(LocalChat,value)
llSay(0,"Hello, Avatar!");
|
#undef
#undef removes a previously defined macro. If you are using
macros for debugging purposes, it can be better to define, then undefine a macro
for readability.
#ifdef #ifndef #else #endif
#ifdef allows you to check if a macro has been defined.
It does not check what the value is, only that it is defined.
#ifndef allows you to check if a macro has NOT been defined,
or has been undefined.
(note: Use of global defines may have unintended results)
#warning
Warning does not break compile, but does display text in the output window, and
adds an error to the main preprocessor errors list.
#region and #endregion
Not actually used by the preprocessor, but they are used in the editor to collapse
code :)
//start_unprocessed_text and
//end_unprocessed_text
Used to mark the beginning and end of unprocessed text - text inside these
markers is sent to the work tab.
Text after these markers is the code that is compiled inside SL. I have
made an effort to comment most of the code processing.
#scriptname
Creates a special #define called ScriptName. ScriptName shows up on the WORK tab, and on the titlebar
Special Defines used by the preprocessor
#scriptname <name>
#define ScriptName <name>
Used in code, these create a define that replaces the master filename displayed in the WORK tab, and on the titlebar.
Used to make the filenames output from Second Life a lot more readable. If you
would like to use the ScriptName in your code, please surround it with quotes
like a normal string.
#define CompileDate <date>
#define CompileShortDate <date>
#define CompileTime <time>
These are auto-inserted into the script by the preprocessor when CompileDate is ticked under options.
They are set to the time of save, and are created in your local culture settings
(ie, US style dates for US people, UK style dates for UK people) so you can parse them
as strings in your own scripts later.
They are created, but not used internally by the preprocessor.
__FILE__
__LINE__
Usually used for debugging,
__FILE__ and
__LINE__ will be replaced with the current file and
line being read by the preprocessor respectively. Note, unlike most
defines, these have deliberately been made to work in comments (although they
will not be highlighted when used in a comment line)
__FILE__ is a string value surrounded by quotes.
For simplicity, pathnames on windows systems using the "\" for folders are
replaced with "/". (If a few people ask, I'll make an option)
__LINE__ is an integer value.
llWhisper(0, "The filename is "+__FILE__+" and the line number is "+(string)__LINE__);
// __FILE__ __LINE__
Optimiser
The optimiser will pick out any unused functions or global variables, and
comment them out on the master file. Comments are used in an effort to
make code more readable, and to highlight that changes have been made in the
code.
Issues
There are a few minor issues with the preprocessor not working 100% as expected, usually due to migrating from another preprocessor. Most problems can easily be corrected by a few minor formatting changes in the original source - it is suggested you check the master file for any errors in the preprocessed code.
Currently you may only have one master/work pair open in each instance of the editor (but as many normal code files as you like)
..a blank line is currently needed at the end of the file, and the preprocessor does not highlight the last line.
Workaround: Add a blank line at the end of the file.
..saving a blank file currently behaves unexpectedly
Workaround: Save as, then reload the file.