[Next]
[Up]
[Previous]
[Contents]
[Index]
Next: 6. Strings, Arrays and
Up: NannyMUD LPC
Previous: 4. Flow Control
Subsections
5. Functions and Program Structure
LPC
functions work in the same manner as functions in other languages;
they make it possible to split a problem into many small parts, write
code once, use others code and help make the code readable, etc.
5.1 Efuns, Sfuns and Lfuns
There are several classes of functions available to an LPC object:
- efuns
Efuns are external functions, i.e they are defined outside
any object, i.e. they are provided by the driver. They can be called
by all objects, but the driver might return different things depending
on what object made the call.
- sfuns
Sfuns are simulated efuns. This means that the function
behaves as an efun, i.e. is available to all objects, but that it is
really implemented through some LPC code.
- lfuns
Lfuns are local functions, i.e. they are defined by an LPC
object. They will be discussed in detail in the following sections.
5.2 Functions without type
Functions can be declared without specifying a type, unless the
#pragma strict_types is in effect, in which case all functions must
have types. Declared without types, the
function arguments can be
declared without types, too, and the function will accept that the
actual number of arguments passed differs from the number of arguments
declared. If called with
too many arguments, the extras are ignored.
If called with
too few, the missing ones default to zero.
Functions declared without types can be called from any other object,
they can be called from inheriting objects as well, and they can be
overloaded10.
5.3 Function types
A function can have the same types as a variable, and then one more:
void. A function of type void cannot return any value; doing
so is considered an error at load-time.
If the type of the function is specified, the
type of the arguments must also be given. If the types of
the arguments are specified, the
type-checking usually given by
#pragma strict_types will be performed on the statements of the function.
Also, the number of arguments passed to the function must be the same as
the number declared.
There is a set of
type modifiers that can be used on the functions type:
static, varargs, public, private
- static
Functions declared with the type modifier 'static' cannot be called
from other objects.
- varargs
A function declared with this type modifier can be called with a
varying number of arguments.
- private
Private functions cannot be called from any other object, nor from
any object inheriting the object where the function is defined.
- public
A function defined as public will always be accessible from
other objects.
- nomask
A symbol defined as 'nomask' cannot be redefined by
inheritance, nor by the mechanism of 'shadowing'11.
5.4 Function Prototyping
When using the
#pragma strict_types, functions must be declared before they
are used. This will in many cases force functions to be declared using
prototypes. This means that the functions type, as well as what parameters
it takes and their type, is specified, but the body of the function (with a
repetition of the type etc.) appears further on in the file.
5.5 Functions Returning Strings, Arrays or Mappings
A function can be exited at any point by adding a
return expr;
statement at the desired point of the code. The value of 'expr' is then
the value returned from the function to the calling code.
A function returning a string, mapping or an array does so by returning a
reference to it, rather than a copy. This can be used to keep shared
strings/arrays/mappings, thus saving some memory. If you'd rather want a copy,
you will have to force it. This is easiest done by returning the sum
of the string/array/mapping and an empty string/array/mapping.
5.6 Calling Non-Existant Functions
In LPC, calling a non-existing function in another object returns a zero.
This is a feature. On the other hand, calling a non-existing function
locally (in the same object) gives a run-time error. This is, also, a
feature.
5.7 Scope Rules
The scope of functions and global variables is from their point of
definition to the end of the file. The scope of formal parameters
(those declared as part of a function declaration) is the whole of the
function.
Local variables can be declared at the beginning of any block, and their
scope is from their point of declaration to the end of the function, not just
the end of the block where they were declared. This can be considered an
unwanted behaviour. Local variables hide any global variables with the same
name.
5.8 Block Structure
Functions cannot be declared within functions in LPC, but within the
functions, blocks can be declared within blocks. Each block can begin
by declaring variables, but local variables can only be declared
once.
5.9 Recursion
Functions in LPC can be called recursively. The driver will allow a certain
depth of the recursion before it stops the code. Circular recursive calls
will also be detected.
5.10 The Preprocessor
The LPC
preprocessor works like C's, almost. Somewhat more details:
- #pragma strict_types
This turns on typechecking for the whole file (at load-time).
- #pragma save_types
This makes the driver save type information which then can be
used objects inheriting this object.
- #define name token-string
Replace subsequent instances of 'name' with token-string.
- #define name(argument [, argument] ... ) token-string
This is a definition of a macro. Note that there can be no space
between 'name' and the `('. Subsequent instances of 'name', followed
by a list of arguments within parentheses, are replaced by
token-string,
where each occurrence of an argument in the token-string is replaced
by the corresponding token in the
comma-separated list. When a macro with arguments is
expanded, the arguments are placed into the expanded
token-string unchanged. After the entire token-string
has been expanded, the preprocessor re-starts its scan for
names to expand at the beginning of the newly created
token-string.
- #echo
This creates an entry in the MUD's debug-log.
- #undef name
Remove any definition for the symbol 'name'. No additional
tokens are permitted on the directive line after name.
- #include "filename"
- #include <filename>
Read in the contents of 'filename' at this location.
This data is processed as if it were part of the
current file. When the <filename> notation is used,
'filename' is only searched for in the
/include12
- #line integer-constant "filename"
Generate line control information for the next pass of
the compiler. `integer-constant' is interpreted as the line
number of the next line and `filename' is interpreted as
the file from where it comes. If `filename' is not given,
the current filename is unchanged. No additional tokens
are permitted on the directive line after the optional
filename.
- #if constant-expression
Subsequent lines up to the matching #else, #elif, or #endif
directive, appear in the output only if `constant-expression'
yields a nonzero value. All binary non-assignment LPC
operators, including `&&', `||', and `,', are legal in
`constant-expression'. The `?:' operator, and the unary `-',
`!', and `~' operators, are also legal in
`constant-expression'.
The precedence of these operators is the same as that for
LPC. In addition, the unary operator `defined', can be used
in constant-expression in these two forms: `defined ( name )'
or `defined name'. This allows the effect of #ifdef and
#ifndef directives (described below) in the #if directive.
Only these operators, integer constants, and names that are
known by the preprocessor should be used within
`constant-expression'. In particular, the sizeof operator is
not available.
- #ifdef name
Subsequent lines up to the matching #else, #elif, or #endif
appear in the output only if name has been defined with a
#define directive, and in the absence of an intervening #undef
directive. Additional tokens after name on the directive line
will be silently ignored.
- #ifndef name
Subsequent lines up to the matching #else, #elif, or #endif
appear in the output only if `name' has not been defined, or
if its definition has been removed with an #undef directive.
No additional tokens are permitted on the directive line after
name.
- #elif constant-expression
Any number of #elif directives may appear between an
#if, #ifdef, or #ifndef directive and a matching #else
or #endif directive. The lines following the #elif
directive appear in the output only if all of the
following conditions hold:
- The `constant-expression' in the preceding #if
directive evaluated to zero, the name in the
preceding #ifdef is not defined, or the name in
the preceding #ifndef directive was defined.
- The `constant-expression' in all intervening
#elif directives evaluated to zero.
- The current `constant-expression' evaluates to
non-zero.
If the `constant-expression' evaluates to non-zero
subsequent #elif and #else directives are ignored up to
the matching #endif. Any 'constant-expression' allowed
in an #if directive is allowed in an #elif directive.
- #else
This inverts the sense of the conditional directive
otherwise in effect. If the preceding conditional
would indicate that lines are to be included, then
lines between the #else and the matching #endif are
ignored. If the preceding conditional indicates that
lines would be ignored, subsequent lines are included
in the output. Conditional directives and corresponding
#else directives can be nested.
- #endif
End a section of lines begun by one of the conditional
directives #if, #ifdef, or #ifndef. Each such directive must
have a matching #endif.
There are some things that works in the standard C preprocessor but that
cannot be used in the LPC preprocessor:
- Concatenation of actual arguments during macro expansion using the
'##' construction does not work.
- Actual arguments cannot be expanded to quoted strings using the
'#' construction.
- A macro's body cannot contain the macro itself.
5.11 Comments in LPC
LPC allows comments over whole blocks by enclosing it in `/*' and `*/', just
like in C. It also allows for comments to the end of line using the
C++-style `//'.
Footnotes
- ...
overloaded10
- See section 7.2.
- ... 'shadowing'11
-
See section 8.1 on shadows.
- ... /include12
- Or rather, in a list of places defined by the
mudlib. This list is usually determined by
/obj/master.c.
[Next]
[Up]
[Previous]
[Contents]
[Index]
Next: 6. Strings, Arrays and
Up: NannyMUD LPC
Previous: 4. Flow Control
Mats Henrik Carlberg
1998-03-25