Inform 6 Reference Addendum

Language and compiler changes: releases 6.30 to 6.34

Maintained by IFTF: <specs@ifarchive.org>

Copyright 2020 by the Interactive Fiction Technology Foundation. This document is licenced under a Creative Commons Attribution-ShareAlike 4.0 International License.

Graham Nelson's Inform 6 is a system for creating adventure games, and The Inform Designer's Manual is the book to read about it.

The fourth edition of that manual, published in 2001, began with that assertion. It's still true -- although these days we have to specify that it's about Inform 6. (Inform 7 is a more modern system, quite different, with its own manual called Writing With Inform.)

Inform 6 has remained broadly unchanged in the twenty years since the DM4 was published. While some authors continue to use I6 directly, its primary use is as an intermediate stage for the Inform 7 compiler. Stability and reliability have therefore been the watchwords of the I6 maintainers.

However, the language has not remained completely static. Most notably, the compiler now supports the Glulx VM as well as the original Z-machine. This required some additions to both the language and the compiler. Other corners of the system have been polished and rearranged, with the aim of making Inform a more flexible tool for both its target platforms.

As a result, the DM4 is now a bit out of date. This document is meant to fill in the gaps for the Inform 6 user of today.

Language versus library

This addendum covers updates to the Inform 6 language and compiler.

The changes described here are mostly to DM4 chapters 1-7, 36, and 38 and up. (Section references such as "§1" refer to DM4 chapters.) The intermediate chapters (the bulk of the DM4!) concern the Inform 6 library, which is not covered by this document.

The Inform library described by the DM4 is version 6/9, which was released along with Inform 6.21 in April of 1999. The library was subsequently updated to 6/10 (a bug-fix release) and then 6/11 (Glulx support and some additional features) before the author shifted his focus to Inform 7 development.

The Inform library is now a separate project managed by David Griffith. Updates can be found on the project page.

The Inform 6 compiler can be used with older versions of the Inform library, back through the Inform 5 libraries. There also exist a number of alternative Inform libraries, such as metro84 and PunyInform (supporting very old computers) and Platypus (a redesigned library). The Inform 6 compiler should be usable with all of them.

Compiler options and settings

The Inform compiler has many options which control its compilation behavior. These options come in three styles, and there are three ways to supply them.

Supplying options

All options can be supplied to the compiler in three ways (§39):

The third method is new since the DM4. It allows you to store your game's compilation options in the same file as its source code.

For example, this source file will be compiled in Glulx format, searching the i6lib directory for include files, raising the maximum number of verbs, and displaying compilation statistics:

!% -G
!% -s
!% +include_path=i6lib
!% $MAX_VERBS=255

Include "Parser";
Include "VerbLib";

[ Initialise;
  location = Kitchen;
];

Object Kitchen "Kitchen"
  with description "It's the kitchen.",
  has light;

Include "Grammar";

The options specified with !% must be at the start of the source file, with no blank lines or other comments before or between them.

Note that this section of the file is parsed before the source encoding is set. (Indeed, this section could specify the source encoding!) Therefore, options in this section must be plain ASCII.

Switch options (dash)

Classic options begin with a dash -- the traditional style of command-line tools. For example, the -h option (help) shows a page of output documenting how to run the compiler. -h2 will show a page listing all options that begin with a dash (§Table3).

New since the DM4:

-B: In Z-code versions 6 and 7 (only), use different offset values for the packed addresses of routines and strings. This allows the game file to contain more executable code. (The default is -~B, where the routine and string segments use the same offset value.)

-Cu: Treat the source files as being in UTF-8 (Unicode) encoding.

[Older options -C1, -C2, etc., are documented in the DM4 (§36); they treated the source files as being in one of the Latin-N encodings. -Cu is a new extension.]

