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. ------------------------------------------------------------------------------