blob: c3e9905ffe3ae0049c3e23647317d170c8dd6a95 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001Intermediate LPC
2Descartes of Borg
3November 1993
4
5 Chapter 4: The LPC Pre-Compiler
6
74.1 Review
8The previous chapter was quite heavy, so now I will slow down a bit so
9you can digest and play with mappings and arrays by taking on the
10rather simple topic of the LPC pre-compiler. By this point, however,
11you should well understand how the driver interacts with the mudlib and
12be able to code objects which use call outs and heart beats. In addition,
13you should be coding simple objects which use mappings and arrays,
14noting how these data types perform in objects. It is also a good idea to
15start looking in detail at the actual mudlib code that makes up your mud.
16See if you understand everything which is going on in your mudlibs
17room and monster codes. For things you do not understand, ask the
18people on your mud designated to answer creator coding questions.
19
20Pre-compiler is actually a bit of a misnomer since LPC code is never
21truly compiled. Although this is changing with prototypes of newer
22LPC drivers, LPC drivers interpret the LPC code written by creators
23rather than compile it into binary format. Nevertheless, the LPC pre-
24compiler functions still perform much like pre-compilers for compiled
25languages in that pre-compiler directives are interpreted before the driver
26even starts to look at object code.
27
284.2 Pre-compiler Directives
29If you do not know what a pre-compiler is, you really do not need to
30worry. With respect to LPC, it is basically a process which happens
31before the driver begins to interpret LPC code which allows you to
32perform actions upon the entire code found in your file. Since the code
33is not yet interpreted, the pre-compiler process is involved before the file
34exists as an object and before any LPC functions or instructions are ever
35examined. The pre-compiler is thus working at the file level, meaning
36that it does not deal with any code in inherited files.
37
38The pre-compiler searches a file sent to it for pre-compiler directives.
39These are little instructions in the file meant only for the pre-compiler
40and are not really part of the LPC language. A pre-compiler directive is
41any line in a file beginning with a pound (#) sign. Pre-compiler
42directives are generally used to construct what the final code of a file will
43look at. The most common pre-compiler directives are:
44
45#define
46#undefine
47#include
48#ifdef
49#ifndef
50#if
51#elseif
52#else
53#endif
54#pragma
55
56Most realm coders on muds use exclusively the directives #define and
57#include. The other directives you may see often and should understand
58what they mean even if you never use them.
59
60The first pair of directives are:
61#define
62#undefine
63
64The #define directive sets up a set of characters which will be replaced
65any where they exist in the code at precompiler time with their definition.
66For example, take:
67
68#define OB_USER "/std/user"
69
70This directive has the pre-compiler search the entire file for instances of
71OB_USER. Everywhere it sees OB_USER, it replaces with "/std/user".
72<* NOTE Highlander@MorgenGrauen 11.2.94:
73 WRONG. OB_USER will _not_ be replaced if within "" in which case it is
74 treated as a normal string. So it is possible to write the text OB_USER.
75*>
76Note that it does not make OB_USER a variable in the code. The LPC
77interpreter never sees the OB_USER label. As stated above, the pre-
78compiler is a process which takes place before code interpretation. So
79what you wrote as:
80
81#define OB_USER "/std/user"
82
83void create() {
84 if(!file_exists(OB_USER+".c")) write("Merde! No user file!");
85 else write("Good! User file still exists!");
86}
87
88would arrive at the LPC interpreter as:
89
90void create() {
91 if(!file_exists("/std/user"+".c")) write("Merde! No user file!");
92 else write("Good! User file still exists!");
93}
94
95<* NOTE Highlander@MorgenGrauen 11.2.94
96 But: write("Text is OB_USER foo bar\n");
97 simply writes "Text is OB_USER foo bar". Confer previous note.
98*>
99
100Simply put, #define just literally replaces the defined label with whatever
101follows it. You may also use #define in a special instance where no
102value follows. This is called a binary definition. For example:
103
104#define __NIGHTMARE
105
106exists in the config file for the Nightmare Mudlib. This allows for pre-
107compiler tests which will be described later in the chapter.
108
109The other pre-compiler directive you are likely to use often is #include.
110As the name implies, #include includes the contents of another file right
111into the file being pre-compiled at the point in the file where the directive
112is placed. Files made for inclusion into other files are often called header
113files. They sometimes contain things like #define directives used by
114multiple files and function declarations for the file. The traditional file
115extension to header files is .h.
116
117Include directives follow one of 2 syntax's:
118
119#include <filename>
120#include "filename"
121
122If you give the absolute name of the file, then which syntax you use is
123irrelevant. How you enclose the file name determines how the pre-
124compiler searches for the header files. The pre-compiler first searches in
125system include directories for files enclosed in <>. For files enclosed in
126"", the pre-compiler begins its search in the same directory as the file
127going through the pre-compiler. Either way, the pre-compiler will
128search the system include directories and the directory of the file for the
129header file before giving up. The syntax simply determines the order.
130<* NOTE Highlander@MorgenGrauen 11.2.94
131 When using standard-headerfiles one should choose <>. "" is appropriate
132 when dealing with selfdefined headerfiles.
133*>
134
135The simplest pre-compiler directive is the #pragma directive. It is
136doubtful you will ever use this one. Basically, you follow the directive
137with some keyword which is meaningful to your driver. The only
138keyword I have ever seen is strict_types, which simply lets the driver
139know you want this file interpreted with strict data typing. I doubt you
140will ever need to use this, and you may never even see it. I just included
141it in the list in the event you do see it so you do not think it is doing
142anything truly meaningful.
143
144The final group of pre-compiler directives are the conditional pre-
145compiler directives. They allow you to pre-compile the file one way
146given the truth value of an expression, otherwise pre-compile the file
147another way. This is mostly useful for making code portable among
148mudlibs, since putting the m_delete() efun in code on a MudOS mud
149would normally cause an error, for example. So you might write the
150following:
151
152#ifdef MUDOS
153 map_delete(map, key);
154#else
155 map = m_delete(map, key);
156#endif
157
158which after being passed through the pre-compiler will appear to the
159interpreter as:
160
161 map_delete(map, key);
162
163on a MudOS mud, and:
164
165 map = m_delete(map, key);
166
167on other muds. The interpreter never sees the function call that would
168cause it to spam out in error.
169
170Notice that my example made use of a binary definition as described
171above. Binary definitions allow you to pass certain code to the
172interpreter based on what driver or mudlib you are using, among other
173conditions.
174
1754.3 Summary
176The pre-compiler is a useful LPC tool for maintaining modularity among
177your programs. When you have values that might be subject to change,
178but are used widely throughout your files, you might stick all of those
179values in a header file as #define statements so that any need to make a
180future change will cause you to need to change just the #define directive.
181A very good example of where this would be useful would be a header
182file called money.h which includes the directive:
183#define HARD_CURRENCIES ({ "gold", "platinum", "silver",
184"electrum", "copper" })
185so that if ever you wanted to add a new hard currency, you only need
186change this directive in order to update all files needing to know what the
187hard currencies are.
188
189The LPC pre-compiler also allows you to write code which can be
190ported without change among different mudlibs and drivers. Finally,
191you should be aware that the pre-compiler only accepts lines ending in
192carriage returns. If you want a multiple line pre-compiler directive, you
193need to end each incomplete line with a backslash(\).
194
195Copyright (c) George Reese 1993