Documentation: the preprocessor - a compiler before the real compiler Description: Before your code is compiled, the preprocessor is running. It will pick any line starting with #, followed by a preprocessor statement. Whitespace is NOT allowed before the #, but between the # and the statement. Also preprocesser statements can be indented. Every statement goes until the end of the line normally. But sometimes, you have a rather long chain of commands, which don't fit into one line. Then you can put a backslash "\" at the end of line. These lines will be joined together then. Macros: Macros are expressions, constants or code snippets that have a name. They can be put in anywhere (apart from strings) and are substituted by there contents. The names are in upper case by convention, but you can also make them lower case. But it's not wise as one might mix it up with variables. The Syntax for macro definitions is: #define The content will be put whereever you write , i.e., calculations in the content will be executed every time it is called. For example, we could define a macro called VOID, containing the string "room/void", by writing: #define VOID "room/void" Now think of the following situation: A wizard wants to have a general debugging macro, which checks if he is online, and tells him debugging information. But of course, he doesn't always want the same info. Therefor, macros can also have arguments, just like functions: #define (, , <...>) You give names to all the parameters, and then you can use these names, just like macros or variables: #define DEBUG(str) \ if (find_player("yourname")) tell_object(find_player("yourname", str+"\n"); Please notice that if you put a semicolon ; at the end, you don't need it after using the macro! At last, we can also just define a macro without any content. This sounds rather useless at first, but it is important for conditional compiling (see below). #define If you now use the macro in your code, it'll be removed. Now another thing that you need sometimes: Undefine macros. Two main cases where we need it: 1. We want to redefine it. That is the case if the macro has different meanings in different parts of the code. You can't just do another #define, you'll have to undefine it first. 2. In conditional compiling; see below. The syntax is: #undef Conditional compiling: Sometimes, you want to have different code in different situations. For example, you might not always need all the abilities or a header file (see below: including). Or you want to execute a different code in Nemesis and NemTest, or maybe even another mud. So, there are three commands that tell the preprocessor to check a condition. Let's start with the easiest one: #ifdef This makes the preprocessor check if a macro called is defined. The second one is almost the same: #ifndef This is the opposite of #ifdef: It will check if the macro is not defined. The third one is a bit more complicated: #if The condition is rather simple: The only valid values are numbers (and constant macros containing numbers), the only function is defined(), which will check if the macro was defined, and the operators are the same as described in 'man operators' apart from the comma and those requiring a variable or non-numeric operands. After one of these commands, you put code that is only compiled if the condition was true. Then you might need an optional else case: #else After this you put code that is only compiled if the condition was false. To end the whole thing, write: #endif You can also nest conditionals. Including files: When using macros, you often want to use them in more files, for example, a domain could define a macro for the domain directory. But it doesn't make a lot sense to redefine that macro in every file. Also code should sometimes be inserted in more than one file, but inheritance can't do what you need, for example because an inherited object cannot access variables of the subclass. Therefor, you can create header files. Those which don't contain that much code but are mainly about macros or other means of data (also functions which return data etc.) have filenames ending on .h by convention, those which contain mainly code do often have names ending on .c, just like normal objects. But now we need some command to put their contents in the main file: #include The file can be enclosed in '""' or '<>', there's actually no difference between it. If the filename starts with "/", then it's an absolute path. If not, the file will be searched for relatively to the main file. After all, if the filename does not contain "..", it will be searched for in the system include directories, which are /include/, /etc/ and /secure/. After the file was found, the preprocessor will read the contents and put them into the main file. This can be in any syntactic context, so the following example would be perfectly legal if some_array.h contains the inner part of an array (comma-separated list of values): some_array = ({ #include "some_array.h" }); /include/auto.h is automatically included before compilation is started. It contains some useful macros. Pragmas: Pragmas are commands that will affect the behaviour of the compiler. They're activated with: #pragma In Nemesis, we have two pragmas: strict_types Makes sure that you declare the type of functions. If a function has a declared type, then types will be more strict inside the function. save_types According to a comment in the Game Driver, this should "save argument types after compilation", but it's only declared and set. Seems like the GD never reads it again :-( Comments: Comments are no normal preprocessor commands. They're just deleted. There are two types of comments: // type A comments reach out until the end of a line /* type B comments can go over several lines, they're stopped with */ Comments are used to explain your code to others. They make it much easier to read and understand. You canNOT nest comments so the following is not possible: /* We don't need this code anymore, see above code ... code... code /* Here some additional information on the command */ code ... */ See also: LPC/inheritance, LPC/operators, w/NemTest