DRAFT LPC90 Language Specification
Table of Contents
-
Introduction
1.1 Purpose of this Specification
1.2 History of LPC
1.3 Design Philosophy -
Lexical Structure
2.1 Characters
2.2 Tokens
2.3 Keywords
2.4 Identifiers
2.5 Literals
2.6 Comments -
Types
3.1 Primitive Types
3.2 Object Types
3.3 Special Types (nil
,mixed
)
3.4 Type Conversion -
Variables
4.1 Variable Declarations
4.2 Scope and Lifetime of Variables
4.3 Default Values -
Operators
5.1 Operator Precedence and Associativity
5.2 Arithmetic Operators
5.3 Relational and Logical Operators
5.4 Assignment Operators -
Expressions
6.1 Evaluation Order
6.2 Method Calls
6.3 Field Access
6.4 Conditional Expressions -
Statements
7.1 Block Statements
7.2 Control Flow Statements (if
,else
,while
,for
)
7.3 Return Statements -
Objects
8.1 Object Definition and Structure
8.2 Fields
8.3 Methods
8.4 Inheritance -
Execution
9.1 Program Entry Point
9.2 Object Instantiation and Initialization -
Preprocessing Directives
10.1#include
Directives
10.2#define
Macros -
Error Handling
11.1 Syntax Errors
11.2 Runtime Errors -
Appendices
A. Backus-Naur Form (BNF) Grammar
B. Reserved Words
1. Introduction
1.1 Purpose of this Specification [toc]
The purpose of this specification is to define the syntax, semantics, and structure of LPC, a programming language designed for building and enhancing LPMuds (online, multi-user, text-only role-playing games) — specifically, as the language existed very soon after its inception. By offering a formal and detailed description of LPC circa 1990, the LPC90 language specification aims to:
-
Establish a Foundation: Establish a consistent and widely accepted foundation that describes an original (or near-original) dialect of LPC, providing a common starting point from which future LPC specifications can evolve;
-
Facilitate Compatibility: Provide a clear and consistent reference for developers working with or adapting legacy LPC-based systems;
-
Enable Collaboration: Provide a foundation for community-driven enhancements or adaptations of LPC, while maintaining fidelity to LPC’s original design;
-
Preserve Historical Context: Document the features and design principles of LPC to ensure that the language’s original intent and functionality are not lost over time; and,
-
Promote Education and Exploration: Serve as a resource for programmers, hobbyists, and gamers interested in the role of LPC in the development of interactive gaming.
This specification is modeled after the scope and structure of modern programming language specifications but reflects LPC90’s simpler, more focused feature set. It aims to strike a balance between technical rigor and accessibility, making it useful for both technical audiences building LPC90-compliant compilers and systems and non-technical audiences interested in LPC’s legacy.
1.2 History of LPC [toc]
Lars Pensjö created LPC in 1989 as a streamlined programming language for MUD (“Multi-User Dungeon”) game engine developers and world architects. MUDs written in LPC came to be known, accordingly, as LPMuds.
1.3 Design Philosophy [toc]
The original design of LPC (i.e., LPC90) reflected a pragmatic approach to programming for text-based, multi-user games, such as MUDs. Its philosophy was guided by simplicity, efficiency, and flexibility, aiming to empower developers to create and maintain complex, interactive systems with minimal overhead.
Key Principles
-
C-like Simplicity
LPC90 drew heavily from the syntax and semantics of the C programming language, providing developers with a familiar and straightforward programming style. This similarity reduced the learning curve for those already acquainted with C, while maintaining the readability and ease of use that procedural programming offered. -
Lightweight Object Orientation
While not fully object-oriented, LPC90 introduced lightweight object support to facilitate modular design and code reuse. Objects encapsulated state and behavior, enabling developers to define interactive entities &emdash; such as players, items, and rooms &emdash; in a manner that was both intuitive and efficient. -
Performance for Real-Time Applications
Designed for real-time, interactive environments, LPC90 prioritized performance. Its features were streamlined to minimize unnecessary complexity, ensuring that MUD servers could handle a high volume (by 1990 standards) of concurrent users and events without significant resource constraints. -
Flexibility and Extensibility
LPC90 balanced simplicity with extensibility, providing mechanisms such as inheritance and preprocessor directives (‘#include’, ‘#define’) to allow developers to structure and extend their code effectively. This flexibility supported a wide variety of use cases, from simple systems to complex game mechanics. -
Minimalism
The language avoided overloading developers with unnecessary features, instead focusing on core functionality that aligned with its intended purpose. This minimalist design philosophy ensured that developers could focus on problem-solving rather than grappling with excessive language constructs. -
Preservation of Developer Creativity
LPC90 provided developers with tools to implement custom behavior and mechanics without imposing rigid design patterns. This freedom fostered creativity and adaptability, enabling the development of highly customized and innovative MUDs.
Historical Context
LPC90’s design reflected the state of computer hardware, networking, programming, and MUD development in the early 1990s. By blending the procedural style of C with lightweight object-oriented concepts, it provided a bridge between traditional structured programming and emerging object-oriented methodologies, making it uniquely suited to its era.
2. Lexical Structure
2.1 Characters [toc]
The characters used in LPC90 source code are defined by the standard ASCII character set. These characters are divided into the following categories based on their role in the language:
1. Letters
- LPC90 recognizes the following as letters:
- Uppercase letters:
A
toZ
- Lowercase letters:
a
toz
- Uppercase letters:
- Letters are used in identifiers, keywords, and string literals.
2. Digits
- The digits
0
to9
are used in:- Numeric literals (e.g.,
42
,3.14
) - Identifiers (after the first character)
- Numeric literals (e.g.,
3. Whitespace
- Whitespace characters are used to separate tokens and improve code readability. They include:
- Space (
- Horizontal tab (
\t
) - Carriage return (
\r
) - Line feed (
\n
)
- Space (
- Whitespace is ignored except when it separates tokens.
4. Special Characters
- LPC90 uses the following special characters in its syntax:
! " # $ % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ ` { | } ~
- These characters are used for operators, delimiters, and string literals.
5. Escape Sequences
- Within string literals and character constants, the following escape sequences are recognized:
\\
- Backslash\"
- Double quote\n
- Line feed\t
- Horizontal tab\r
- Carriage return- Additional escape sequences may be supported by the implementation for extended functionality.
6. Comments
- Comments are ignored during lexical analysis and can span:
- A single line: Introduced by
//
- Multiple lines: Enclosed between
/*
and*/
7. Character Encoding
- LPC90 assumes the source file is encoded in ASCII. Any characters outside the standard ASCII range may lead to undefined behavior unless explicitly supported by the implementation.
8. Case Sensitivity
- LPC90 is a case-sensitive language. For example:
- The identifier
Variable
is distinct fromvariable
.
- The identifier
- Keywords must be written in lowercase as specified.
Example
Here is an example showcasing valid use of characters in LPC90:
int count = 10; // Variable declaration
string name = "LPC90\n"; /* String with escape sequence */
if (count > 0) { // Special characters used in syntax
count--; // Decrement operator
}
2.2 Tokens [toc]
In LPC90, a token is the smallest unit of meaningful text in the source code. Tokens are recognized during lexical analysis and are categorized into several types:
1. Identifiers
Identifiers are names used for variables, fields, methods, and other user-defined elements.
- An identifier must begin with a letter (
A-Z
,a-z
) or an underscore (_
). - Subsequent characters may include letters, digits (
0-9
), or underscores. - Identifiers are case-sensitive.
Example:
int my_varariable = 10;
string _name = "LPC90";
2. Keywords
Keywords are reserved words that have predefined meanings in LPC90. They cannot be used as identifiers.
Examples of keywords include:
if
, else
, for
, while
, return
, true
, false
, nil
, inherit
Example:
if (x > 0) {
return true;
}
3. Literals
Literals represent fixed values in the source code. LPC90 supports the following types of literals:
- Integer literals: Whole numbers, e.g.,
42
,-100
- Float literals: Decimal numbers, e.g.,
3.14
,-0.01
- String literals: Sequences of characters enclosed in double quotes, e.g.,
"Hello World"
. - Logical literals:
true
,false
, andnil
(null).
Example:
int num = 42;
float pi = 3.14;
string message = "Hello";
status flag = true;
4. Operators
Operators are symbols that perform computations or comparisons. Examples include:
- Arithmetic Operators:
+
,-
,*
,/
,%
- Comparison Operators:
==
,!=
,<
,>
,<=
,>=
- Logical Operators:
&&
,||
,!
- Assignment Operators:
=
,+=
,-=
,*=
,/=
Example:
int result = 10 + 5;
if (x >= 0 && x < 100) {
x += 1;
}
5. Delimiters
Delimiters are symbols used to separate or group code elements. They include:
- Parentheses:
(
and)
- Braces:
{
and}
- Brackets:
[
and]
- Semicolon:
;
- Comma:
,
- Colon:
:
Example:
if (x > 0) {
my_array[0] = 10;
}
6. Comments
Comments are ignored by the compiler and are used for documentation:
- Single-line comments begin with
//
and extend to the end of the line. - Multi-line comments are enclosed between
/*
and*/
.
Example:
// This is a single-line comment
/* This is a
multi-line comment */
Summary
Tokens are categorized as:
- Identifiers: Names of variables, fields, and methods.
- Keywords: Reserved words with predefined meanings.
- Literals: Fixed values such as numbers, strings, or logical constants.
- Operators: Symbols for computation, comparison, and logic.
- Delimiters: Symbols that structure the code.
- Comments: Non-executable documentation in the code.
The proper use of tokens ensures that LPC90 source code is well-formed and understandable by the compiler.
2.3 Keywords [toc]
Keywords in LPC90 are reserved words with predefined meanings. They are an essential part of the language syntax and cannot be used as identifiers for variables, methods, or other user-defined elements.
List of Keywords
The following words are reserved in LPC90:
-
Control Structures:
if
,else
,for
,while
,return
-
Logical Constants:
true
,false
,nil
-
Object-Oriented Keywords:
inherit
Usage of Keywords
Keywords must be written in lowercase. LPC90 is case-sensitive, so writing If
instead of if
will result in a syntax error.
Example:
if (health > 0) {
return true;
} else {
return false;
}
In this example:
if
,else
, andreturn
are keywords.- They control the flow of the program and are reserved for specific language behavior.
Restrictions
Attempting to use a keyword as an identifier will result in a compilation error. For example:
Invalid Code:
int if = 10; // Error: 'if' is a reserved keyword
Summary
Keywords are reserved words that define the structure and behavior of LPC90 programs. They include control structures, logical constants, and object-oriented terms. Since LPC90 is case-sensitive, keywords must be written in lowercase exactly as specified.
2.4 Identifiers [toc]
Identifiers in LPC90 are names used to represent variables, methods, fields, parameters, and other user-defined elements. They allow developers to reference and manipulate data and behaviors in a program.
Rules for Identifiers
- Starting Character:
An identifier must begin with:- A letter (
A-Z
,a-z
) - An underscore (
_
)
- A letter (
- Subsequent Characters:
After the first character, identifiers can include:- Letters (
A-Z
,a-z
) - Digits (
0-9
) - Underscores (
_
)
- Letters (
-
Case Sensitivity:
LPC90 is case-sensitive, meaning identifiers such asVariable
,variable
, andVARIABLE
are treated as distinct. - Reserved Words Restriction:
Identifiers cannot be the same as keywords or reserved words (e.g.,if
,else
,return
). Using reserved words as identifiers will result in a compilation error.
Valid and Invalid Identifiers
Valid Identifiers:
int health;
string _name;
float player1_score;
Invalid Identifiers:
int 1stPlayer; // Cannot start with a digit
float if; // 'if' is a reserved keyword
string player-name; // Cannot contain a hyphen
Naming Conventions
While LPC90 imposes no strict naming conventions, the following practices are encouraged to improve code readability:
- Use Descriptive Names:
Choose names that clearly convey their purpose.
Example:int health_points; string player_name;
- Underscores for Separation:
Use underscores to separate words in multi-word identifiers.
Example:float player_score;
- Avoid Reserved Words:
Always avoid names that conflict with reserved keywords.
Summary
Identifiers in LPC90:
- Must start with a letter or an underscore.
- Can include letters, digits, and underscores after the first character.
- Are case-sensitive.
- Cannot use reserved words.
Adhering to these rules ensures that LPC90 programs are syntactically correct and readable.
2.5 Literals [toc]
Literals in LPC90 are fixed, constant values that appear directly in the source code. They represent specific data and can be categorized into the following types:
1. Integer Literals
Integer literals represent whole numbers, both positive and negative.
- They consist of a sequence of digits (
0-9
). - Negative integers are prefixed with a minus sign (
-
).
Examples:
int health = 100;
int damage = -25;
2. Float Literals
Float literals represent real numbers with a fractional part.
- They include a decimal point (
.
). - Optional negative values are prefixed with a minus sign (
-
).
Examples:
float pi = 3.14;
float temperature = -12.5;
3. String Literals
String literals represent sequences of characters enclosed in double quotes ("
).
- Special characters can be represented using escape sequences.
Escape Sequences:
\\
- Backslash\"
- Double quote\n
- Line feed (newline)\t
- Horizontal tab\r
- Carriage return
Examples:
string name = "LPC90";
string greeting = "Hello, World!\nWelcome to LPC.";
string escaped = "Path: C:\\Users\\Player";
4. Logical Literals
LPC90 includes three logical constants:
true
: Represents a logical “true” value.false
: Represents a logical “false” value.nil
: Represents a null or “no value.”
Examples:
status is_alive = true;
status has_loot = false;
object weapon = nil;
Summary
LPC90 supports the following types of literals:
- Integer Literals: Whole numbers like
42
or-100
. - Float Literals: Real numbers like
3.14
or-0.01
. - String Literals: Text values enclosed in double quotes, supporting escape sequences.
- Logical Literals: The constants
true
,false
, andnil
.
Literals provide the foundation for constant values within LPC90 programs and are essential for defining variables, initializing fields, and representing fixed data.
2.6 Comments [toc]
Comments in LPC90 are used to add explanatory notes or documentation to the source code. Comments are ignored by the compiler during lexical analysis and do not affect program behavior. LPC90 supports two types of comments:
1. Single-Line Comments
- Single-line comments begin with
//
. - All text following
//
on the same line is treated as a comment and ignored by the compiler.
Example:
// This is a single-line comment
int health = 100; // Initialize health to 100
2. Multi-Line Comments
- Multi-line comments are enclosed between
/*
and*/
. - They can span multiple lines, making them useful for larger blocks of documentation or temporarily disabling code.
Example:
/*
This is a multi-line comment.
It spans multiple lines.
*/
int health = 100;
/* Multi-line comments can also
be used to temporarily disable code.
int damage = 25;
*/
Comment Nesting
- LPC90 does not allow nesting of multi-line comments.
- Starting a new
/*
inside an existing multi-line comment will lead to syntax errors.
Invalid Example:
/* Outer comment
/* Inner comment */ // Error: nested comments are not allowed
*/
Best Practices for Comments
- Clarity: Use comments to explain complex logic or document code intentions.
- Avoid Redundancy: Do not comment obvious code.
- Consistent Style: Follow a consistent style for comments throughout your code.
Good Example:
// Check if the player has enough health
if (health > 0) {
reset();
}
Summary
LPC90 supports two types of comments:
- Single-Line Comments: Begin with
//
and extend to the end of the line. - Multi-Line Comments: Enclosed between
/*
and*/
, and can span multiple lines.
Comments are essential for improving code readability, documentation, and maintenance but are ignored by the compiler during execution.
3. Types
3.1 Primitive Types [toc]
Types
Primitive Types
LPC90 supports the following primitive types:
- int
- Represents integer values as a 32-bit signed integer with a range of -2,147,483,648 to 2,147,483,647.
- Example:
int count = 42;
- float
- Represents floating-point numbers with single-precision, following the IEEE 754 standard, with approximately 7 decimal digits of precision and a range of about ±1.4 × 10⁻⁴⁵ to ±3.4 × 10³⁸.
- Example:
float pi = 3.14;
- status
- Represents a boolean value, where:
true
indicates a positive condition.false
indicates a negative condition.
- Example:
status is_ready = true;
- Represents a boolean value, where:
- string
- Represents sequences of characters.
- Strings are immutable.
- Example:
string name = "player_one";
- void
- Used to indicate that a method does not return a value.
- Cannot be used as a variable type.
- Example:
void reset() { // Method implementation }
Primitive types provide the foundational building blocks for variables, method return types, and method parameters in LPC90. Additional types such as mapping
and mixed
are defined later in this specification.
3.2 Object Types [toc]
3.3 Special Types (`nil`, `mixed`) [toc]
3.4 Type Conversion [toc]
4. Variables
4.1 Variable Declarations [toc]
4.2 Scope and Lifetime of Variables [toc]
4.3 Default Values [toc]
5. Operators
5.1 Operator Precedence and Associativity [toc]
5.2 Arithmetic Operators [toc]
5.3 Relational and Logical Operators [toc]
5.4 Assignment Operators [toc]
6. Expressions
6.1 Evaluation Order [toc]
6.2 Method Calls [toc]
6.3 Field Access [toc]
6.4 Conditional Expressions [toc]
7. Statements
7.1 Block Statements [toc]
7.2 Control Flow Statements (`if`, `else`, `while`, `for`) [toc]
7.3 Return Statements [toc]
8. Objects
8.1 Object Definition and Structure [toc]
8.2 Fields [toc]
8.3 Methods [toc]
8.4 Inheritance [toc]
9. Execution
9.1 Program Entry Point [toc]
9.2 Object Instantiation and Initialization [toc]
10. Preprocessing Directives
10.1 #include
Directives[toc]
10.2 #define
Macros [toc]
11. Error Handling
11.1 Syntax Errors [toc]
11.2 Runtime Errors [toc]
12. Appendices
A. Backus-Naur Form (BNF) Grammar [toc]
This appendix defines the grammar of LPC90 using Backus-Naur Form (BNF). The grammar specifies the structure of an LPC source file, which consists of the following elements in order:
- Optional
inherit
declarations - Optional preprocessor directives, including
#include
and#define
- Field declarations and definitions
- Method declarations and definitions
A.1 BNF Grammar
<source-file> ::= <inherit-section>? <preprocessor-section>? <field-section> <method-section>
<inherit-section> ::= "inherit" <string-literal> ";"
<preprocessor-section> ::= (<include-directive> | <define-directive>)*
<include-directive> ::= "#include" <file-path>
<file-path> ::= <quoted-file> | <bracketed-file>
<quoted-file> ::= "\"" <file-name> "\""
<bracketed-file> ::= "<" <file-name> ">"
<file-name> ::= <identifier> ("/" <identifier>)*
<define-directive> ::= "#define" <identifier> <replacement-text>
<field-section> ::= <field-declaration>*
<field-declaration> ::= <type> <identifier> ("=" <expression>)? ";"
<method-section> ::= <method-declaration>*
<method-declaration> ::= <type> <identifier> "(" <parameter-list>? ")" <block>
<parameter-list> ::= <parameter> ("," <parameter>)*
<parameter> ::= <type> <identifier>
<block> ::= "{" <statement>* "}"
<type> ::= "int" | "float" | "mapping" | "mixed" | "object" | "status" | "string" | "void"
<expression> ::= <literal> | <identifier> | <binary-expression> | <unary-expression>
<literal> ::= <integer-literal> | <float-literal> | <string-literal> | "true" | "false" | "nil"
<statement> ::= <expression> ";"
| "if" "(" <expression> ")" <block> ("else" <block>)?
| "while" "(" <expression> ")" <block>
| "for" "(" <expression>? ";" <expression>? ";" <expression>? ")" <block>
| <block>
A.2 Example LPC Source File
inherit "base_object";
#define MAX_HEALTH 100
#include "local_file.h" // File in the same directory
#include <standard_lib.h> // File in the standard library
int health = 100;
string name;
void reset() {
health = MAX_HEALTH;
}
A.3 Parsing of the Example
The example LPC file in A.2 (above) parses into the following sections:
Inherit Section:
inherit "base_object";
Preprocessor Section:
#define MAX_HEALTH 100
#include "local_file.h" // File in the same directory
#include <standard_lib.h> // File in the standard library
Field Section:
int health = 100;
string name;
Method Section:
void reset() { health = MAX_HEALTH; }
B. Reserved Words [toc]
This appendix lists the reserved words in LPC90. Reserved words are predefined keywords in the language that cannot be used as identifiers (such as variable names, function names, or object names). They are an integral part of the language syntax and semantics.
List of Reserved Words
The following words are reserved in LPC90:
- Data Types:
int
float
mapping
mixed
object
status
string
void
- Control Structures:
else
for
if
return
while
- Logical Constants:
false
nil
true
- Object-Oriented Keywords:
inherit
Notes
-
Case Sensitivity: LPC90 is a case-sensitive language. Reserved words must be written in lowercase as listed above.
-
Future Extensions: Additional reserved words may be introduced in future versions of the LPC specification. Programs written in LPC90 should avoid using words that might reasonably become reserved in future specifications, such as
switch
orclass
. -
Impact on Identifiers: Because reserved words cannot be redefined, attempting to use them as identifiers will result in a compilation error.
Editor’s note: The draft LPC90 specification was generated with the assistance of ChatGPT.