A
/ \ _ Play Now Nemesis on
| | | | _______ _ _ _______ _______ _ _______
| |\ | | | ____| | \ / | | ____| / ____| | | / ____|
/-------/-------------------------------------------------------------------,
O= Home <=XX| About News Pics Adventurers Wizards Download Connect >
\-------\-------------------------------------------------------------------'
| | \ | | |____ | | | | | |____ ___ \ \ | | ___ \ \
| | \_| |_______| |_| |_| |_______| |_______/ |_| |_______/
\ /
V
Documentation Area
Document Path: /doc/LPC/preprocessor
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 <name> <content>
The content will be put whereever you write <name>, 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 <name>(<param1>, <param2>, <...>) <content>
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 <name>
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 <name>
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 <name>
This makes the preprocessor check if a macro called <name> is
defined.
The second one is almost the same:
#ifndef <name>
This is the opposite of #ifdef: It will check if the macro is
not defined.
The third one is a bit more complicated:
#if <condition>
The condition is rather simple: The only valid values are numbers
(and constant macros containing numbers), the only function is
defined(<name>), which will check if the macro <name> 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 <file>
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 <name>
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:
This page was generated in LPC
Imprint / Impressum