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