The Grendel Project - A Windows MUD Server (c) 2000-2002 by Michiel Rook = GMC introductory guide & specification ====================================== GMC (or Grendel MUD C if you will) is a language similar to C, devised for the sole purpose of powering the scripted parts of the Grendel MUD Server. It has support for variables, control structures, (nested) functions and external variables/traps. The system consists of a compiler, an assembler and a virtual machine setup which can be called from an application, in this case Grendel. 1. Syntax The GMC language is in many respects quite like C, with some simplifications and exceptions. The most important supported language constructs: - global and local variables - function definitions - loops (only for currently) - 'include' files - basic flow control (if statements) - valid integer & boolean expression 2. The compiler The GMC compiler works in four distinct passes. In the first pass, the source files are scanned & parsed, and basic syntax checking is performed. The second pass performs type checking & coercion. In the third pass an optimizer performs some basic optimizations: dead-code elimination, algebraic simplication (constant elimination) and some flow-of- control optimizations. The fourth and final pass is the code generator, where assembly code for the stack machine is written to a file. 3. The assembler The assembler simply converts the "human readable" assembly code to a binary format (this includes translating the labels for jumps/calls). Additionally, the assembler performs some simple optimizations (in a section commonly known as the 'peephole optimizer'), to reduce the number of instructions. 4. The virtual machine The VM of the GMC language is a fully functional stack machine processor with some 40+ opcodes in its instruction set. Internally the machine consists of a stack utilizing the Delphi 'variant' type. Apart from the stack there are a number of registers - the stack pointer, the base pointer, and the program counter (or instruction pointer). Only the first two can be accessed directly from the assembler. Lastly there is a data segment present. Its size is defined through the assembler directive '$DATA'. 5. Getting out of the VM The VM has support for a number of mechanisms to help a program 'get out' of the environment and have some interaction with the calling application. These mechanisms are: - System traps - Signals & sleep - External variables - External methods The system trap (in the form of do <string expression>) can be set to a userspecified function by the calling application. The trap can do with the string expression as it sees fit. Signals are used to "suspend" the execution of the program until some condition has been met (e.g. a signal has been raised) in another part of the server (wether that be native or scripted code). The sleep function suspends the program until a certain tickcount has been reached. External variables are a construct to associate external data with names or expressions in the GMC language. External methods are methods within a class, that are registered before a script is executed. In a script they are represented by a function without a body ('float cos(float x);' for example). These 'callbacks' are somewhat dangerous, as there is no mechanism to check the validity of the parameters specified in the declaration, nor the values provided at the time of calling. 6. Types GMC only allows basic (primitive) types - thus compound and structured types or arrays are not included in the language. The following basic types are supported: int, float, string, void, bool and external 'void' should not be used for basic identifiers, as these have no semantic meaning - any operations with these identifiers can be considered unsafe. 'int', 'float' and 'bool' exhibit the normal behaviour you would expect. 'string' works the same as the pascal type LongString. 'external' is a special type - it has no strict semantic meaning in itself, but will evaluate to a callback to the shell surrounding (or calling, if you will) the VM. This callback will take care of the necessary checks (including or excluding typing) and return a value associated with the external. An example: external ch; ch = "Grimlord"; Executing this snippet will have the external callback trying to associate the string value "Grimlord" with some enviroment. If this association succeeds, the resulting value will be placed in 'ch'. Another example, following on the previous one: x = ch.alignment; Again, this will have the callback trying to associate the member variable 'alignment' with the (already associated) variable 'ch'. Care must be taken that this member variable does actually exist, or hell will fall down and chaos will ensue. 7. Common entry points An 'entry point' is a position in your script code that has a common syntax or structure, and can be easily identified by the calling process. These entry points can be viewed as seperate blocks of code that are called when a particular event is triggered. Below you will find some common entry points that are used throughout the server code. void onTick(external ch) - is called every second void onAct(external ch, external target, string arg) - is called whenever 'ch' receives some action 'arg' from 'target' void onFight(external ch, external target) - is called every fight tick void onDeath(external ch, external target) - is called when 'ch' dies at the hands of 'target' void onReset(external ch) - is called when 'ch' resets void onGive(external ch, external target, external obj) - is called when 'target' gives 'obj' to 'ch' bool onBlock(external ch, external target) - is called when 'target' tries to leave a room with 'ch' blocking void onEmoteTarget(external victim, external actor, string arg) - is called when (e.g.) mob is target of an emote (e.g. 'slap <mobname>'); 'victim' is the target, e.g. the mob; 'actor' the person executing the emote (you, when you slap a mob); 'arg' will contain the emotename (Name:-field from system\socials.dat, e.g. 'SLAP'). When an entry point onEmoteTarget exists, the default emote handling (as defined in checkSocial() in mudsystem.pas) will not be executed. void onGreet(external ch, external target) - is called when 'target' enters a room where 'ch' is in