[When -Cu is used, the compiler does not add any characters to the Z-machine's "cheap" alphabet table. You can use the Zcharacter directive to add selected Unicode characters; see §36.]

-G: Compile to Glulx format rather than Z-machine. The default output file will be given an .ulx extension.

-G -vX.Y.Z: In Glulx, specify the VM version number to note in the generated game file. For example, -G -v3.1.0 would generate a game file that specifies VM spec 3.1.0.

[Normally the compiler works out the earliest version number compatible with the features used by your game. You can use this option to specify a later version.]

-H: In Glulx format, use Huffman encoding to compress strings. This is the default; to use uncompressed text, use -~H.

-k: Output debugging information to a file gameinfo.dbg. This switch is documented in the DM4 (§7), but the output format has changed. It is now an extremely verbose XML format which describes every facet of the compiled game file.

-W: Sets the number of words in the Z-code header extension table (Z-spec 1.0). The default is -W3. The $ZCODE_HEADER_EXT_WORDS setting does the same thing.

-V: Display the compiler version and exit with no further action.

Path options (plus)

Options beginning with a plus set paths used by the compiler (§39). For example, +DIRNAME or +include_path=DIRNAME set the directory which is searched for include files.

You can also give a comma-separated list of paths: +include_path=DIR1,DIR2,DIR3

New since the DM4:

A double plus sign adds a new path or paths to an existing list. For example, ++include_path=DIRNAME will add DIRNAME to the paths which are searched for include files. The newly-added paths will be searched first.

Compiler settings (dollar)

These were referred to as "memory settings" in the DM4 (§39). However, they now encompass a wide range of compiler behavior.

The $LIST setting will show a page of output listing all dollar-sign settings for Z-machine games. To see all settings for Glulx games, give the -G argument before $LIST.

[If you supply one of these settings as a command-line option on MacOS or Unix, remember that the shell treats the dollar sign as a special character. You must escape the dollar sign so that it reaches the compiler:
inform \$MAX_VERBS=255 source.inf If you supply such a setting in a source file, using the !% format, you should not use the backslash.]

New since the DM4:

Settings marked "internal memory setting" do not affect the compiled game file. They just tell the Inform compiler to pre-allocate more work space, allowing it to compile a larger game. If you see a compile error which mentions one of these, set it higher and try again.

All other settings do affect the compiled game file in some way. Most often they modify the way that game data is laid out in memory.

$ALLOC_CHUNK_SIZE

This controls the size of various miscellaneous memory pools in the Inform compiler. (Internal memory setting.)

$DICT_CHAR_SIZE

The byte size of one character in the dictionary. This is only meaningful in Glulx. It can be 1 (dictionary characters are one byte) or 4 (dictionary characters are four-byte words).

$DICT_WORD_SIZE

The number of bytes in a dictionary word entry. (In Z-code this is 6, representing up to 9 Z-characters, and cannot be changed.)

$GLULX_OBJECT_EXT_BYTES

The number of extra zero bytes to add to each object table entry. This is writable memory which the game can use freely. (This is only meaningful in Glulx, as the Z-code object format is fixed by the spec.)

$INDIV_PROP_START

The index number of the first individual property. This also determines the maximum number of common properties. (In Z-code this is 64 and cannot be changed.)

$MAX_ARRAYS

The maximum number of arrays in one compiled game. (Internal memory setting.)

$MAX_GLOBAL_VARIABLES

The maximum number of global variables in one compiled game. (Internal memory setting. In Z-code this is 240 and cannot be changed.)

$MAX_INCLUSION_DEPTH

The maximum number of nested Include directives in source files. (Internal memory setting.)

$MAX_LOCAL_VARIABLES

The maximum number of local variables in a routine. (Internal memory setting. In Z-code this is 16 and cannot be changed.)

$MAX_NUM_STATIC_STRINGS

The maximum number of compiled strings in one compiled game. (Internal memory setting. This is only meaningful in Glulx, as Z-code uses a different text layout scheme.)

$MAX_OBJ_PROP_COUNT

The maximum number of properties in one object's property table. (Internal memory setting. This is only meaningful in Glulx.)

$MAX_OBJ_PROP_TABLE_SIZE

The maximum number of words used by one object's property table. (Internal memory setting. This is only meaningful in Glulx.)

$MAX_SOURCE_FILES

The maximum number of source files in one compilation. (Internal memory setting.)

$MAX_STACK_SIZE

The amount of memory that the interpreter will reserve for the Glulx stack. (This is only meaningful in Glulx.)

$MAX_UNICODE_CHARS

The maximum number of unique non-ASCII characters in the game text. (Internal memory setting. This is only meaningful in Glulx, as Z-code uses a different text layout scheme.)

$MEMORY_MAP_EXTENSION

The number of extra zero bytes to add to the end of the compiled game file. This is writable memory which the game can use freely. (This is only meaningful in Glulx.)

$NUM_ATTR_BYTES

The number of bytes used for attribute flags in each object. The maximum number of attributes is 8 * NUM_ATTR_BYTES. (In Glulx, this must be a multiple of 4 plus 3. In Z-code this is always 6 and cannot be changed.)

$OMIT_UNUSED_ROUTINES

If this is set to 1, the compiler will omit the compiled code of unused routines from the game file. (See $WARN_UNUSED_ROUTINES.)

$SERIAL

Sets the game's serial number to the given six-digit number. (The Serial directive does the same thing; see §38.)

$WARN_UNUSED_ROUTINES

If this is set to 2, the compiler will display a warning for each routine in the game file which is never called. (This includes routines called only from uncalled routines, etc.) If set to 1, it will warn only about functions in game code, not in library files.

$ZCODE_HEADER_EXT_WORDS

This sets the number of words in the Z-code header extension table. The default is 3. The -W setting does the same thing. (See Z-spec 1.0. This is only meaningful in Z-code.)

$ZCODE_HEADER_FLAGS_3

This is the value to store in the Flags 3 word of the header extension table. (See Z-spec 1.1. This is only meaningful in Z-code.)

Language changes

A few elements of the Inform language itself have been updated or extended.

Directives

A couple of notes on general directive syntax:

Directives in Inform 6 are not case-sensitive. These declarations are equivalent:

Global varname;
GLOBAL varname;
global varname;

The DM4 does not state this, but it has been true in every version of the Inform compiler, so we can accept it as a principle of the language.

[The DM4 mostly shows directives in title case: Global, Zcharacter, Ifdef. This is the manual's code style, not a language requirement.]

[Variable names and symbols are also case-insensitive. Language keywords, such as if and return, are not; they must be given in lower case. Case is also significant for the built-in print tokens (A), (a), (The), and (the); see §26.]

Directives can also be written with a # sign:

#Global varname;

For standalone directives, the # sign is optional. However, a few directives can be used within a routine or object definition. This allows conditional compilation of individual lines of code or object properties (§38). These directives are:

Ifdef, Ifndef, Ifnot, Ifv3, Ifv5, Iftrue, Iffalse, Endif

When one of these directives appears within a routine or object definition, the # sign is required.

[The compiler does not always detect directives appearing invalidly within a definition. However, using non-"if" directives in this way is unsupported. It may not work as expected and it may be reported as an error in the future.]

Array

The Array directive (§2.4) supports a new form, which is new in 6.30:

Array arrname buffer N; 
Array arrname buffer expr1 expr2 ... exprN; 
Array arrname buffer "string";

This defines arrname as a hybrid array, in which the first word array-->0 contains the length (N), and the following N bytes array->WORDSIZE, array->(WORDSIZE+1) ... array->(WORDSIZE+N-1) contain the specified expression values or string characters.

[This hybrid form is used by the print_to_array method (§3.12) and various library functions.]

All forms of the Array directive support the static keyword, which is new in 6.34:

Array arrname static -> 1 2 3 4;
Array arrname static string "plugh";

The static keyword must appear before the array type (->, -->, string, table, or buffer). It indicates that the array should be placed in non-writable memory.

[In Z-code, this places the array at the end of readable memory (after the dictionary and before the beginning of code storage). In Glulx, it places the array at the end of ROM (after string storage). A static array declaration should always provide initial values, since it cannot be updated at runtime. ]

Dictionary

The DM4 marked the Dictionary directive as obsolete (§Table5), but it has been reinstated as of 6.33. It allows you to add a word to the game dictionary and set its optional dictionary flags.

Dictionary 'word';
Dictionary 'word' val1;
Dictionary 'word' val1 val3;

The first form simply adds the word if it is not already in the dictionary. The second form also sets the dict_par1 flag to the given value, or bitwise-or's the value to that flag if the word already exists. The third form also sets the dict_par3 flag in the same way.

The values can be numeric literals or constants. They can be 0-255 for Z-code, or 0-65535 for Glulx.

[dict_par2 cannot be set by this directive. It is always the verb number, or zero for words that are not verbs.]

Ifv3

This is mentioned in the DM4 as being for compiler maintenance only (§Table5). In fact it is used by the library, so it's worth documenting. This is a conditional compilation directive, like Iftrue, which compiles code when building Z-code V3 (only). It is equivalent to:

#Ifdef TARGET_ZCODE;
#Iftrue (#version_number == 3);
! ...code...
#Endif;
#Endif;

Ifv5

This misnamed directive is also used by the library (§Table5). It conditionally compiles code when building Z-code V4 and later or Glulx. Thus it is the converse of Ifv3. (The name is left over from much earlier versions of Inform.)

Origsource

The Origsource directive allows you to mark part of a source file as having been generated from another file. (E.g, an Inform 7 source file.) This directive is new in 6.34.

Origsource "Filename";
Origsource "Filename" 10;
Origsource "Filename" 10 40;
Origsource

This declares that all following lines are derived from the given filename. This will be reported in error messages and debug output. You may optionally provide a line number and a character number within the line (10 and 40, in these examples).

The declaration holds through the next Origsource directive (but does not apply to included files). The fourth form, with no arguments, clears the declaration.

Replace

The Replace directive (§25) allows you to redefine a function which has already been defined (such as in a library or in the veneer).

[The DM4 says that you can only replace functions in files marked with the System_file directive. This limitation has been removed.]

The Replace directive has two forms, of which the second is new in 6.33:

Replace Func;
Replace Func OriginalFunc;

Multiple definitions of Func() may follow the Replace directive. Func will refer to the last-defined version, except that definitions in normal files are preferred over definitions in System_file files or the veneer. With the second form, OriginalFunc will refer to the first-defined version of the function.

Undef

The Undef directive allows you to remove a previously-defined constant. This directive is new in 6.33.

Undef Const;

This leaves the Const symbol undefined. If Const was never defined, this does nothing.

Statements

The action statements <Action> and <<Action>> (§6) now support up to four arguments. The four-argument form is new as of 6.33.

<Action>
<Action Noun>
<Action Noun Second>
<Action Noun Second, Actor>

All provided arguments are passed to the R_Process() veneer function.

[As in previous version of Inform, the Action argument can either be a bare action name or a parenthesized expression which produces an action value. Thus, <Take lamp> and <(##Take) lamp> are equivalent.]

[This statement does not follow the traditional IF command syntax, which would put the actor first: "ACTOR, ACTION NOUN". Inform's lexer is not able to handle that ordering consistently, so the statement has to put the actor last.]

The capitalized (A) print token joins (a), (The), and (the) as of 6.30; see §26.

print (A) lamp;

This calls the CInDefArt() veneer function.

Glulx support

The ability to compile a Glulx game file (the -G option) was introduced in 6.30. This came with a few additions to the Inform language.

One of the constants TARGET_ZCODE and TARGET_GLULX is always defined. These can be used with the Ifdef directive to mark code that should only be compiled on one platform.

The constant WORDSIZE is always defined; it is 2 in Z-code and 4 in Glulx.

As noted above, code under the Ifv5 directive is also compiled for Glulx.

Language features supported only in Glulx

If the first argument to a function is named _vararg_count, arguments will be passed on the VM stack, with _vararg_count set to the number of arguments.

Literals beginning with $+ and $- are compiled as floating-point constants. For example: $+1.0, $-1e3, $+2.5e-3. The constants FLOAT_INFINITY, FLOAT_NINFINITY, FLOAT_NAN are also defined.

[Note that the standard Inform arithmetic operators (+, -, etc) do not work with floating-point values. You must use Glulx opcodes (@fadd, @fsub, etc).]

The print_to_array() method (§3.12) requires two arguments, rather than one (as in Z-code).

Language features not supported in Glulx

Module compilation (the -M option, §38) and Infix (the -X option, §7) are not available.

The Zcharacter directive (§36) is not available, since Glulx does not use the ZSCII character set.

The save, restore, and read statements (§1.15, §2.5) are not available. These features require more complex behavior in Glulx and cannot be encapsulated in a single statement. They must be implemented in library code using the @glk opcode.

Z-machine V3/4 limitations

Early releases of Inform (through Inform 5) were designed to support all versions of the Z-machine from 3 through 6. However, Inform 6 extended the language in ways which require more advanced VM support. Therefore, certain language features require Z-machine version 5 or later.

You can work around the lack of obj.prop() by writing:

addr = obj.prop;
addr();

In general, Inform 6 is able to compile older source code to V3 if the source and the library avoids the obj.prop() syntax. This means you cannot use the Inform 6 library. You must use the Inform 5 library, or one of the alternative libraries designed for V3, such as metro84 or PunyInform.

[It is possible to re-implement a limited version of obj.prop() for V3 by replacing the CA__Pr and Cl__Ms veneer routines. Some alternative libraries do this.]

Bugs

A great number of bugs have been fixed since Inform 6.21. The list is not included here. See the Release Notes for details.

Particular thanks to Daniel Fremont for the many bug reports uncovered by his input-fuzzing project.