The Inform Technical Manual for revision 5.4, last updated 24/9/94 1 Introduction 2 Recondite directives 3 Unusual constant forms 4 String indirection and low strings 5 Game control commands and keyboard reading 6 Obselete commands 7 The abbreviations optimiser 8 Dictionary and parsing table formats Section 1 Introduction This is a short collection of notes on low-level matters covering what is neither in The Inform Designer's Manual nor the assembly-language documentation in The Specification of the Z-machine. The Designer's Manual is, however, intended to be entirely self-contained for all practical purposes. If this document contains nothing either interesting or useful, I feel I shall have achieved my purpose. It contains much of the commentary which used to be in the source code's header, such as its modification history, notes on porting the Inform compiler to new machines and documentation of obselete or internally-used features. I anticipate revising this (though not necessarily the Designer's Manual) each time the source code is updated. Section 2 Recondite directives These are the directives airily dismissed as 'recondite' in A1 to the Designer's Manual. Default ; If the constant has not yet been defined, define it with this value. (In Verblib this is used to give constants like MAX_CARRIED their default values if the main game source has not already set them; hence the name.) Stub ; If the routine has not yet been defined, define one which has $n$ local variables and simply returns false. (Setting the number of local variables prevents the game from calling a routine with more arguments than it has local variables to put them in; this should not do any harm to the interpreter, but neither does a little caution.) This is how "entry point" routines are handled: the Grammar library file stubs out any undeclared entry points. Dictionary ; Enters in dictionary, and makes a new constant for its address. This is not so much recondite as obselete; nowadays one would write something like Constant frog_word 'frog'; but in any case now that one can write simply 'frog' the need has gone away. System_file; Declares the present file to be a 'system file'. The only way in which these differ from other files is that if Inform has been told to Replace a given routine, it will ignore a definition of this routine in a 'system file'. Thus Parser and Verblib are system files, and conceivably other user-written library extensions (for magic, say) might want to be. Lowstring ; Puts string in the "low strings" area of the Z-machine (an area in the lowest 64K of memory which holds static strings, usually to hold abbreviations), and creates a constant with the given name to hold its word address. Any string which is to be used with the @ string escape must be declared in this low strings area. (But the use of the @ string escape is clumsy and there are probably better ways to get the effect in Inform 5.) Version ; sets the game file version (3 for Standard games, 5 for Advanced; 4 and 6 are present for completeness). This directive isn't so much recondite as redundant; the preferred way is to either set -v3 or some such at the command line, or to include a switches directive, e.g. Switches v3; The remaining directives are for debugging Inform only: Listsymbols; Listdict; Listverbs; Listobjects; are fairly self-explanatory (be warned: they can produce a lot of output). In addition, a number of tracing modes can be turned on and off in mid-pass: Trace Btrace Ltrace Etrace NoTrace NoBtrace NoLtrace NoEtrace Trace is an assembly-language style trace, with addresses and bytes as compiled; Btrace is the same, but produced on both passes, not just on pass 2; Ltrace traces each internal line of code; and Etrace, the highest-level of these, traces the expression evaluator at work by printing out the expression trees made and the assembly source these are reduced to. (A more vehement, less legible version is etrace full, which shows the process in minute detail.) Section 3 Unusual constant forms There are more constant forms in Inform 5 than are dreamt of in the Designer's Manual. Some are obselete, others obscure. To begin with, Inform predefines a number of constants which are used by the library: adjectives_table (byte address) preactions_table (byte address) actions_table (byte address) code_offset (packed address of code) strings_offset (packed address of strings) version_number (3 or 5 as appropriate) largest_object (the number of the largest created object + 255) dict_par1 dict_par2 dict_par3 which can be read by something like lookup = #adjectives_table; One does occasionally want to know the largest object number in high-level code, but the library provides a variable top_object such that the legal variable numbers are 1 <= n <= top_object and using this is preferable. The dict_par constants are byte offsets into a dictionary entry of the three bytes of data about the word, and are provided because these offsets are different between Standard and Advanced games; thus, the parser uses these constants to ensure portability between the two. A constant beginning #a$ means "the action number of this action routine". Thus, #a$TakeSub is equivalent to the more usual ##Take A constant beginning #w$, followed by a word of text, has as value the address of the given word in the dictionary (Inform will give an error at compile time if no such word is present). Largely obselete. A constant beginning #n$, followed by a word of text, has as value the address of the given word in the dictionary (Inform adds it to the dictionary as a new word if it is not already there). Thus, #n$leopard is equivalent to 'leopard'. However, this constant form is still useful to enter single-letter words into the dictionary (like y, which the parser defines as an abbreviation for "yes") since 'y' would instead mean the ASCII value of the character 'y'. A constant beginning #r$, followed by a routine name, gives the (packed) address of the given routine. This is chiefly useful for changing the routine-valued properties of an object in mid-game, e.g. lamp.before = #r$NewBeforeRoutine; where NewBeforeRoutine is defined as a global routine somewhere. Section 4 String indirection and low strings Inside a static string (in double-quotes), the string escape @nn, an @ sign followed by a two digit number, means "print the n-th string variable here". nn is a decimal number from 00 to 31. Now such a variable string can be set with the String ; which means that any string to be used in this way has to have been defined as a "low string" (see above). For example, Lowstring L_Frog "little green frog"; ... String 0 #L_Frog; "You notice a @00!^"; will result in the output You notice a little green frog! Actually, since the first 32 entries of the "synonyms table" in the Z-machine are reserved for this purpose, the command String n x is in fact equivalent to (0-->12)-->n=x; Due to a minor design infelicity of the Z-machine, the more friendly-looking usage String 0 "illegal frog"; will work in a Standard game but may unpredictably fail in an Advanced one exceeding 128K in length; hence the need to ensure all relevant strings are "low" (in the bottom 128K of memory). Section 5 Game control commands and keyboard reading quit; (Actually an assembly language opcode.) This quits the game (at once, with no confirmatory question to the user): all games must end this way, since it is illegal to return from the Main routine). restart; (Similarly an opcode.) Restarts the game exactly to its initial state, losing the previous state for good. save