13 What little I remember
----------------------
13.1 Publication history
-------------------
The language has existed in the following different forms on the Internet:
Inform 1 v0.5 April 30th 1993
Inform 2 v0.6 (I can't find any record of this date)
Inform 3 v1.0 November 17th 1993
Inform 3a December 7th 1993
Inform 4 January 20th 1994
Inform 5 June 1st 1994
Inform 5.1 June 12th 1994
Inform 5.2 June 19th 1994
Inform 5.3 (released on an "Acorn User" cover disc)
Inform 5.4 October 2nd 1994
update later in October 1994
Inform 5.5 v1501 late May/early June (private circulation)
v1502 June 30th 1995
Inform 6 v6.01 April 30th 1996: declared a "beta" release
v6.02 May 5th 1996
v6.03 May 10th 1996
v6.04 September 12th 1996: declared no longer "beta"
v6.05 September 24th 1996
Inform 6.1 v6.10 December 16th 1996
v6.11 January 27th 1997
v6.12 March 26th 1997
v6.13 April 5th 1997
v6.14 September 8th 1997
v6.15 March 22nd 1998
Inform 6.2 v6.20 December 10th 1998: declared a "beta"
v6.21 April 30th 1999
There have been a few other very slightly modified states, consisting of
bug fixes and source code portability improvements on the above (e.g.
Inform 4 went through a fairly long process of tidying-up once it reached
the porters), and a number of CD ROM releases.
This base of users has continuously grown, from size 1 (myself) to what at
time of writing is a very large group of at least casual users and a group of
perhaps 50 "serious" ones whom I actually know. Inform's early versions were
very hard to use, as will become clear, and only attracted attention because:
(a) it did something undeniably "cool", to aficionados of 1980s adventure
games - it revived the Infocom run-time format, and the early Inform
manuals were for a while the fullest documents on the Web describing
the Infocom format; and
(b) since "Curses" had been written in it, the compiler must at least work.
(Even though the source code for "Curses" has never been made public,
the fact that it was known to exist underwrote the project and made
it seem worthwhile to the many porters who invested considerable time
and effort on initially complex and poorly written code.)
I first posted Inform to the Internet in the spirit of "glasnost" rather than
with any pretension that it would be a widely used program. (It worked for
me, which was all that was then required.) By mid-1994 my ambitions for it
had grown: in looking back, that first year is the interesting one.
13.2 Design history
--------------
Inform was designed specifically as a language to express programs which
would run on the Z-machine, a run-time format which already existed. In
turn, the Z-machine was designed specifically as a run-time format for
an existing language (ZIL, or Zork Implementation Language, a form of MDL).
Inform is therefore the result of a game of Chinese whispers, since I had no
idea what ZIL looked like until much later.
In fact Inform and ZIL are entirely dissimilar. One reason for this is that
ZIL is syntactically a very high-level language, not unlike LISP, and its
compiler (ZILCH) made a substantial translation down to Z-machine level:
whereas Inform was designed very close to the Z-machine level. It is often
remarked that Inform resembles C, and although this is partly because some
syntax conventions were borrowed from C by a designer who felt comfortable
with it, another reason is that both languages were designed for easy
translation to efficient low-level code.
Inform began as an assembler called "zass", whose syntax continues to exert
a (perhaps malign) influence on the language of today. The zass assembly
mnemonics were different from the modern set (this was at a time when no
standardisation of opcode names had taken place), and were copied from the
set of names output by Mark Howell's disassembler "txd". (The opcode
names recognised by Inform were tinkered with until Inform 5 when the standard
set was agreed.) But the format of routines and labels remains. A typical
"zass" routine looked like this:
[ Routine v1 v2 ... vn
an assembly line
.alabel
another assembly line
]
and semicolons were introduced as line separators when "zass" became Inform
1. Individual assembly lines then took the form
opcode operand1 ... operandn store;
(if they were store operands), with no syntactic indication that the last
operand was not really an operand but a store destination. This persisted
until Inform 5, and is still recognised in Inform 6, though the preferred
syntax is now
opcode operand1 ... operandn -> store;
Right up until Inform 5, similarly, "sp" was a reserved word meaning "the
assembly-language stack pointer", preventing its use as a local variable
name (for example). Only in Inform 6 has it disappeared from the set of
reserved words (except in the context of assembly lines).
One of the most unusual features of Inform is its handling of local variables
to functions, in that
(a) functions can be called with any number of arguments;
(b) there's no specification by the programmer of any expected number
of arguments;
(c) local variables and argument-receiving variables are treated as
the same;
(d) there are at most 15 local variables per routine.
All four arise from the fact that this is how Z-machine programs behave:
these were the rules for zass, and they're still the rules for Inform 6.
It's efficient to identify Inform's idea of local variables with the
Z-machine implementation of locals; nevertheless, the decision to do so
was made by default.
This illustrates a general point about restrictions in the Inform syntax.
The Z-machine is rich, well-equipped with features making it a good target
for compilation. It implements, let us say, feature F subject to a modest
restriction (for example, it implements local variables subject to a limit
of 15 per routine). Since this is good enough for most purposes, and
efficient, and easy to compile to, an early release of Inform decided to
make use of the Z-machine's implementation directly; and consequently the
design of the Inform language was shaped around the restriction needed
to make it possible to use F.
In other words, if a sparer "RISC" target machine had been chosen, Inform
would have been obliged to make a new implementation of feature F, which
would not have been subject to arbitrary Z-machine restrictions.
Perversely, it is therefore Inform's greatest weakness (as well as its
greatest selling point) that it compiles to the Z-machine. At least, though,
there is a not inconsiderable reward from using the Z-machine's features
so directly: compact and fast code results.
In any case, the history of Inform is a continuous process of syntax moving
away from direct expression of the Z-machine and towards a higher-level
description of a program.
Something that partially frustrated this was that Inform acquired a serious
user base "too soon", before the language design was mature enough: by Inform
4, a good many people were using Inform, and this began to make me nervous of
changing the established syntax. But if a syntax feature is clearly "wrong"
(that is, anomalous and inconvenient) then clearly one must bite the bullet
and make a change. In retrospect, I feel I have always been too hesitant
over this.
For example, I realised when working on Inform 5.1 that the notation
print "You swallow ", (the) food, " with glee.";
to mean "print the name of the object whose number follows, preceding it
by a suitable definite article", would be desirable. But I had wanted
Inform 5 to be a point of stability, not rapid change, and so I shied away
from adding this feature (besides, I was worried about complicating the
interaction between the library and the language itself). I did not in fact
add the feature until Inform 5.5, but it would have been easier for all
concerned had I done so earlier.
The moral to draw would be that any really big changes still needed ought
to be made now. Unfortunately, they are just too big (the syntax for
character and dictionary literals, for example, or for array and property
value initialisation) and so I have failed to learn my lesson, after all.
Another problem with an evolutionary design is that vestigial features tend
to survive, especially if one is trying to serve a user base who may still
be using old syntaxes. (For instance, using old library files of code.)
A problem P, say, is given a crude solution S1 in 1993, a slightly better
solution S2 in 1994 and a proper solution S3 in 1995. By this time, does
Inform still have to recognise the syntaxes applying to S2 and S1? Usually
I have decided to make it do so; the formal concept of an "obsolete usage"
(which would be recognised but cause "please change this" warnings to be
issued) was not added to Inform until 5.5.
For example, how do we set a property value? In Inform 1, by using a line
of assembly code:
put_prop lamp oil_left 15;
By Inform 3 this had become painful, and a shift away from assembly language
was taking place, but not a drastic one. The statement "write" was devised
for writing a sequence of property values (in this example, just one):
write lamp oil_left 15;
(Even this existed partly because of a horrid form of "object recycling"
present in Autumn 1993 forms of "Curses" and very early drafts of "Jigsaw",
causing objects to be heavily over-written: it became necessary to change
many properties in one go. The "write" statement was a great help.)
Only in Inform 4 did the C-like form appear:
lamp.oil_left = 15;
And not until Inform 6 was it possible to apply ++ and -- to a property
specified in this way. Likewise, only in Inform 6 was the "write" statement
finally withdrawn from recognition, though it was flagged as obsolete in
Inform 5.5.
Such obsolete syntaxes do not merely increase the "clutteredness" of the
language; they also block more desirable syntaxes by causing clashes. And
the tendency to provide partial solutions to problems has been unfortunate
in putting off the point where significant change is needed. I did not
realise in "zass" that a notation was needed to refer to dictionary words
as operands of opcodes, automatically creating them if need be; then I did
realise this, in Inform 1, but made a directive called "Dictionary" to set
constant symbol names equal to their dictionary addresses; in Inform 3,
I found this was cumbersome and instead used the syntax #n$... to indicate
"new dictionary word" (it seemed logical since #w$... was being used for
"existing dictionary word"); in Inform 5, the syntax '...' was used, and
this was perhaps a mistake, since it clashes slightly with the syntax for
specifying literal characters.
If I had realised at Inform 1 that a syntax was needed, this would have been
avoided. As a footnote, #n$... is still present in the language; #w$...
and "Dictionary" were finally deleted in Inform 6.
A happier point of view on this evolution is that, at every stage, the subset
of Z-machine features which Inform could use expanded. Inform 1 could produce
only version 3 games; Inform 4 was a major breakthrough in making version 5
games; and so on. (V5 did not become the default version compiled to
until Inform 5, but this reflects a lack of confidence in the interpreters
for high-version-number Z-machines then available.) And an evolved syntax
is at least adapted to what its users want of it.
(i) Inform 1 and 2
--------------
Inform 1, then, was the assembler "zass" rewritten and with certain shorthands
added. For example,
var = number operator number;
was permitted, though full expressions were not. Most of the "creating"
directives were present -- Object, Global, Property and Attribute -- though
directives were not syntactically distinguished from statements, and could
be mixed freely. Nor were statements distinguished from assembly lines:
indeed, most of them were assembly lines.
In addition, control structures were provided:
if ... else ...
while ... ...
do ... until ...
These took their modern form, except that conditions did not need to be
bracketed, and braces were compulsory around all code blocks, even those
which contained only one statement. A form of "for" loop was provided,
but took the BASIC-like form "for var 1 to 10". (This syntax existed
alongside the modern "for" syntax until Inform 6.)
Grammar and actions existed in their modern form from the first (except
for the <...>, <<...>> notation for causing them). Object definitions took
their modern form (except that specifying a parent was compulsory, there was
no "class" segment and routines could not be given as property values).
And that was about all. The language appears from this description to be
very primitive, and it was, but it was not so different in appearance from a
"real" language (except for the lack of compound expressions) and "Curses"
was written in Inform 1 code for about two years before being translated
into modern syntax.
Inform 2 was only a tidying-up release of Inform 1.
(ii) Inform 3 and 3a
---------------
Inform 3 was a more substantial upgrade, with various worthy features
(command line switches; control over header flag bits) added. But the
driving force was that "Curses" was being expanded, and running severely into
the limits of the Z-machine Version 3 architecture: in particular, the limit
of 255 objects. "Curses" apparently needed a minimum of about 270: Richard
Tucker suggested to me that there was no need for the 255 physical Z-machine
objects to correspond directly to the 270 game objects. So the idea of
"recycling" was born. Object O might be a carpet in one room and a door in
another: as long as it was impossible for these ever to be simultaneously
present. When either room was entered, everything about O was over-written
to make it the appropriate definition.
This made it necessary to be able to drastically alter objects. The "write"
statement (see above) was introduced to fix properties, a syntax #n$...
was introduced to refer to dictionary words (because so many were needed as
property values to over-write with) and the @.. string escape was added
to make use of the Z-machine's abbreviations table, with the "string"
statement added for changing entries in it. (This last made it possible for
the apparently unalterable object short-name to consist of a string reading
"print abbreviation 1", so that by changing abbreviation 1 it was possible to
effectively alter short names.) Finally, object declaration syntax was
altered to make it possible to give the same object more than one symbol
name.
In retrospect this substantial effort to break the game-object Z-object
correspondence was misguided; the proper solution to the problem was to make
Inform Version-5 capable (as happened in Inform 4). It ought to be
remembered, though, that at this time many people were using Version 3
interpreters not capable of running Version 5 games (indeed, the Version 5
release of "Curses" was one of the nudges towards a wider awareness of
Version 5 and the interpreters capable of running it). Inform hung back
because interpreters were not ready; yet as events turned out, interpreters
became ready partly because of Inform overtaking them.
Inform 3a was a tidying-up release of Inform 3.
(iii) Inform 4
--------
Inform truly became a high-level language, rather than an assembler with
delusions of grandeur, only with the release of Inform 4.
The important new addition was a full expression evaluator, recognising
operators (and an expanded set of these, including for instance ++ and --),
precedence levels, brackets and so on. Conditions were also permitted to
be compound, using the new logical operators && and ||. Properties could
be referred to using the new "." operator (along with ".&" and ".#").
System functions (such as "children" and "random") were added.
This was the decisive break of the correspondence between Inform statements
and Z-machine instructions: expressions no longer looked like three-address
code by any other name, and might compile to arbitrarily long sequences of
instructions. Opcodes like "random" were no longer accessed directly, but
via system functions.
The most annoying syntax point remaining was that braces were still
compulsory. A typical Inform 3 line might have been:
if i == 2 { print "Two"; }
This restriction was now lifted. Implementation considerations
(specifically, in the source line-reader which fed into the tokeniser) meant
that some indication was needed of where the condition ended, and so brackets
were imposed on conditions. Thus, the corresponding Inform 4 line:
if (i == 2) print "Two";
Making the parallel with C even closer, new-style "for" loops were
introduced:
for (i=0:i<10:i++) print i;
(and the desire to make Inform capable of compiling "for" loops as complex as
those available to C caused the operators ++, -- and , to be added). More
originally, "objectloop" was added.
Although it had little impact on the syntax, to the outside world the major
development was that Inform was now capable of compiling Version 5 files
(which had no limit on object numbers and could be twice as large as Version
3 ones). The main impact of this on the language (which I now regret) was
that statements like "box" and "style" were added to control newly available
text features of the Z-machine.
Otherwise I took the decision that in principle all Inform programs should be
cross-compilable to all versions (subject to the limits applying in each
version), and this remains substantially true. Since certain game operations
such as saving, loading and reading the keyboard were commanded by very
different assembly language in versions 3 and 5, these were abstracted into
statements so that, for instance, what looked like version-3 assembly
language to read the keyboard would in fact be compiled to appropriate but
different version-5 assembly.
(iv) Inform 5
--------
The final stage in Inform's arrival as a programming language took place a
little over a year after Inform 1's creation. Only then did I look back in
leisure at the language, and only then did I begin to seriously find out about
the rival adventure-game languages to see what they were capable of. I was
unimpressed except by TADS (which I continue to have a great respect for):
the point was rubbed home when I was adapting the original mainframe
Adventure, "Colossal Cave", to Inform for use as an example. Dave Baggett's
TADS translation was constantly at my side, and it became obvious that the
corresponding Inform 4 code was far less legible.
In some ways, then, the Inform 5 syntax was worked out by constructing the
language so as to make the implementation of "Advent" look neat.
Although Inform had, from the first, associated code closely with objects
(the concept of before/after routines was part of the original conception),
only now was this brought out in syntax by making explicit routine definitions
property values. (Previous code had been full of property values like
"FireplacePre", which were names of what would now be called before-routines.)
The syntax now seems obvious and natural, but at the time it felt like a
breakthrough: what had been broken through, I think, was the residual feeling
that Inform was an assembler at heart, whose programs were a list of routines
interspersed with some overgrown variable definitions.
Class definitions (and the inheritance rules) followed in the same, somewhat
bewildering, couple of days, and a brace of aesthetic changes followed:
dictionary words written 'thus', ##Names for actions (rather than the
previous #a$Name syntax), the use of bare strings as implied "print_ret"
statements. Most importantly, the use of <...> and <<...>> to trigger
actions, and the implementation of what amounted to a switch statement on the
current action within embedded routines.
I have come to realise that adventure game programs are unusually dense in
selections and comparison against lists of alternative possibilities. Inform
now contains many syntaxes to make such comparisons concise:
switching on actions in embedded routines;
the "switch" statement (added in Inform 5.5) - note that both of these
deliberately take a more concise form from, say, C, by not allowing
case fall-through and therefore not requiring the incessant use
of "break" statements;
switch ranges such as "5, 7, 8 to 19: ...";
the "or" alternative operator in conditions, as in "if (x == 1 or 5) ...".
And this, I feel, is something for which I should make no apology.
Later developments (in 5.5) included the Array directive (previously, it was
customary to use global variables to point to arrays) and the printing
syntaxes for "print (The) ..." and so forth (see above). An extension was
made to "Versions 7 and 8" (new hybrids of the Z-machine allowing larger
games to be compiled), though this had little impact on the language or the
compiler.
The release of Inform 5.5 notwithstanding, the language remained essentially
stable during the two years between Inform 5 and Inform 6. For the first
time it became possible for people other than myself to seriously use Inform,
rather than toy with it. From Inform 5 onwards, the issue has not been
adequacy of the language but adequacy of its documentation, and I think this
is the point where Inform can be counted a "proper" language.
13.3 Implementation history
----------------------
Writing a compiler for a large language from scratch requires glacial
patience, but the result is a mountain. The time invested in tedious details
during development is repaid ten times over when the compiler comes to be
used. Temporary measures are infernal temptations, and must be rejected
firmly.
Inform was not written this way.
The compiler has been through three "design iterations": "zass", which was
discarded as soon as I thought I had understood how the Z-machine worked,
Inform 1 to 5.5, and now Inform 6. This section briefly describes the second
iteration.
Inform 1 was essentially a program for translating assembly language lines
into Z-code statements. It made the generous and unjustified assumption
that its input would always be well-formed except for the odd spelling
mistake, and did not check syntax particularly carefully: lexical analysis
consisted of grabbing a line from the source code files (accessing these
files a byte at a time, in an unbuffered way) and cutting out white space
to leave a set of tokens. Syntax analysis consisted of going through
these tokens until a line seemed to have worked out all right, and then
forgetting the line altogether (never checking if there were any more tokens).
This caused an enormous number of little jobs later, testing for error
conditions like "expected a semicolon after ... but found ..." in a quite
unsystematic way.
Not only was there no formal apparatus for syntax analysis, but lexical
analysis went on all over the place, with strings being cut up and compared
against the symbols table erratically (and often repeatedly). Tokens were
stored as strings (with all the consequent inefficiencies of manipulation).
Direct string comparisons were commonplace, making it difficult to pin down
what the set of reserved words was, and indeed almost impossible to write
a precise definition of what programs would pass Inform syntax checking.
When statements required translation into code, this translation would
actually be made into textual assembly language instructions, fed back into
Inform via a "preprocessor". (As Inform became more elaborate, this
preprocessing might take three stages: high level code such as "objectloop"
constructs being knocked down to equivalent "while" statements and then to
assembly language lines.)
In order to cope with the problem of forward references to labels, Inform
made two passes through its assembly language source, which is fairly standard
behaviour for assemblers (because it is easy to implement and has low
memory overheads). Yet it became a more and more nightmarish process to
ensure that high-level constructs would always translate into identical code
on pass 1 and pass 2, and ever more clear that great effort was being made
to do a long and difficult calculation twice, burning the result the first
time.
Given all this, the wonder is that Inform worked at all. In fact it worked
rather well, after a couple of years of polishing and optimisation: although
slow in theory, profiling runs suggested that the process of translating into
textual assembly language (for instance) was not a significant speed loss
(since opcodes could be textually recognised very quickly, while the work
in parsing operands had been deferred from earlier on, and would have to have
been done anyway). Inform performed very rapidly in terms of compilation
time per source line when compared to typical commercial compilers (which,
to be fair, were compiling more complex languages) and was unusually low
in memory consumption.
This last was a serious issue when Inform was released, as many users were
running it on machines like 0.5M Amigas. Without a grown-up syntax analyser,
there was no need to store large parse trees (such as most compilers do for
entire routines at a time: the performance of most compilers seriously
degrades as the length of a single routine increases).
From Inform 1 to 5.5, the main algorithms and issues never changed, despite
much reorganisation, renaming, rewriting and extension. But after two and a
half years, it had clearly "rusted" badly: it was difficult to maintain or
work on. Bugs were appearing which seemed ridiculous in a program so
established and widely used: for example, not until 1995 did anybody realise
that division had been accidentally programmed as right, not left associative
(thus "12/6/2" evaluated to 4, not 1). An endless mass of ad-hoc rules was
being added to cover up the lack of proper lexical analysis. Moreover, the
major new feature -- the linker -- added another massive complication to an
already convoluted piece of code. (I have by now designed and painfully got
working three different versions of the linker, and would not go through all
that again for all the tea in China.)
What began as a general tidying-up and bug-fixing exercise sank into the
depressing realisation that a total rewrite was the only way to make
significant progress. Six months later, the writing of this sentence finally
completes that task.
13.4 Modification history
--------------------
(i) Changes made between v6.01 and v6.02
------------------------------------
Features added:
"Declared but not used" and "no such constant" errors now reported on or near
line of occurrence, not at end of source.
Error message added for local variable being defined twice for the same
routine
Bugs fixed:
"Segmentation fault" (i.e., writing memory out of range) fixed to do with
symbol flags being set wrongly
Constant binary numbers not lexed correctly
"for (p = 0::)" misinterpreted due to "::" being recognised as an operator
Backpatch error under RISC OS (and possibly elsewhere) when linker used
Grammar token routines reported as "declared but not used"
Grammar token routines not working at run time
"ofclass" failing to recognised inherited class membership
Inheritance of negated attributes not working
"children" function giving the wrong answer (specifically, always giving the
object number of the first child); this had the knock-on effect of
making the "tree" debugging verb produce incorrect output
Source code cleaning:
Header file rearranged to typedef int32 in the right place, and tidied
up a little; ICL_Directory defined rather than left to cause an error
when Inform is compiled; INFORM_FILE replaced with MAIN_INFORM_FILE
in some of the OS definition blocks; SEEK_SET defined rather than left
to the vagaries of ANSI
Type clashes between int and int32 reconciled for:
assemble_label_no, routine_starts_line, read_byte_from_memory_block,
write_byte_to_memory_block, parse_label, symbol_index
Return value for hash_code_from_string cast explicitly to int (rather than
implicitly from unsigned int)
prec_table given type int
Many "dead assignments" (redundant settings of variables) removed
"=-" replaced by "= -" to prevent pre-ANSI compilers from misunderstanding
"x=-1" as "x=x-1"
The veneer string for the source of "CA__Pr" has been contracted to make
it smaller than 2048 chars long, since Microsoft Visual C/C++ won't
compile strings longer than that
symbs[] explicitly cast to char * in a few points in "linker", "objects" and
"symbols"
Format string for process IDs corrected from "_proc%08x" to "_proc%08lx"
Format string for serial number copying removed, and a use of strcpy put
in its place
(ii) Changes made between v6.02 and v6.03
------------------------------------
Feature added:
The on/off command-line switches can now be prefixed with ~ to turn them off.
(This is useful only in ICL, to undo the effect of previous lines.)
Bugs fixed:
The "my parent is Class" value in modules changed from 0xffff to 0x7fff to
make it valid in type int (rather than int32)
The "spaces" statement not being parsed correctly (bug in syntax analyser)
Arrays declared using Global rather than Array don't work (this is fixed,
but also now causes an obsolete usage warning)
Fclose applied to null file handle (effectively, the same file closed twice)
"for (::p++)" misinterpreted due to "::" being recognised as an operator
Some -> -> object initialisations getting the structure wrong
Table of property names wrongly compiled (resulting in garbled run-time error
messages)
Serious failure of individual property inheritance from a class when both
inheritor and class define individual property values
Messages sent to a property whose value is NULL now do nothing and reply 0
(as if the property value were 0)
Action switches not working in properties called via messages (well, not
really a bug: but it's better that they should work, as this makes it
possible to call "before"/"after" as messages)
The "children" inlined routine leaving redundant values on the stack (which
resulted in complex expressions containing uses of children()
mis-evaluating)
Actions in the form and using a call opcode improperly (with
possibly regrettable results -- though they worked on my interpreter!)
ICL files not working (due to a bug gratuitously introduced in v6.02), and
not understanding tab characters as spaces, and generally being poorly
implemented (I found print "Err..."; in the code, to my alarm): generally
tidied up now
Negative constants not working as switch() case values
Slightly better reporting of bad statement errors, and slightly better
recovery
Source code cleaning:
Calls to get_next_char() replaced with (*get_next_char)() which is equivalent
to a modern ANSI compiler, but inequivalent to a pre-ANSI one
Logically redundant "break" statements added to parse_routine() to prevent
either "unreachable code" or "no return from non-void function" warnings
being produced
parse_given_directive() has its unnecessary parameter removed
uchar types used for characters as read in by the lexer before filtering takes
place to, e.g., strip off any set top bits
(iii) Changes made between v6.03 and v6.04
------------------------------------
Features added:
When double-quoted text is continued from one source line to another, and
the first ends in ^, then the new-line is not replaced by a space " ".
Thus: print "Shall I compare thee to a summer's day?^
Thou art more...";
results in the "T" being printed underneath the "S", not one space to the
right.
Statements like
"The wyvern swallows ", (the) noun, " in three gulps!";
are now correctly understood to be print_ret statements. (Previously
this gave errors because the syntax analyser thought it was going to
be a list of three switch cases separated by commas, until it hit the
semicolon and realised there should be a colon, by which time it was
too late to go back. The language definition has never been clear
on whether long implied print_rets are legal or not, so I've decided
that they are.)
The #n$ construct (for single-character dictionary words) can now take
non-alphabetic characters: e.g., #n$1 and #n$# refer to dictionary
words '1' and '#'.
Bugs fixed:
The Verb "newverb" = "oldverb"; syntax not working, due to mistake in syntax
analyser (or rather, to inadequate testing)
If routine R is being Replaced, then its new definition can now appear either
before or after its Library definition (as long as the Replace declaration
occurs before both definitions). In 6.01 to 6.03, errors would result
if the new definition was earlier than the Library one.
Constants not being allowed as switch cases when they happen to be the same as
internal statement keywords (such as the single letter "a")
Memory allocations of 0 bytes now return NULL, which protects Inform from
trying to apply "free" to them, which seems to have caused problems on
some ports (not on mine, but it was my mistake)
Spurious "Second 'Ifnot' in same 'If...'" errors appearing in certain
nested 'If...' configurations
A comma in between object headers and bodies is now optional once again (as
it used to be in Inform 5), rather than forbidden.
Text or commentary appearing after a string folding character \ now causes
an error, as it should (the rest of such a line should be empty).
"continue" not properly working inside a "for" loop of the "optimised" kind
(that is, whose update code consists of just variable++ or variable--)
For two different reasons, "or" did not quite work when used in its
extended way (i.e. with conditions other than ==, ~= or with many
alternatives): apologies, as the code was in a muddle. Better now.
Class classname(N) ... was allowing creation of only N-1 new instances,
not N.
(a) not recognised as a print specification when "a" is also the name of
a local variable.
"youngest" function failing to work.
Source code cleaning:
Header declarations of the variables "mv_xref" and "no_stubbed_routines"
removed (neither one actually exists in the released state of Inform 6)
Miscellaneous comments added
Assembly of store opcodes optimised to pull opcodes in a few cases, saving
1 byte of object code each time
Hooks for Robert Pelak's MAC_FACE port (traditionally the most strenuous)
inserted
Error messages reworded slightly for better consistency
(iv) Changes made between v6.04 and v6.05
------------------------------------
Feature added:
Assembly language tracing slightly tidied up (a cosmetic change only).
Bugs fixed:
When a file with very long strings in (such as one generated automatically
by "infoclues") is read, it can corrupt memory, resulting in the malloc
heap being damaged.
Spurious backpatching errors (actually, all backpatching errors are spurious -
backpatching is supposed to work every time) produced when the Z-code
area of the Z-machine exceeds 64K. (This seldom happens even in large
games, unless quite long print and print_ret strings are quoted.) The
error message in question was
*** Backpatch symbol out of range ***
and, just to recap, this should never appear. Please send me the
offending source code if it persists!
The only time I've seen this bug is that it once hung the Z-machine while
working on printing an inventory of items which needed grouping using
"list_together", but it's actually a mistake in the shift-reduce
expression grammar: "(...)" (function call) has precedence level 11,
whereas "." has level 12, in order to make messages
object.message(...)
parse correctly (i.e., as (object.message)(...)). This isn't usually
done in SR operator grammars because, as I now realise, it results in
function(X).property
being misinterpreted as function(X.property). I've corrected this by
giving (...) the asymmetric precedence level of 11 on the right, but
14 on the left.
Printing dictionary contents to a text transcript file not working on the
Amiga port, since an internal buffer was overwritten by one byte
(5x16+1 = 81, not 80).
Spurious "variable declared but not used" warnings appearing for a variable
used only as a store destination in assembly language.
The "box" statement producing boxes of the wrong width when the text contains
the @ escape character (e.g. "@@92@@92@@92" used to be wrongly
calculated as 12 characters wide, when it really consists of three
backslash characters).
The v6.04 optimisation using "pull" (see above) didn't work in v6, v7 or v8
(for two different reasons, but basically because the opcode behaves
differently in these as compared with lower versions).
Assembly language in v8 recognising the wrong instruction set (same as
the previous bug).
Version 6 games not properly compiled in some cases (because of a rounding
error in calculating packed address offsets: a new section 8.8 has been
added to this manual to document how Inform works these out).
"I compiled Inform 6.05 under Purify, and am pleased to report that Purify
reported exactly 0 memory access errors and 0 bytes of memory leaked."
-- Brad Jones
(v) Changes made between v6.05 and v6.10
------------------------------------
Features added:
The four ICL path variables which define places to look for input of
different kinds (source code, include files, ICL files and modules)
can now hold lists of alternative locations, separated by a character
called FN_ALT which may be OS-dependant (but is normally ',').
These alternatives are tried left-to-right until the desired filename
is found. It's legal for an alternative to be empty, meaning the
current position (e.g. "+include_path=,library,oldlib" gives three
possible paths -- the current directory, then the library and oldlib
subdirectories). The on-line examples (in the -h1 help information)
now include this new feature.
File and pathnames in ICL and on the command line can now contain spaces
if written inside double-quotes: e.g., "Games Folder/New Games" would
be a valid ICL pathname. (Provided for benefit of Macintosh users.)
A new error message format, -E2, uses Macintosh Programmer's Workshop style.
Output game files in the MPW port are given the type and creator for the
MaxZip interpreter. (With thanks to Tom Emerson for supplying details.)
The compiler can now generate a new format of grammar table: if used with
old code, it will behave just as it used to, but if used with Library
6/3 or later will generate "GV2" (grammar version 2) tables. Users
will notice that several restrictions are lifted, most usefully:
the number of tokens per grammar line can be up to 30, not up to 6;
the total number of prepositions is now unlimited (it used to be
limited to about 80);
the total number of routines named in grammar tokens is now
unlimited (it used to be limited to 32);
the total number of actions per game can be up to 4096, not 256.
(Chapter 8 above has been rewritten to document GV1 and GV2 in full.)
In addition, there are three new grammar features:
(a) you can mark an action as "reverse", as in the following example:
Verb 'show' 'present' 'display'
* creature held -> Show reverse
* held 'to' creature -> Show;
"reverse" indicating that the two parameters are to be reversed
in order before the action is generated.
(b) you can give two or more prepositions (only) as alternatives:
Verb 'sit' 'lie'
* 'on' 'top' 'of' noun -> Enter
* 'on'/'in'/'inside' noun -> Enter;
the "/" markers indicating alternative prepositions, any one of
which is equally good.
(c) there is a new grammar token called "topic", which matches any
block of text up to the next preposition or the end of the input.
For instance,
Verb 'read'
* noun -> Examine
* 'about' topic 'in' noun -> Consult
* topic 'in' noun -> Consult;
It's used mostly for reading material and subjects of conversation,
hence the name "topic". For how to deal with the results of parsing
a topic, see the Designer's Manual on "Consult".
These three features are only available when using Inform in conjunction
with Library 6/3 or later.
The run-time veneer's implementation has been rewritten, especially in the
areas of message-sending and superclass access. Several benefits:
(a) the :: superclass operator can be used with any property
(in Inform 6.05 it only worked with individual properties);
(b) it makes sense to look up or send to
something.Object::cant_go
and this refers to the default value of "cant_go". (So we can
think of common properties as being exactly the ones inherited
from class Object.)
(c) printing out a property name, as in
print (property) Crown::colour
now correctly prints "Crown::colour". (Previously it got stuck
on superclass properties.)
(d) the limits on numbers of things are made more sensible. These
are now as follows:
(i) up to 256 classes per game;
(ii) up to 128 different individual properties (and up to 63
common properties) can be provided by any single object;
(iii) up to 32703 individual property names throughout the game.
These limits are now enforced by the compiler, which used to
lazily not check them.
(e) in games using the Inform library, when the variable debug_flag
has bottom bit set (the Inform library does this when the
"routines" verb has been typed), all messages are traced to
the screen. (Except any messages caused as a result of trying
to perform this printing.) This is fuller and more helpful
than the old "routines" output.
(Several parts of chapter 9 above have been corrected.)
The dictionary data structure is entirely redesigned, as a red-black tree
rather than a hash table. The effects of this change are localised
to "text.c" (i.e., no other source files were modified to achieve it).
For small games no difference will be noticed; for large games there will
be a slight speed improvement, becoming more noticeable as the game grows.
(E.g.: on my machine "Curses" compiles 4% faster.) See Section 8.4 above
for details.
As part of a general move toward multilingualism, the notation for dictionary
words is extended: 'word//letters' means the word 'word' with some flags
attached. At present, the only such flag is 'p', meaning "plural".
Note that 'word//' is legal and equivalent to 'word'. Thus, 'w//'
is another way of making the dictionary word #n$w (which we can't write
as 'w' because that's only a single character).
(This information is stored in a previously unused flag in #dict_par1:
see the bitmap in section 8.5 above.)
Dictionary words may now contain accented characters (this is likely to be
essential for some Scandinavian languages). It is also now legal to
write a quotation mark within quotation marks, in two cases:
''' (meaning: the literal character ')
'@'etude' (to put an acute accent on something)
To avoid dictionary resolution falling unacceptably when accented chars
are used, it's helpful to move commonly occurring ones into the
Z-machine alphabets: the new directive "Zcharacter" does this.
See section 12.2 above.
The dictionary contents are now given in alphabetical order in text transcript
files, and the "Trace dictionary;" output is much more descriptive.
Tracing output for calls to functions marked with a * is more legible,
giving exactly the arguments supplied and naming embedded routines
more sensibly (e.g. as "lantern.time_left" rather than "Embedded__43").
The -g switch now traces only the user's own functions, not the library
ones, unless -g2 is set.
Inform now checks for the error of giving the same property twice in one
definition. This is not always as obvious as (say) giving the
"description" of an object twice over, because of the existence of
aliases. A typical error message would be:
line 15: Error: Property given twice in the same declaration,
because the names 'initial' and 'when_open' actually refer
to the same property
A warning is produced if the "box" statement is used in a Version 3 game
(since it cannot have any effect in such a game).
The default memory allocation for arrays has been increased (from 4000 to
10000 bytes). The original was too conservative, and anyway more will
be needed for language definition files in library 6/3.
Action and attribute names are now written into story files, so that it's
possible to print them (for debugging purposes). Full details of how
to do this are in section 9.6 above. (Users with library 6/3 may notice
that the "actions" debugging verb now names all actions, not just the
ones defined by the library.)
Inform now allows the three special constants DEBUG, USE_MODULES and
MODULE_MODE to be defined more than once without giving an error.
Thus, if your code contains "Constant DEBUG;" already, but you
compile it with the "-D" option anyway, no error will be produced.
When an object isn't given a textual name, rather than calling it "?"
Inform now calls it something like "(red_box)", where "red_box" is
its internal symbol name. (This makes debugging output easier to
follow and wastes very few bytes.) When the object hasn't got an
internal name either (if it's defined just as "Object;" for
example) it has the textual name "(102)", 102 being its object number.
Bugs fixed:
"Extend only ..." not always parsed correctly, sometimes giving a spurious
syntax error, other times failing to notice "first/last/replace".
In -U mode, failure to report as an error a line consisting of two words, the
first of which is a constant or variable name defined in a previously
linked module. (This arose when the line "Action RevTakeWith" was
accidentally written instead of "Fake_action RevTakeWith" -- what
happened was that "Action" was recognised as the variable "action",
which Inform knew was a symbol exported from a linked module (ParserM);
it took this value as a class, wrongly, and made a new object called
RevTakeWith of this "class". The fault was in the syntax analyser,
which wrongly assumed that it wouldn't necessarily be known whether an
exported symbol was a class-name or not, and so allowed all exported
symbols to be used, just to be on the safe side.)
ICL fatal error messages quoting a garbled filename.
Version 3 games (ah, remember them?) not compiling because of the usage of
call opcodes not present in the V3 Z-machine
The "Include ">name"" feature not working when the original source file
lies at the current working directory of the host OS, rather than in
some subdirectory.
The linker had a rarely-occurring bug which prevented the tasks scoring
system from working properly in a game which linked rather than included
the library modules: if an instruction wrote a value to certain variables
whose internal numbers were in a certain narrow range, then these
variables would not be correctly reconciled with the story file variables
at link time. This same bug possibly also accounts for an even rarer
occurrence, which I've had no definite report of, in which the less than
professional error message "Ooops" is produced. (I've corrected the
error message to something more helpful.)
Rather seriously (though this error took a long time to be found),
if (condition) rfalse; else ... [or the same thing with rtrue;]
producing syntax errors. (A mistake in some optimisation code.)
The "elder" function wrongly returning 0.
Not always reporting errors when global variables were used wrongly as
values of object properties or array elements. (Sometimes a backpatch
error would be given.) These are now properly parsed in constant
context, not quantity context.
Spurious warning about code not being reachable at the close brace of
a "for" loop, when this is indeed not reachable. (It can still be
sensible code, if the idea is always to "continue" or "return"
from the body of the loop.)
When the error "Error: System function name used as value "child"" is
produced, also printing a spurious *** Emit token error *** message.
Backpatch errors sometimes produced when compiling a line (in a module only)
which contains an "if" condition making heavy use of "or".
Code backpatch errors sometimes produced when the condition "ofclass" is
compiled.
'->' or 'Nearby' mysteriously failing if the parent object referred to
was (a) defined in a module and (b) one of the first four objects
defined there.
"Declared but not used" warnings issued for replacements of routines
only accessed from within a linked module.
Error message if a non-existent ICL variable set, not being printed.
Source code cleaning:
A port definition called PC_WIN32 has been added to "header.h", courtesy of
Kirk Klobe.
Two variables made int32 instead of int (thanks to Evan Day for spotting
the desirability of this).
The veneer routines are segmented so that no individual literal string
is as long as 512 characters. (An irritating requirement imposed by
the Macintosh port's compiler.)
Six miscellaneous explicit casts of (char *) to (uchar *), suggested by
Robert Pelak. More systematically, the opcode names in asm.c are all
explicitly cast to (uchar *).
A slight change to inform.c makes the Mac front end's arrangement (of
calling only sub_main(), while main() itself is not compiled) more
generally usable by other ports: see section 2.2 (e).
(vi) Changes made between v6.10 and v6.11
------------------------------------
Bugs fixed:
An important one -- the optimised form of statements like
if (variable) rfalse;
was being negated, i.e., was being wrongly compiled as
if (~~variable) rfalse;
(In Library 6/3, this showed up at one stage as odd behaviour when
moving around in darkness.)
The statement "spaces 0" printing infinitely many spaces instead of
doing nothing. (Negative arguments have always done nothing.) It is
possible to provoke this behaviour in calls to the list-writer.
Bug to do with parsing quoted filenames in ICL.
Spurious "declared but not used" warning for global variables used only
in a module being linked in.
Source code cleaning:
Atari ST definition block updated on advice of Charles Briscoe-Smith.
Copyright dates nudged on to 1997.
Paranoid test added when closing temporary files.
Macintosh interface code added on advice of Robert Pelak.
Two long printfs subdivided to assist poor compilers.
String subdivision in "CA__Pr" in the veneer moved slightly in a way
which makes no logical difference, but which seems to fix a mysterious
problem observed by Robert Pelak (possibly with his compiler: it has
been observed on no other platform).
Text transcript file is now opened as a text file, not a binary file,
which will hopefully assist some ports but inconvenience nobody.
(All the same, it may be worth testing that text transcripts still
look sensible on your port.) Code added to the Macintosh port to
ensure closure of the file if compilation aborts.
(vii) Changes made between v6.11 and v6.12
------------------------------------
Features added:
A new switch, -C, and the ability to read source code files in any
ISO 8859 standard extension to the ASCII character set. The
default is ISO 8859-1, Latin1, the standard character set on
most computers in most European countries. This means that
many accented characters can simply be typed directly, a
particular advantage with exotic ISO ranges (Arabic, Hebrew,
Greek, Cyrillic, etc.). If your computer is unable to use any
of 8859-1 to -9, the -C0 switch (for plain ASCII only) can be
used. Accent markers such as '@:u' (for u-diaeresis) remain
valid, just as usual, but a new string escape '@{..hex number..}'
allows the specification of any Unicode character. For instance
'@{a9}' produces a copyright sign (Unicode values between $0000
and $00ff are equal to ISO Latin1 values), and '@{2657}' produces
in principle a White bishop chess symbol. In practice, if you
wish to use rare Unicode symbols, you'll need an interpreter
obeying the Z-Machine Standard 1.0, and you'll probably have
to supply it with an appropriate font as well; also, any characters
not normally resident in the Z-machine need to be declared in
advance of use with the "Zcharacter table" directive. But if
you're only using (e.g.) ordinary German, Spanish or French
accents the new facilities will work with any Standard 0.2
interpreter.
The "Zcharacter" directive, for configuring the Z-machine to
use non-English alphabets, is greatly enhanced.
(In the Z-machine, Inform now always generates a header extension
table, and sometimes uses a slot within it to point to a Unicode
translation table newly specified in Standard 1.0.)
The debugging information file has finally been brought up to date with
Inform 6, and old code inherited from Inform 5 (the only such
code in the whole compiler) has been cleaned out. The main change
is in producing source-code-to-PC-value maps, which is made more
difficult by the compression of code at the end of each routine.
The exact format will probably change: this release is an interim
one, to assist development of a source-level debugger.
The concept of sequence points has been introduced, likewise.
Bugs fixed:
Not a bug as such, but the veneer implementation has been changed so that
class-objects never have attributes set. In 6.01 to 6.11, a class
object like Monster might have the attribute "animate" and would
therefore be picked up in objectloops over all animate objects, and
so on. This is undesirable, and illogical since after all class
objects don't provide any properties, so why have attributes?
Anyway, the result means that objectloops of the form
objectloop (x has ) ...
will now not range through classes but only genuine game objects.
When compound Boolean conditions are used as expressions (for instance,
in an assignment like "x = (y>1) || d;") the wrong answers could
result if the top operator was ||. (If it was &&, or if the
condition had no &&s or ||s in, or if the condition was being used
as a test rather than a numerical value, everything was normal.)
Fake actions being defined before grammar version is set were causing
mysterious problems. This would happen if the Fake_Action directive
were used before "Parser" is included. An error message has been
added advising that Fake_Action directives should be moved.
(Fake actions are now mostly obsolete anyway.)
Any attributes aliased together being given the unhelpful name
"" in output from the "showobj" debugging verb.
Backpatch *** errors *** sometimes being produced as a knock-on effect
from already-reported linkage errors. (These *** errors *** are
now suppressed if linkage has already broken down.)
The character codes for << and >> (Continental European quotation marks)
were the wrong way around, following a mistake in version 0.2 of
the Z-Machine Standards document. They have therefore been
swapped over, following the correction made in version 1.0 of that
document.
Accented characters deep inside dictionary words sometimes getting lost.
(Because of an ambiguity in the Standards document where Inform
made the wrong choice, but interpreters made the right one.)
The -w (suppress warnings) switch doing nothing. (In writing Inform 6
I simply forgot this.)
Source code cleaning:
A new UNIX64 port, for 64-bit Unix machines, added (courtesy of Magnus
Olsson) which should subtract pointers correctly even in the unlikely
event that they lie in different 2^32 byte pages. Otherwise identical
to UNIX.
And a new BEOS port added (courtesy of Michael van Biesbrouck) but which is
identical to the Linux one in all but name.
Link error message handling, and character error message handling,
slightly more automated.
The "Compiled with %d errors and %d warnings" message reworded so as not
to mention 0 of anything, and to indicate how many warnings were
suppressed (by the -q or -w switches).
The table of memory settings is now printed more prettily in response
to the ICL command $list.
A new memory setting, MAX_LABELS, has been added, along with error checking
to test for too many label points in any single routine.
Various functions to do with character set handling tidied up and moved
into the new section "chars.c".
(viii) Changes made between v6.12 and v6.13
------------------------------------
Bug fixed:
String escapes in the form "You can't go @00 from here." not working
(slip of the keyboard when re-writing string escapes in v6.12).
Source code cleaning:
The type of alphabet[][] has been altered so as to ensure that the
contents are not read-only strings:
from char *alphabet[3] to char alphabet[3][27].
(ix) Changes made between v6.13 and v6.14
------------------------------------
Bugs fixed:
"Parker's disease": In very large games only, backpatch errors being
caused because the Z-code area of the Z-machine had overflowed
past the size where the compiler could backpatch it (this tended
to happen only if large amounts of text were printed by Inform code
rather than being property values). The Inform code generator now
automatically writes any string of text longer than 32 characters
into the static strings area: designers shouldn't notice any difference
in behaviour of the "print" or "print_ret" statements.
(The new arrangement is fractionally wasteful of bytes -- about
2 to 4 bytes per string in excess of 32 characters -- but makes
a big difference to the relative sizes of the code and strings
areas. "Advent" compiled the old way was 60.1% code, 17.3% strings;
the new way, it comes out 40.6% code, 37.1% strings and is about
1K bigger. Most of the change occurs when compiling library
messages; the effects are less dramatic on typical Inform code.)
A different cause of backpatch errors is attempting to link Version 5 modules
into a Version 8 game. If you're compiling a V8 game and want to
link in the library, for instance, you'll need to compile the
library modules with "-v8" as well. Inform used not to check this
error condition, but now does produce an error message if there's
a version mismatch between game and module.
The linker also now checks that module and game are using the same
Z-machine character set. (If either one has made a Zcharacter directive
which differs from the other, then the sets are inconsistent and
linkage can't take place. This will only ever happen if you're
working in a language other than English, and trying to use the linker,
and it can be cured by copying the Zcharacter directives out of the
language definition file into a little include file, and including
that in the source for your main file as well as the source for any
modules of your own -- i.e., any modules other than the library ones.)
Finally, the linker checks for the error condition that the module asked
to import a variable which turns out not to have been defined in the
main game. (This may cause problems in linking with library 6/6, as
Inform is now able to detect an error in 6/6's "linklv.h" which it
previously wasn't able to detect: delete the line reading
"Import global gender_and_number;" from "linklv.h" if so.)
"continue" not working (branching to the non-existent label -1, in
fact) if used inside a "switch" statement. (It ought to continue
the innermost loop containing the "switch" statement, if there is
one, or give an error if there isn't.)
The two string escapes @@94 (producing a ^ character) and @@126
(producing ~) in fact producing new-line and double-quote.
Conditional branches to rtrue or rfalse in assembly-language being
reversed in sense.
Source code being garbled after any Include statement which ends at
a byte position which is a multiple of 4096, minus 3. (My thanks
to Andrew Plotkin for both finding and diagnosing this.)
"For" loops in the form "for ( : : )" (with white space between the two
colons), which occur in a routine after a previous one which happens
to have a designer-defined label in a particular position, causing
an incorrect if harmless "Label declared but not used" warning.
Very short programs testing "x provides ", but never reading,
writing or otherwise using , causing stack overflows or
restarts. Nobody would ever need such a program anyway.
Function calls not working, or having garbled arguments, in Version 3
or Version 4 games (the Inform library requires Version 5 or better
nowadays, so the ability to compile V3 or V4 files is only needed
for interpreter testing).
The error message disallowing use of an assembly opcode if the Z-machine
version doesn't support it, now quotes the opcode name.
Suppressed "declared but not used" warnings for global objects not being
counted towards the total number reported as suppressed when Inform
prints its final message.
Source code cleaning:
Three character conversions amended to unsigned character conversions.
Backpatch errors, which I devoutly hope not to see again, are now
reported as a new category of error: "compiler errors" which produce
an apologetic banner, asking the user to report the fault to me.
Link errors are reported more prettily (differently, anyway).
(x) Changes made between v6.14 and v6.15
------------------------------------
Features added:
Parametrised object creation. That is, if you define a class in which
objects can be created, and also give it a "create" property like so:
Class Monster
with ...
create
[ start_at new_species;
move self to start_at;
self.species = new_species;
], ...
then you can now make creation calls like so:
M = Monster.create(Tomb_of_Kings, Ogre);
The same applies to "recreate":
Monster.recreate(M, Wall_of_Thorns, Hobbit);
An attempt to supply more than 3 parameters to either kind of creation
will result in a run-time error message.
It is now legal to declare a Class with zero create-able objects:
Class Moribund(0) ...
This is useful (i) to permit a definition like
Class Gadgets(NUM_GADGETS)
in some library file, where NUM_GADGETS is supplied by the library
file's user and might be zero; and/or (ii) to permit "recreate"
to be used on objects of the given class, reinitialising them
to the values set in the class definition.
The ASCII form feed character (12 decimal) is now legal as white space.
More precisely, it is in all contexts treated as a line feed.
Bugs fixed:
Getting property lengths wrong for common property values referred to
using the superclass operator :: (a bug which sometimes manifests
itself in a crash when a common property routine belonging to a
superclass is called).
Crashing when halting on a memory error because an extremely long string
of text has caused MAX_STATIC_STRINGS to be exceeded. (The compiler
now ensures that MAX_STATIC_STRINGS is at least twice the size of
MAX_QTEXT_SIZE, which should be more than plenty.)
Crashing when printing an extremely long "Expected ... but found ..."
error (where the second ... stands for an awfully long string of
text).
An inability to assemble the optional third operand to the "@set_colour"
opcode (which is available to Version 6 games only).
Array sizes are now formally checked to lie in the range 1 to 32767
entries, with an error message produced if they don't.
Misinterpretation of array definitions with calculated sizes:
Array Muggins -> MAX_SERVERS * 50;
In Inform 6.14, this would be wrongly parsed as an array with one
entry, initialised to the value given: whereas 6.15 correctly parses
it as an array with MAX_SERVERS*50 initially zero entries.
When constants are calculated with at compile time (as in the previous
bug), Inform 6.15 now detects overflows of signed addition,
subtraction and multiplication. So if, for instance, MAX_SERVERS
is 100000, then the following error is produced:
Error: Signed arithmetic on compile-time constants overflowed
the range -32768 to +32767: "100000 * 50 = 500000"
Two bugs in the veneer (both found and fixed by Chris Hall): (i) a program
using ".create()" but not "provides" will go into a recursive loop
(this never happens if the Inform library is included);
(ii) more importantly, some creations of objects within classes
where deletions had previously occurred were resulting in two
different created objects sharing the same properties.
Improper use of 'or' not always producing a good error message (sometimes
producing instead the compiler error "*** emitter overflow ***").
The more explanatory error message
Error: 'or' not between values to the right of a condition
should now be produced in all such cases.
Expressions featuring ) followed immediately by ( sometimes crashing
the expression evaluator. For instance:
(ChooseRoutine())(1);
BigRoom.(BigDoor.dir_to)();
The grammar resolving whether a function call is intended, or
only a bracketed expression, has been refined so that, e.g.,
;
is not misinterpreted as containing one argument, the result of
the function call "dial(4*the_time)". (If you want this, you must
put brackets around it.)
Named action constants (like ##Take) not being correctly numbered after
the 256th in order of first usage.
The "Default" directive for setting constants not properly handling
some values which are other than numerical -- e.g.,
Default Story "Untitled Story";
would not have worked correctly under Inform 6.14.
Backpatching "compiler errors" are now suppressed if errors have already
been reported (because in some circumstances, error recovery is
good enough to allow compilation to continue but not good enough
to leave a self-consistent backpatch table in the affected area).
Error recovery from missed close-quotation-marks in object
definitions has been marginally improved in some cases.
Source code cleaning:
Use of the Inform 5 statements 'print_paddr', 'print_addr' and
'print_char' (all illegal in Inform 6) now results in an obsolete
usage message which prints up the necessary Inform 6 equivalent.
The statistics output now includes the story file's serial codes, in the
traditional . format.
Note that this manual now contains an algorithm for syntax-colouring
Inform source code.
(xi) Changes made between v6.15 and v6.20
------------------------------------
Features added:
Strict (-S) mode added, under which Inform undertakes to compile a story
file which cannot crash the Z-machine (unless the user has compiled
some assembly-language) but will instead print helpful error messages
when illegal operations are attempted. -S mode is wasteful of story
file size (it adds perhaps 10 to 15%) and of execution speed (but on
most modern computers, Z-machine interpreters run extremely quickly
anyway) but is intended to be helpful for debugging. See section
7.8 of this manual for a list of exactly what strict-mode does.
In support of strict mode, several new # system constants have been
added, but these should not be used by designers and are not public
features.
Inform now checks that readable-memory usage (i.e. the top of the dictionary
and the bottom of the code area) does not exceed $10000, as this is a
Z-machine requirement. The "-s" statistics listing has an added line
indicating how much of readable memory a game file has needed.
(To test this, try compiling a game with "Array gross --> 32767;"
in it.)
Bugs fixed:
"class.copy(a,b)" not working properly when "a" overrides an individual
property defined by some class. (Because of a bug not in the code for
"copy" but in "objects.c": individual property tables were accumulating
redundant extra values, which never showed up except when "copy" was
used. Thanks to Erik Hetzner and Gevan for finding and fixing this.)
"class.copy(a,b)" also transferring the class memberships of b to a (or
at least whenever a and b both belonged to at least one class).
When a message is sent to a common property of an object which that object
doesn't provide, it wasn't being properly routed to the routine given
in the default value of that common property (which we'd normally expect
to be 0 or NULL, either way causing nothing to happen). Instead, a
call would be made to 0-->0, with unpredictable consequences. (This
was originally reported as a bug in "Balances".)
The maximum number of entries in a list given as a common property value
wasn't being correctly restricted to 32 in two different situations:
when directly giving values, where the limit was wrongly set to 64;
and when the list grows through inheritance of an additive property,
where no limit was checked.
The "Switches" directive can't set "-k" or "-r", because it's too late by
then to reopen the question of opening debugging/transcript files,
but 6.15 didn't know this. Torbj|rn thus contributed the shortest
legal source file yet known to crash Inform, at just 11 characters:
"Switches r;".
The rennab (the un-banner) printed at the end of compilation claiming
"(no output)" if there were no errors during the main compilation pass,
but there were errors late in story file construction instead.
I'm not sure this is a bug as such, but assembly listing (caused by -a, -t
or use of "#Trace assembly") no longer covers the veneer. (Because
it's a nuisance and clutters up the listing.)
Not a bug either. The return opcode automatically generated by "]", where
needed (i.e. when this is reachable) is now a sequence point. This was
requested by Mark Musante, to assist debuggers.
(xii) Changes made between v6.20 and v6.20a
-------------------------------------
(These are bug fixes made to the early beta-version v6.20.)
The "length" calculation for properties (in "properties_segment()" of
"objects.c") calculates the length differently for individual and
common properties.
Some small test programs not properly working because the wrong combinations
of veneer routines were being compiled. (I've rewritten the appropriate
routines in "veneer.c" which decide which routines need the presence of
which other routines.) In particular, ".#" applied to individual
properties might not work in a very small file.
Array bounds checking not working on arrays of >= 255 entries.
(xiii) Changes made between v6.20a and v6.21
-------------------------------------
A new "-X" switch provides support for the Infix debugging library file.
(Which it does by compiling additional veneer tables of symbol
names.)
The maximum number of source files read from in compilation has been
raised from 64 to 256, at the request of a user. (No, really. She
knows who she is.) The filename storage has been reduced in size,
which will reduce the physical size of the Inform program by 8K
on most systems.
The "-g" switch for tracing function calls now has a third setting,
"-g3", which traces even veneer calls: the "-g2" setting now traces
game and library calls but not veneer calls.
New syntax: "Zcharacter terminating" specifies the terminating character
table for games in Z-machine versions >= 5. See section 12.3 for
details.
Bugs fixed:
Loops in the form "objectloop (X in Y) ..." causing stack underflow crashes
if compiled with -S checking off.
-S checking now guards against attempts to use properties of "nothing",
for instance rejecting something like "nothing.name = 'nobody';",
and error messages concerning nonexistent objects no longer print
garbled names for them.
Linking sometimes producing backpatching errors if arrays are already
created before the link occurs.
The -S (strict checking) and -X (Infix) switches are now disabled for files
being compiled as modules. (They wouldn't work, and would anyway make
the library modules too large.)
-S checking no longer tries to compile "pop" opcodes in Versions 5, 6, 8
to clear values off the stack in some cases of array-boundary checking.
(These Z-machine versions lack a "pop" opcode: instead, the same effect
is inelegantly produced by "@jz sp" with a null branch, taking up
three bytes rather than one. C'est la Z.)
A potential crash if the limit on the number of adjectives is exceeded in
a grammar version 1 game (which probably means a very big one using
library 6/2 or earlier) has been removed.
The readable-memory ceiling was incorrect for version 6 games.
The error message resulting from asking Inform to read an unopenable ICL
file is now coherent.
Assembly tracing at level 3 (which you don't want to read) now correctly
prints the size of a routine after branch optimization.
The checksum is now included in the header block attached to a debugging
information file. (Previously this slot contained 0000.)
A minor bug in the abbreviations optimizer, so obscure that I'm not even
sure what its consequence was, has been removed.
Source code cleaning:
The MAC_68K machine definition has been removed from the header: there
are no longer any specific lines of code for this system.
(xiv) Acknowledgements
----------------
Many thanks to the following informers, who have reported bugs in Inform 6:
Torbj|rn Andersson, Toni Arnold, Jose Luis Diaz de Arriba, Michael Baum,
Paul E. Bell, Michael van Biesbrouck, Gerald Bostock, Neil Brown,
Russ Bryan, Jesse Burneko, Evan Day, Gevan Dutton, Stephen van Egmond,
Tom Emerson, Theresa van Ettinger, Greg Falcon, Roy Fellows, Rob Fisher,
David Fletcher, C. E. Forman, Richard Gault, Paul Gilbert, David Glasser,
Michael Graham, Bjorn Gustavsson, Chris Hall, Kory Heath, Erik Hetzner,
Andreas Hoppler, Paul Horth, Sam Hulick, Francis Irving, Brad Jones,
Christoffer Karlsson, Niclas Karlsson, John Kean, John Kennedy,
Matt Kimball, Kirk Klobe, Michael A. Krehan, Mary Kuhner, Josh Larios,
JŸrgen Lerch, Harvey Lodder, Jennifer Maher, Bonni Mierzejewska,
Paul Mikell, Tim Muddleton, Olav Mueller, Jeff Nassiff, Ross Nicol,
Magnus Olsson, Marnie Parker, Robert Pelak, Jason Penney,
Aphoristic Petrofsky, Andrew Plotkin, Richard H. Poser, Fredrik Ramsberg,
Gareth Rees, Evin Robertson, Matthew Russotto, Gunther Schmidl,
Miron Schmidt, Rene Schnoor, Nyuchezuu Shampoo, Lucian P. Smith,
Anson Turner, Lorelle VanFossen, David L. Wagner, John Wood,
Uncle Bob Newell and all.
------------------------------------------------------------------------------