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.

Script 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 Warning 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.
NormalWork 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, InputOutput
// 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.