{ Brief comments on the .txt version: This .txt version of the Inform Designer's Manual has a number of features to make your life easier. The .tex version written by Graham Nelson made use of italics, typewriter fonts, things inside boxes, and a few things I still don't understand from reading the source. Special characters: · Accents like è and á are faithfully reproduced, as well as fancy characters like the squiggly-S section character "§". · In the original format, triangles were used to denote tricky or difficult sections of the material. These were rendered in this document as an o with a slash through it like this: "ø". One feature in this ASCII format which is not given directly in the dvi or postscript is that the extent of the difficult section is identified with a vertical bar down its side: ø like | this | section · What appeared in the original document as a box around text appears here as [text]. (This occurs only in the section on grammar.) Formatting: · The page breaks are reproduced here more or less exactly. The original document used a footer containing the page number and the current subject. To jump to a particular page, say 22, search for the string "page: 22"; you will arrive at the *bottom* of that page (since the page number is in the footer). Note the space in the string. · Italicized and typewriter text do not appear any differently than the surrounding text. If you understand what is being talked about, this should not be a big deal. · Page break characters have been inserted before the beginning of each chapter. Features: · The index at the end should prove much more useful in this version than in the last one -- I used it directly from the .tex source rather than the awful mess generated by "dvi2txt". · This document has been formatted to be 75 columns or less in width: people who want to put it into a binder can do so by indenting the whole thing by 4 or 5 characters before printing. ... finally, a very big `thank-you' to Allison Weaver who tirelessly proofread the document, thereby reducing the amount of unnecessary grief in the world. Stephen van Egmond October 11th, 1996 svanegmo@undergrad.math.uwaterloo.ca (until mid-1997) svanegmo@truespectra.com } {Further brief comments by Lucian Smith: This version incorporates the draft 'errata' Graham put out in May, 1997. I tried to keep with Stephen's conversion conventions, with one exception being that I put single quotes (') around some typewriter text, for added clarity. Sorry if the inconsistency confuses you. Lucian Smith May 21st, 1997 lpsmith@rice.edu } The Inform Designer's Manual by Graham Nelson Third edition 4 September 1996 as updated 16 May 1997 Detailed contents ::::::::::::::::::::::::::::::::::::::::::::::::: 2 Introduction :::::::::::::::::::::::::::::::::::::::::::::::::::::: 7 Book One: Programming I The Inform Programming Language :::::::::::::::::::::::::::::::::: 10 II Using the Compiler ::::::::::::::::::::::::::::::::::::::::::::::: 63 Book Two: Designing III Fundamentals :::::::::::::::::::::::::::::::::::::::::::::::::::::: 82 IV The Model World ::::::::::::::::::::::::::::::::::::::::::::::::::: 97 V Describing and Parsing ::::::::::::::::::::::::::::::::::::::::::: 135 VI Testing and Hacking :::::::::::::::::::::::::::::::::::::::::::::: 166 Appendices Tables and summaries :::::::::::::::::::::::::::::::::::::::::::: 178 Answers to all the exercises::::::::::::::::::::::::::::::::::::: 209 Index ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 250 [page: 1 / footer:] Contents Introduction :::::::::::::::::::::::::::::::::::::::::::::::::::::::: 7 BOOK ONE: PROGRAMMING Chapter I: The Inform Programming Language 1 The language of routines :::::::::::::::::::::::::::::::::::::::: 10 1. First principles 2. Example 1: Hello World 3. Example 2: Elsinore 4. Numbers and variables 5. Arithmetic expressions 6. Arguments and return values 7. Example 3: Cubes 8. Conditions: if, true and false 9. Example 4: Factorials 10. Code blocks, else and switch 11. while, do... until, for, break, continue 12. Example 5: A number puzzle 13. quit and jump; saving the program state 14. Printing output 15. Example 6: Printing in hexadecimal 16. Built-in functions 1: random and indirect 17. Accepting input 2 The language of data::::::::::::::::::::::::::::::::::::::::::::: 36 1. Directives and constants 2. Global variables 3. Arrays 4. Example 7: Shuffling a pack of cards 5. Seven special data structures 3 The language of objects ::::::::::::::::::::::::::::::::::::::::: 44 1. Objects and communication 2. Built-in functions 2: the object tree 3. Creating objects 1: setting up the object tree 4. Statements for objects: move, remove, objectloop 5. Creating objects 2: with properties 6. private properties and encapsulation 7. Attributes, give and has 8. Classes and inheritance 9. Messages 10. Access to superclass values 11. Philosophy 12. Sending messages to routines, strings or classes 13. Creating and deleting objects 14. Footnote on common vs. individual objects [page: 2 / footer: Contents] Chapter II: Using the Compiler 4 The language of Inform::::::::::::::::::::::::::::::::::::::::::: 63 ICL (Inform Control Language); Include; conditional compilation: If..., Ifnot, Endif; Message; linking in the library; writing new modules to link in. 5 Compiler options and memory settings::::::::::::::::::::::::::::: 69 Switches; memory sizes; typical memory usage; raising memory settings. 6 All the Inform error messages:::::::::::::::::::::::::::::::::::: 73 Fatal errors; errors, including linker and assembler errors; warnings, including obsolete usage warnings. BOOK TWO: DESIGNING Chapter III: Fundamentals 7 Getting started:::::::::::::::::::::::::::::::::::::::::::::::::: 82 Beginning to lay `Ruins'; including the library files; the Initialise routine; some properties of mushrooms; name, description and initial; edible foodstuffs; introducing before and after rules; the stone steps; self-destructing rules. 8 Introducing messages and classes :::::::::::::::::::::::::::::::: 87 Recap of message-sending: a parrot; classes for treasure artifacts: the pygmy statuette, the honeycomb; how clashes are sorted out in class inheritance, additivity. 9 Actions and reactions:::::::::::::::::::::::::::::::::::::::::::: 91 Actions are attempts; generating them with <, <<; the action, noun and second variables (and inp1, inp2); the ## notation; the standard actions, in Groups 1 to 3; creating new actions, the Blorple example; fake actions like ThrownAt; how actions are processed, over `Before', `During' and `After' stages. Chapter IV: The Model World 10 Places, scenery, directions and the map :::::::::::::::::::::::: 97 Giving `Ruins' a small map; n_to, d_to, etc.; when you cant_go; scenery objects; default rules; rooms have before and after too; a mist object, present in many rooms, using found_in; the five senses and reaction rules; direction objects in the compass. 11 Containers, supporters and sub-objects :::::::::::::::::::::::: 102 Containers: container, supporter, capacity, open, openable; locks and keys: locked, lockable, with_key; LetGo and Receive to trap use of a container: a horrifying chasm; the Search action; transparent objects have visible sub-objects; a television set with buttons. 12 Doors:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 104 How to create a door; door_to, door_dir; when_open, when_closed; a stone door for `Ruins'; a two-way door, the `Advent' grate; why door_dir is needed and how to trap every attempt to go through. 13 Switchable objects :::::::::::::::::::::::::::::::::::::::::::: 106 switchable and on: when_on, when_off; the Gotham City searchlight; a sodium lamp; describe taking precedence. [page: 3 / footer: Contents] 14 Things to enter, travel in and push around::::::::::::::::::::: 108 enterable objects: a slab altar; vehicles: KAR 1; special rule about the Go action when inside something enterable; the PushDir action: a huge pumice-stone ball; pushing up and down. 15 Reading matter and consultation ::::::::::::::::::::::::::::::: 110 The Consult action, "look up"; consult_from and consult_words: a dictionary of glyphs, Tyndale's Bible; making "read" and "examine" different. 16 Living creatures and conversation:::::::::::::::::::::::::::::: 112 animate objects and the life rule; a mummified priest, Blofeld, a coiled snake; some people are transparent; orders: actions for other people; talkable objects; parsing conversation: Zen and Charlotte; untypeable verbs; fake fake actions; several voice-activated machines; applications of scope: telepathy and phone calls. 17 The light and the dark :::::::::::::::::::::::::::::::::::::::: 119 Light and darkness is automatically managed; the definition of `when there is light'; OffersLight and HasLightSource; going from darkness to darkness and the DarkToDark entry point; modifying the darkness object. 18 Daemons and the passing of time:::::::::::::::::::::::::::::::: 121 Daemons and the daemon property; starting and stopping them; background daemons; timers (fuses); time_left and time_out; each_turn events for places and nearby objects; the time of day; changing it with SetTime; on the status line; midnight, sunrise, sunset; the exact sequence of events at end-of-turn. 19 Starting, moving, changing and killing the player ::::::::::::: 124 What Initialise should do; the location; initial restoration; teleportation and the PlayerTo routine; what happens when the room changes: NewRoom, initial for a room, visited; giving the player his own before rule; using ChangePlayer to transform him into any object; multi-character games; life and deadflag; the DeathMessage routine; resurrection and the AfterLife routine. 20 Miscellaneous constants and scoring ::::::::::::::::::::::::::: 128 Story and Headline; MAX_CARRIED; the automatic rucksack SACK_OBJECT; `amusing' rewards for the victorious; two scoring systems: MAX_SCORE, OBJECT_SCORE, ROOM_SCORE; tasks: TASKS_PROVIDED, NUMBER_TASKS, task_scores, PrintTaskName; rankings and PrintRank; automatic score notification and notify_mode; "objects" and "places" verbs, removable with NO_PLACES. 21 Extending and redefining the Library::::::::::::::::::::::::::: 130 Enriching the model; amulets and their spells; making a new library file; new common properties; changing default values of these; the LibraryMessages system for changing messages like "Dropped."; changing the prompt; the last resort, using Replace directives; even on `hardware' functions like random. [page: 4 / footer: Contents] Chapter V: Describing and Parsing 22 Describing objects and rooms::::::::::::::::::::::::::::::::::: 135 print (The) obj, ... (the) obj and so on; indefinite and definite article; proper nouns; the short_name of an object; invent strings and routines; exactly how inventory lines are printed; a matchbook; describe routines; exactly how rooms are described; Locale. 23 Listing and grouping objects :::::::::::::::::::::::::::::::::: 140 The list-maker WriteListFrom; its style bitmap; examples: tall and wide inventories; grouping similar items together in lists: foodstuffs, Scrabble pieces and denominations of coin. 24 How nouns are parsed::::::::::::::::::::::::::::::::::::::::::: 143 How name is used; a fried green tomato turning red; the parser breaks text into a stream of words; wn and NextWord; reading words as numbers or from their raw text; a parse_name routine is much more flexible than name; the ParseNoun entry point; distinguishing adjectives from nouns. 25 Plural names for duplicated objects:::::::::::::::::::::::::::: 147 Collections of indistinguishable objects; a bag of six coins; the plural property for printing out plurals; definition of `indistinguishable'; writing parse_name routines to allow plurals to be understood; class of crowns. 26 How verbs are parsed::::::::::::::::::::::::::::::::::::::::::: 149 The parser's fundamental method; BeforeParsing entry point; the actor and verb word; synonyms for verbs; definitions of grammar, line and token; action_to_be; Verb directive: a simplified "take" grammar; meta verbs; grammar creates actions; creating an "xyzzy" verb; how to Extend grammar for an existing verb: pushing numbered buttons; priority: replace, first, last; splitting synonymous verbs apart with Extend only; the UnknownVerb and PrintVerb entry points. 27 Tokens of grammar:::::::::::::::::::::::::::::::::::::::::::::: 154 Full list of grammar tokens; prepositions; noun and held; implicit taking; tokens allowing multiple objects like "all"; filtering out nouns by attribute: "use" verb; and by general routine: "free" verb; parsing numbers: "type" verb, ParseNumber; general parsing routines; reading from the parser's raw text buffer and parse table; exercises, including French, telephone and floating-point numbers, times of day, adding a third parameter to a grammar line. 28 Scope and what you can see::::::::::::::::::::::::::::::::::::: 159 The definition of `in scope'; touchability is stricter than scope; answering questions: "what is a grue"; scope=... tokens with programmable scope; scope_stage, ScopeWithin and PlaceInScope; changing the global definition of `in scope' using InScope; scope_reason; looping over and testing scope; making the rules more sensitive to darkness; a long room divided by a glass wall; the add_to_scope property for component parts of containers. 29 Helping the parser out of trouble ::::::::::::::::::::::::::::: 164 Parser error messages and ParserError; ambiguity-resolution and influencing it with ChooseObjects; making "eat" prefer edible objects; redefining "all". [page: 5 / footer: Contents] Chapter VI: Testing and Hacking 30 Debugging verbs and tracing ::::::::::::::::::::::::::::::::::: 166 Suite of debugging verbs: "purloin", "abstract", "tree", "scope", "goto", "gonear", "actions", "routines", "timers", "trace", "recording", "replay", "random"; transcriptions; the random-number generator; Infix-format debugging files; how to crash the game interpreter at run-time; the levels of parser tracing; compiling with debugging code. 31 Limitations on the run-time format::::::::::::::::::::::::::::: 169 Formats of the Z-machine; restrictions: memory, vocabulary, dictionary resolution, attributes, properties, names, special effects, objects, memory management, global variables, "undo" verb, function arguments; using Abbreviate to save run-time memory. 32 Boxes, menus and drawings:::::::::::::::::::::::::::::::::::::: 171 Asking yes/no questions with YesOrNo; the status line; character graphics, escape characters; proportional- and fixed-pitch fonts, font; epigrams in boxes and box; menus of text options, DoMenu, pretty_flag, menu_item; an example menu; submenus are allowed; changing the text style to bold-face, underlining, reverse video. 33 Descending into assembly language ::::::::::::::::::::::::::::: 173 Assembly language @; reliability of interpreters; table of opcodes worth knowing about; upper and lower windows: splitting, setting the window, moving the cursor, clearing the screen, word-breaking; the colour scheme; a bell sound; keyboard reading in real-time; function and cursor keys; tokenising with dictionaries; encoding dictionary entries; input/output streams; the stack frame: throw and catch; examples: a title page, drawing status lines, formatting and centering text. APPENDIX: Tables and summaries A1 Inform operators::::::::::::::::::::::::::::::::::::::::::::::: 178 A2 Inform statements ::::::::::::::::::::::::::::::::::::::::::::: 180 A3 Inform directives ::::::::::::::::::::::::::::::::::::::::::::: 181 A4 Grammar:::::::::::::::::::::::::::::::::::::::::::::::::::::::: 182 A5 Library attributes :::::::::::::::::::::::::::::::::::::::::::: 183 A6 Library properties :::::::::::::::::::::::::::::::::::::::::::: 185 A7 Library-defined objects and routines :::::::::::::::::::::::::: 191 A8 Library actions ::::::::::::::::::::::::::::::::::::::::::::::: 193 A9 Library message numbers:::::::::::::::::::::::::::::::::::::::: 194 A10 Entry points and meaningful constants::::::::::::::::::::::::: 198 A11 What order the program should be in::::::::::::::::::::::::::: 200 A12 A short Inform lexicon:::::::::::::::::::::::::::::::::::::::: 201 Answers to all the exercises::::::::::::::::::::::::::::::::::::::: 209 Index:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 250 [page: 6 / footer:] Introduction I will build myself a copper tower With four ways out and no way in But mine the glory, mine the power . . . -- Louis MacNeice (1907-1963), Flight of the Heart Inform is a system for creating adventure games, and this is the book to read about it. Infocom format `story files' (adventure games, that is) can be played on almost any computer, from personal organisers to mainframes, with the aid of `interpreter' programs. The task of the Inform `compiler' is to translate a textual description of a game into a story file. The result will play identically on any machine of any model. Inform is a suite of software, called the `library', as well as a compiler. Without the library, it would be a major undertaking to write a description of even the smallest game. The library has two ingredients: the parser, a program for translating written English inputs into a form games can more easily understand, and the "world model", a complex web of rules common to all adventure games. Given these, the designer only needs to describe things and give any exceptional rules that apply. ("There is a bird here, which is a normal item except that you can't pick it up.") The library is rich in detail. The parser recognises over 80 distinct verbs and a vocabulary of about 300 words even before any rooms or objects are created, and is programmable and highly flexible. It can handle ambiguities, clarify its input by asking questions ("Which key do you mean...?") and can cope properly with plurals, vagueness, conversation, pronouns and the player becoming someone else in mid-game. It can be configured to languages other than English. The world-model includes rooms, items, vehicles, duplicates, containers, doors, things on top of other things, light and darkness, switching things on and off, opening, closing and locking things, looking up information in books, entering things, scoring and so forth. Just as Inform has two strands -- compiler and library -- so this manual has two parts: Programming and Designing. In Book One, small computer programs are written to perform simple calculations, never using the library. Book Two is entirely about making games. Newcomers are invited to work through §1 and §7, the "getting started" sections in Books One and Two, before reading much more of either. In trying to be both a tutorial and reference work, this book aims itself in style halfway between the two extremes of manual, Tedium and Gnawfinger's Elements of Batch Processing in COBOL-66, third edition, and Mr Blobby's Blobby Book of Computer Fun. (This makes some sections both leaden and patronising.) Passages which divert the main story, usually to tell an unexpurgated truth which may confuse or bore a newcomer, are marked with a warning triangle ø or two. Mundane or irrelevant passages in longer examples are sometimes replaced with a line reading just "..." [page: 7 / footer: Introduction] To keep Book Two from clogging up with examples, many are set as "exercises", with "answers" given in full at the back of the book. Harder exercises are marked with triangles and some are very hard indeed. I emphasize that the exercises are often intended as a way of presenting answers to deliberately difficult questions, to assist experts: the curse of Adventure design-languages is the feature which is ideal for the simple but too inflexible to cope with the complicated. For a list of exercises with page references to question and answer, see under "exercises" in the Index. A better tutorial than attempting the exercises, then, is probably to make a simple game, as demonstrated in Chapter III, and then add an example of each new feature as you work through Chapters IV and V. Many sections end with a `References' paragraph referring to yet more examples which can be found in Inform's demonstration games. All of these have publically available source code (see the Inform home page): those most frequently referred to are `Advent' (a full version of the original mainframe `Adventure', which contains a good deal of "everyday Inform"), `Adventureland' (a version of Scott Adams's primitive classic), `Alice Through The Looking-Glass' (a heavily annotated game, developed in the course of Gareth Rees's WWW tutorial for Inform), `Balances' (a short story consisting of puzzles which stretch the parser's abilities) and `Toyshop' (hardly a game: more an incoherent collection of unusual objects). In addition, the little game `Ruins' is developed in the course of Chapters III and IV of this manual. Finally, the "game" called `Museum of Inform' simulates a museum whose exhibits are solutions to the exercises in this manual. Copyright on Inform, the program and its source code, its example games and documentation (including this book) is retained by Graham Nelson, who asserts the moral right to be identified as the author under the Copyrights, Designs and Patents Act 1988. Having said this, I am happy for it to be freely distributed to anybody who wants a copy, provided that: (a) distributed copies are not substantially different from those archived by the author, (b) this and other copyright messages are always retained in full, and (c) no profit is involved. (Exceptions to these rules must be negotiated directly with the author.) However, a story file produced with the Inform compiler (and libraries) then belongs to its author, and may be sold for profit if desired, provided that its game banner contains the information that it was compiled by Inform, and the Inform version number. The Internet source for Inform material (executables of the compiler for different machines, source code, the library files and example games) is the German National Research Centre for Computer Science, where Volker Blasius maintains an archive at the anonymous FTP site ftp.gmd.de. Inform's home directory at this site is: ftp://ftp.gmd.de/if-archive/infocom/compilers/inform6 Another useful resource is the Inform 6 home page on the `World Wide Web', which includes Gareth Rees's `Alice' tutorial, located at: http://www.gnelson.demon.co.uk/inform.html [page: 8 / footer: Introduction] This manual describes Inform release 6.13 (or later), using library release 6/5 (or later). Earlier Inform 6 compilers and libraries are are very similar but Inform 5.5 and 5/12 very different. This manual has evolved from seven earlier publications, once rather makeshift and sometimes defensive ("Inform is an easel, not a painting"). There were specifications of the run-time code format and literary critiques of games gone by: like an oven manual padded out with both a cookery book and a detailed plan of the gas mains. This book contains just the instructions for the oven. So there are four `companion volumes'. The Craft of Adventure is an essay on the design of adventure games; The Z-Machine Standards Document minutely covers the run-time format and Inform assembly language, its lowest level; and The Inform Technical Manual documents Inform's internal working in great detail, and includes a formal context-free grammar for the Inform language. _The Inform Translator's Manual_ describes how to write a language definition file for games which speak languages other than English. Some of the ideas of Inform came from an incremental multi-player game called Tera, on the Cambridge University mainframe, written by Dilip Sequeira and the author in 1990 (whose compiler was called Teraform); in turn, this stole a little from David Seal and Jonathan Thackray's game assembler; which dates back to the close of the 1970s and was written for `Acheton', perhaps the first worthwhile game written outside America. Still, much of the Inform kernel derives ultimately from the IEEE Computer article `Zork: A Computerized Fantasy Simulation Game' by P. David Lebling, Marc S. Blank and Timothy A. Anderson; and more was suggested by Richard Tucker and Gareth Rees, among others. The list of those who have helped the project along is legion: I should like to thank them all, porters, users and critics alike, but especially Volker Blasius, Paul David Doherty, Mark Howell, the ever avuncular Bob Newell, Robert Pelak, Gareth Rees, Jørund Rian, Dilip Sequeira, Richard Tucker, Christopher Wichura and John Wood. One final word. I should like to dedicate this book, impertinently perhaps, to our illustrious predecessors: Will Crowther, Don Woods and the authors of Infocom, Inc. Graham Nelson Oxford April 1993 -- May 1997 And if no piece of chronicle we prove, We'll build in sonnets pretty rooms; As well a well wrought urn becomes The greatest ashes, as half-acre tombs. -- John Donne (1571?-1631), The Canonization [page: 9 / footer:] Chapter I: The Inform programming language Language is a cracked kettle on which we beat out tunes for bears to dance to, while all the time we long to move the stars to pity. -- Gustave Flaubert (1821-1880) 1 The language of routines §1.1 First principles This chapter aims to introduce beginners to Inform as though it were a general-purpose programming language (rather than a tool for designing adventure games). The examples given will be short programs performing simple calculations (rather than games). To begin with, the Inform language is: 1. Compiled. That is, the Inform compiler translates text written by the author (called the "source code") into a program (called the "object code" since it is the object of the exercise). This translation is only done once, but the resulting program can be run many times. 2. Procedural. That is, a program is divided into a number of "routines" (also called "functions" or "procedures"), each being a list of orders to be obeyed (though these orders are traditionally called "statements"). When the program is run, only one thing happens at a time: at any given moment, a single routine is being obeyed. 3. Object-oriented. That is, the fabric of a typical Inform program will be woven around "objects" being dealt with, which are regarded as being self-contained. For example, a program to simulate a warehouse might have objects representing lorries and containers; each object would have a position and contents at any given time. The program would have general rules describing "lorry" and "container" as well as actual examples of each. A lorry would have the ability to receive a message telling it to do something, such as "load up with a container and leave the warehouse". 4. Portable. That is, once Inform has compiled the source code (having found no mistakes), the resulting program can be run on almost any model of computer. It will exhibit exactly the same behaviour on each of them. It cannot depend on the "environment": it cannot suddenly run out of memory and crash, for instance. [page: 10 / footer: 1 The language of routines] The computer runs an Inform program (which need not be a game) with the aid of an "interpreter". There are at least 40 different interpreters available for this format (called the "Z-machine" or "Infocom format") and there may be a choice available for your model of computer: it is a good idea to get the most modern and accurate possible. Look to see if they support the Z-Machine Standard, and if so, up to what revision number. §1.2 Example 1: Hello World Traditionally, all programming language tutorials begin by giving a program which does nothing but print "Hello world" and stop. Here is such a program in Inform: ! "Hello world" example program [ Main; print "Hello world^"; ]; The text after the exclamation mark is a "comment", that is, it is text written in the margin by the author to remind himself of what is going on here. Such text means nothing to Inform, which ignores anything on the same line and to the right of an exclamation mark. Once commentary has been stripped out, Inform regards the source code as a list of things to look at, divided by semicolons ;. It treats line breaks, tab characters and spaces all as so-called "white space": that is, a gap between two things whose size is unimportant. Thus, exactly the same program would be produced by the source code [ Main ; print "Hello world^" ; ] ; or, at the other extreme, by [ Main;print"Hello world^";]; Laying out programs legibly is a matter of forming good habits. ø The exception to the rule about ignoring white space is inside quoted | text, where | | "Hello world^" and "Hello world^" | | are genuinely different pieces of text and are treated as such. Inform | treats text inside quotation marks with much more care than its | ordinary program material: for instance, an exclamation mark inside | quotation marks will not cause the rest of its line to be thrown away | as a comment. [page: 11 / footer: 1 The language of routines] Every program must contain a routine called Main, and in this example it is the only routine. When a program is set running, the first instruction obeyed is the first one in Main, and it carries on line by line from there. This process is called "execution". When the Main routine is finished, the program stops. The routine has only one statement: print "Hello world^" Printing is the process of writing text onto the computer screen. This statement prints the two words "Hello world" and then skips the rest of the line (or "prints a new-line"): the ^ character, in quoted text, means "new-line". For example, the statement print "Blue^Red^Green^" prints up: Blue Red Green print is one of 28 statements in the Inform language. The full list is as follows: box break continue do font for give if inversion jump move new_line objectloop print print_ret quit read remove restore return rfalse rtrue save spaces string style switch while (Only about 20 of these are commonly used.) §1 covers all those not concerned with objects, which are left until §3. §1.3 Example 2: Elsinore The following source code has three routines, Main, Rosencrantz and Hamlet: [ Main; print "Hello from Elsinore.^"; Rosencrantz(); ]; [ Rosencrantz; print "Greetings from Rosencrantz.^"; ]; [ Hamlet; print "The rest is silence.^"; ]; [page: 12 / footer: 1 The language of routines] The resulting program prints up Hello from Elsinore. Greetings from Rosencrantz. but the text "The rest is silence." is never printed. Execution begins at Main, and "Hello from Elsinore" is printed; next, the statement Rosencrantz() causes the Rosencrantz routine to be executed. That continues until it ends with the close-routine marker ], whereupon execution goes back to Main just after the point where it left off: since there is nothing more to do in Main, the program finishes. Thus, Rosencrantz is executed but Hamlet is not. In fact, when the above program is compiled, Inform notices that Hamlet is never needed and prints out a warning to that effect. The exact text produced by Inform varies from machine to machine, but will be something like this: RISC OS Inform 6.03 (May 11th 1996) line 8: Warning: Routine "Hamlet" declared but not used Compiled with 0 errors and 1 warning Errors are mistakes in the program which cause Inform to refuse to compile it, but this is only a warning. It alerts the programmer that a mistake may have been made (because presumably the programmer has simply forgotten to put in a statement calling Hamlet) but it doesn't prevent the compilation from taking place. Note that the opening line of the routine Hamlet occurs on the 8th line of the program above. Usually there are mistakes in a newly-written program and one goes through a cycle of running a first draft through Inform, receiving a batch of error messages, correcting the draft according to these messages, and trying again. A typical error message would occur if, on line 3, we had mistyped Rosncrantz() for Rosencrantz(). Inform would then have produced: RISC OS Inform 6.03 (May 11th 1996) line 5: Warning: Routine "Rosencrantz" declared but not used line 8: Warning: Routine "Hamlet" declared but not used line 3: Error: No such constant as "Rosncrantz" Compiled with 1 error and 2 warnings (no output) The error message means that on line 3 Inform ran into a name which did not correspond to any known quantity (it isn't the name of any routine, in particular). Note that Inform never produces the final story file if errors occur during compilation: this prevents it from producing damaged story files. Note also that Inform now thinks the routine Rosencrantz is never used, since it didn't recognise the mistype in the way that a human reader would have done. Warnings are sometimes produced by accident this way, so it is generally a good idea to worry about fixing errors first and warnings afterward. §1.4 Numbers and variables Internally -- that is, whatever the outward appearance -- all programs essentially manipulate numbers. Inform understands "number" to be a whole number in the range -32768 to +32767. (Special programming would be required to represent larger numbers or fractions.) There are three notations for writing numbers in Inform: here is an example of each. -4205 $3f08 $$1000111010110 [page: 13 / footer: 1 The language of routines] The difference is the radix, or base, in which they are expressed. The first is in decimal (base 10), the second hexadecimal (base 16, where the digits after 9 are written a to f or A to F) and the third binary (base 2). Once Inform has read in a number, it forgets which notation was used: for instance, if the source code is altered so that $$10110 is replaced by 22, this makes no difference to the program produced. A print statement can print numbers as well as text, though it always prints them back in ordinary decimal notation. For example, the program [ Main; print "Today's number is ", $3f08, ".^"; ]; prints up Today's number is 16136. since 16136 in base 10 is the same number as 3f08 in hexadecimal. Inform recognises many other notations as "constants", that is, values which are literally described in the source code. A full list will appear later, but one other is that a single character between single quotation marks, for instance 'x' is a constant. A "character" is a single letter or typewriter-symbol, and all that the programmer needs to know is that each possible character has its own numerical value. ø For most characters, this numerical value is the standard ASCII value | for the character: for instance, 'x' has numerical value 120. (This | is true even if Inform is being run on a model of computer which | doesn't normally use the ASCII character set.) Exotic characters such | as '@ss' (the Inform notation for German sz) have non-standard codes: | see the Z-Machine Standards Document if you really need to know. Finally, in this initial batch of constant notations, Inform provides two special constants: true false which are used to describe the truth or otherwise of possible conditions. ø true has the numerical value 1; false has the numerical value 0. [page: 14 / footer: 1 The language of routines] Inform has a concept of "variable" like that used in algebra, where it is easy but limiting to express facts using only numbers: 34 - 34 = 0 11 - 11 = 0 694 - 694 = 0 Although suggestive this fails to express the general case: that any number subtracted from itself leaves zero. We express this fact symbolically in algebra by writing x - x = 0 where x is a variable; the implication being "whatever value x actually is, the statement is still true". Likewise, in Inform what seems to be a word of text may be a variable which represents a number: when the source code is compiled, Inform cannot know what numerical value this text represents. When the program is run, it will always have a numerical value at any given time. If oil_left is a variable, the statement print "There are ", oil_left, " gallons remaining.^"; is executed as if oil_left were replaced by whatever that value currently is. Later on, the same statement may be executed again, producing different text because by that time oil_left has a different value. Inform can only know that text (such as oil_left) represents a variable if the source code has "declared" that it does. Each routine can declare its own selection of variables on its opening line. For example, in the program [ Main alpha b; alpha = 2200; b = 201; print "Alpha is ", alpha, " while b is ", b, "^"; ]; the Main routine has two variables, alpha and b. Like most names given in source code (called "identifiers"), variable names can be at most 32 characters long and may contain letters of the alphabet, decimal digits or the underscore _ character (often used to imitate a space). To prevent them looking too much like numbers, though, they may not start with a decimal digit. (So a44 is legal but 44a is not.) For example: turns_still_to_play chart45 X are all possible variable names. Inform ignores any difference between upper and lower case letters in such names, for example considering CHArt45 as the same name as chArT45. [page: 15 / footer: 1 The language of routines] The = sign occurring twice in the above routine is an example of an "operator": a notation usually made up of the symbols on the non-alphabetic keys on a typewriter and which means something is to be done with the items it is written next to. In this context, = means "set equal to". When the statement 'alpha = 2200' is executed at run time, the current value of the variable alpha becomes 2200 (and it keeps that value until another such statement changes it). The variables alpha and b are called "local variables" because they are local to Main: in effect, they are its private property. The program [ Main alpha; alpha = 2200; Rival(); ]; [ Rival; print alpha; ]; causes an error on the print statement in Rival, since alpha does not exist there. Indeed, Rival could even have defined a variable of its own also called alpha and this would have been a separate variable with a probably different value. §1.5 Arithmetic expressions The Inform language is rich with operators, making it concise but not always very readable. Feeling comfortable with the operators is the main step towards being able to follow Inform source code. Fortunately, these operators are based on the usual rules for writing arithmetic formulae, which gives them a headstart in familiarity. Indeed, the most commonly used operators are "arithmetic": they combine one or more numbers to give one resulting number. Whenever a number is expected in a statement, a general "expression" can be given instead: that is, a calculation giving a number as a result. For example, the statement seconds = 60*minutes + 3600*hours sets the variable seconds equal to 60 times the variable minutes plus 3600 times the variable hours. White space is not needed between operators and "operands" (the numbers to be operated on): the spaces on either side of the + sign are only provided for legibility. Ordinary arithmetic is carried out with the operators + (plus), - (minus), * (times) and / (divided by). Usually dividing one integer by another leaves a remainder: for example, 3 goes into 7 twice, with remainder 1. In Inform notation, 7/3 evaluates to 2 7%3 evaluates to 1 the % operator meaning "remainder after division", usually called just "remainder". Dividing by zero is impossible and a program which tries to do this will go wrong. [page: 16 / footer: 1 The language of routines] ø As a brief aside, this gives an example of how Inform can and can't help | the programmer to spot mistakes. The program | | [ Main; | print 73/0; | ]; | | produces an error when compiled: | | line 2: Error: Division of constant by zero | > print 73/0; | | | since Inform can see that it definitely involves doing something | illegal. However, Inform fails to notice anything amiss with the | equivalent program | | [ Main x; | x = 0; | print 73/x; | ]; | | | and this program compiles correctly. The resulting story file will | "crash" when it is run, that is, catastrophically halt. The moral is | that just because Inform compiles a program without errors, it does | not follow that the program does what the programmer intends. In a complicated expression the order in which the operators work may affect the result. As most human readers would, Inform works out both of 23 + 2 * 700 2 * 700 + 23 to 1423, because the operator * has "precedence" over + and so is acted on first. Brackets may be used to overcome this: (23 + 2) * 700 2 * (700 + 23) evaluate to 17500 and 1446 respectively. Each operator has such a "precedence level". When two operators have the same precedence level (for example, + and - are of equal precedence) calculation is (almost always) "left associative", that is, carried out left to right: the notation a - b - c is equivalent to (a - b) - c The standard rules for writing mathematics give + and - equal precedence, lower than that of * and / (which are also equal). Inform agrees and also pegs % equal to * and /. [page: 17 / footer: 1 The language of routines] The final purely arithmetic operator is "unary minus". This is written as a minus sign - but is not the same as ordinary subtraction. The expression: -credit means the same thing as: 0 - credit The operator - is different from all those mentioned so far because it operates only on one number. It has higher precedence than any of the five "binary" operations above. For example, -credit - 5 means (-credit) - 5 and not -(credit - 5). One way to imagine precedence is to think of it as glue attached to the operator. A higher level means stronger glue. Thus, in 23 + 2 * 700 the glue around the * is stronger than that around the +, so that 2 and 700 belong bound to the *. Some operators do not simply act on values but actually change the current values of variables: expressions containing these are called "assignments" (because they assign values as well as working them out). One such operator is 'set equals': alpha = 72 sets the variable alpha equal to 72. Just like + and the others, it also comes up with an answer: as it happens, this value is also 72. The other two assignment operators are ++ and --, which will be familiar to any C programmer. They are unary operators, and can be used in any of the following ways: variable++ ++variable variable-- --variable The first of these means "read off the value of variable, and afterwards increase that value by one". In ++variable the "increment" (or increase by 1) happens first, and then the value is read off. -- acts in a similar way but "decrements" (decreases by 1). These operators are provided as convenient shorthand forms, since their effect could usually be achieved in other ways (just using + and -). For example, suppose the variable has value 12. Then the result would be 12, 13, 12 or 11 respectively; the value left in variable afterwards would be 13, 13, 11 or 11. Note that expressions like 500++ (4*alpha)-- 34 = beta are meaningless: the values of 500 and 34 cannot be altered, and Inform knows no way to adjust alpha so as to make 4*alpha decrease by 1. All three will cause errors. [page: 18 / footer: 1 The language of routines] ø "Bitwise operators" are provided for manipulating binary numbers on a | digit-by-digit basis, something which is often done in programs which | are working with low-level data or data which has to be stored very | compactly. Inform provides &, bitwise AND, |, bitwise OR and ~, bitwise | NOT. For each digit, such an operator works out the value in the answer | from the values in the operands. Bitwise NOT acts on a single operand | and results in the number whose i-th binary digit is the opposite of | that in the operand (a 1 for a 0, a 0 for a 1). Bitwise AND (and OR) | acts on two numbers and sets the i-th digit to 1 if both operands have | (either operand has) i-th digit set. So, for example, | | | $$10111100 & $$01010001 == $$00010000 ø The remaining operators will be described as needed: the full table | is laid out in §A1. §1.6 Arguments and Return Values As has already been said, in Inform jargon the word "function" is synonymous with "routine". A function might be defined as a correspondence (x1 , ... , xn) => f(x1 , ... , xn) where a set of input numbers are fed in, and a single value comes out. These input numbers are called "arguments". The value coming out is the "return value", or is said to be "returned". All Inform routines are like this. A number of arguments are fed in when the routine is "called" (that is, set running) and there is always a single numerical result. This result is called the "return value" because it is returned to the rest of the program. Some very simple routines conceal this. For instance, consider Sonnet: [ Main; Sonnet(); ]; [ Sonnet; print "When to the sessions of sweet silent thought^"; print "I summon up remembrance of things past^"; ]; Sonnet is a routine which takes as input no arguments at all (it is an example of the n = 0 case), so it is called with nothing in between the round brackets. Although it does return a value (as it happens, this value is true) the statement Sonnet() simply calls the routine and throws the return value away. If Main were instead given by [ Main; print Sonnet(); ]; then the output would be When to the sessions of sweet silent thought I summon up remembrance of things past 1 [page: 19 / footer: 1 The language of routines] because the print statement in Main has been told to print the number resulting from a call to Sonnet. Thus in Inform there is no such thing as a "void function" or "procedure": every routine returns a number even though this may immediately be thrown away as unwanted. When a routine is called, Routine(arg1, ...) the arguments given are substituted into the first variables declared for Routine, and execution begins running through Routine. Usually, there can be any number of arguments from none up to 7, though a limit of 3 applies if Inform has been told to compile an early-model story file (see § 31 for details). If execution runs into the ] end-of-routine marker, so that the routine is finished without having specified any definite return value, then this value is true. (This is why the printed return value of Sonnet is 1: true has the value 1.) §1.7 Example 3: Cubes A more typical, though less aesthetic, example than Sonnet: [ Main; print Cube(1), " "; print Cube(2), " "; print Cube(3), " "; print Cube(4), " "; print Cube(5), "^"; ]; [ Cube x; return x*x*x; ]; which, when executed, prints 1 8 27 64 125 The expression Cube(3) is calculated by substituting the number 3 into the variable x when Cube is set running: the result of the expression is the number returned by Cube. Any "missing arguments" in a routine call are set equal to zero, so the call Cube() is legal and does the same as Cube(0). §1.8 Conditions: if, true and false Such routines are too simple, so far, even to express many mathematical functions, and more flexibility will be needed. [page: 20 / footer: 1 The language of routines] A "control construct" is a kind of statement which controls whether or not, and if so how many times or in what order, other statements are executed. The simplest of these is if: if () which executes the only if the , when it is tested, turns out to be true. For example, when the statement if (alpha == 3) print "Hello"; is executed, the word "Hello" is printed only if the variable alpha currently has value 3. It is important not to confuse the == operator (test whether or not equal to) with the = operator (set equal to). Conditions are always given in (round) brackets. The basic conditions are as follows: (a == b) Number a equals number b (a ~= b) Number a doesn't equal number b (a >= b) a is greater than or equal to b (a <= b) a is less than or equal to b (a > b) a is greater than b (a < b) a is less than b (o1 in o2) Object o1 possessed by o2 (o1 notin o2) Object o1 not possessed by o2 (o1 has a) Object o1 has attribute a (o1 hasnt a) Object o1 hasn't attribute a (o1 provides m) Object o1 provides property m (o1 ofclass c) Object o1 inherits from class c (The conditions relating to objects will be discussed later.) A useful extension to this set is provided by the special operator or, which gives alternative possibilities. For example, if (alpha == 3 or 4) print "Scott"; if (alpha ~= 5 or 7 or 9) print "Amundsen"; where two or more values are given with the word or between. Scott is printed if alpha has value either 3 or 4, and Amundsen if the value of alpha is not 5, is not 7 and is not 9. or can be used with any of the conditions, and any number of alternatives can be given. For example, if (player in Forest or Village or Building) ... often makes code much clearer than writing three separate conditions out; or if (x > 100 or y) ... can be convenient to check whether x is bigger than the minimum of 100 or y. Conditions can also be built up from simpler ones (just as long expressions are built up from single operators) using the three logical operators &&, ||and ~~ (pronounced "and", "or" and "not"). For example, if (alpha == 1 && (beta > 10 || beta < -10)) print "Lewis"; if (~~(alpha > 6)) print "Clark"; "Lewis" is printed if alpha equals 1 and beta is outside the range -10 to 10; "Clark" is printed if alpha is less than or equal to 6. The discussion above makes it look as if conditions are special kinds of expression which can only use certain operators (==, &&, or and so on). But this is not true: conditions are expressions like any other. It's legal to write print (beta == 4); [page: 21 / footer: 1 The language of routines] for instance, and this results in 1 being printed if beta equals 4, and 0 otherwise. Thus: the result of a true condition is 1; the result of a false condition is 0. This is why true and false are defined to be 1 and 0 respectively. Thus one might write code along the lines of betaisfour = (beta == 4); ... if (betaisfour == true) ... though it would be easier to write betaisfour = (beta == 4); ... if (betaisfour) ... because, just as conditions can be used as numbers, so numbers can be used as conditions. Zero is considered to be "false", and all other values are considered to be "true". Thus if (1) print "Magellan"; if (0) print "da Gama"; always results in "Magellan", never "da Gama", being printed. One common use of variables is as "flags". A flag can only hold the value 0 or 1, false or true according to some state of the program. The fact that a number can be used as a condition allows natural-looking statements like if (lower_caves_explored) print "You've already been that way."; where lower_caves_explored is a variable being used in the program as a flag. ø Note that && and ||only work out what they absolutely need to in order | to decide the truth. That is, | | if (A && B) ... | | will work out A first. If this is false, there's no need to work out B, | and it never is worked out. Only if A is true is B actually tested. | This only matters when working out conditions like | | if (x==7 && Routine(5)) ... | | where it can be important to know that the Routine is never called if x | has a value other than 7. [page: 22 / footer: 1 The language of routines] §1.9 Example 4: Factorials The factorial of a positive integer n is defined as the product 1 * 2 * 3 * ... * n so that, for example, the factorial of 4 is 24. Here is an Inform routine to calculate factorials: [ Main; print Factorial(7), "^"; ]; [ Factorial n; if (n==1) return 1; return n*Factorial(n-1); ]; This calculates 7 factorial and comes up with 5040. (Factorials grow rapidly and 8 factorial is already too large to hold in a standard Inform number, so calling Factorial(8) would give a wrong answer.) The routine Factorial actually calls itself: this is called "recursion". Execution reaches "seven routines deep" before starting to return back up. Each of these copies of Factorial runs with its own private copy of the variable n. Recursion is hazardous. If one calls the routine [ Disaster; return Disaster(); ]; then despite the reassuring presence of the word return, execution is tied up forever, unable to finish evaluating the return value. The first call to Disaster needs to make a second before it can finish; the second needs to make a third; and so on. This is an example of a programming error which will prove disastrous when the program is run, yet will cause no errors when the source code is compiled. (It can be proved that it is impossible to construct a compiler capable of detecting this general class of mistake. Inform does not even try.) §1.10 Code blocks, else and switch A feature of all control constructs is that instead of just giving a , one can give a list of statements grouped together into a unit called a "code block". Such a group begins with an open brace { and ends with a close brace }. For example, if (alpha > 5) { print "The square of alpha is "; print alpha*alpha; print ".^"; } [page: 23 / footer: 1 The language of routines] If alpha is 3, nothing is printed; if alpha is 9, The square of alpha is 81. is printed. (As usual the layout is a matter of convention: it is usual to write code blocks on margins indented inwards by some standard number of characters.) In some ways, code blocks are like routines, and at first it may seem inconsistent to write routines between [ and ] brackets and code blocks between braces { and }. However, code blocks cannot have private variables of their own and do not return values: and it is possible for execution to break out of code blocks again, or to jump from block to block, which is impossible with routines. An if statement can optionally have the form if () else in which case is executed if the condition is true, and if it is false. For example, if (alpha == 5) print "Five."; else print "Not five."; Note that the condition is only checked once. The statement if (alpha == 5) { print "Five."; alpha = 10; } else print "Not five."; cannot ever print both "Five" and then "Not five". The else clause has a snag attached: the problem of "hanging elses". if (alpha == 1) if (beta == 2) print "Clearly if alpha=1 and beta=2.^"; else print "Ambiguous.^"; is ambiguous as to which if statement the else attaches to. The answer (in Inform 6, though this has changed since earlier versions of the language) is that an else always pairs to its nearest if, unless there is bracing to indicate the contrary. Thus the else above pairs with the beta condition, not the alpha condition. In any case it is much safer to use braces to express what is meant, as in: if (alpha == 1) { if (beta == 2) print "Clearly if alpha=1 and beta=2.^"; else print "Clearly if alpha=1 but beta not 2.^"; } [page: 24 / footer: 1 The language of routines] The if...else... construct is ideal for switching execution between two possible "tracks", like railway signals, but it is a nuisance trying to divide between many different outcomes this way. To follow the analogy, the construct switch is like a railway turntable. print "The train on platform 1 is going to "; switch (DestinationOnPlatform(1)) { 1: print "Dover Priory."; 2: print "Bristol Parkway."; 3: print "Edinburgh Waverley."; } Each possible value must be a constant, so switch(alpha) { beta: print "The variables alpha and beta are equal!"; } is illegal. Any number of outcomes can be specified, and values can be grouped together to a common outcome. For example, print "The mission STS-",num," was flown on the Space Shuttle"; switch(num) { 1 to 5, 9: print " Columbia."; 6 to 8: print " Challenger."; 10 to 25: if (num == 12) print " Discovery"; print ", but it was given a flight number like 51-B."; default: print "."; } will result in a true statement being printed (as long as num is between 1 and, at time of writing, 78), if an incomplete one. The default clause is executed if the original expression matches none of the other values, and it must always come last if given at all. In this case, it means that if num is 62, then The mission STS-62 was flown on the Space Shuttle. is printed. Note that each clause is automatically a code block and needs no braces { to } to delimit it from the rest of the routine: this shorthand makes switch statements much more legible. §1.11 while, do...until, for, break, continue The other four Inform control constructs are all "loops", that is, ways to repeat the execution of a given statement (or code block). Discussion of one of the four, called objectloop, is deferred until §3.4. [page: 25 / footer: 1 The language of routines] The two basic forms of loop are while and do...until: while () do until () The first repeatedly tests the condition and, provided it is still true, executes the statement. (If the condition is not even true the first time, the statement is never executed.) For example: [ SquareRoot n; x = n; while (x*x > n) x=x-1; return x; ]; a (fairly chronic) method for finding square roots. (If SquareRoot(200) is called, then x runs down through the values 200, 199, ..., 14, at which point x*x <= n since 14 * 14 = 196.) The do...until loop repeats the given statement until the condition is found to be true. (Even if the condition is already satisfied, like (true), the statement is always executed the first time through.) One particular kind of while loop is needed so often that there is an abbreviation for it, called for. For example, counter = 1; while (counter <= 10) { print counter, " "; counter++; } which produces the output 1 2 3 4 5 6 7 8 9 10 (Recall that counter++ adds 1 to the variable counter.) Languages like BASIC make extensive use of this kind of loop. For example, in BBC BASIC, the above loop would be written FOR counter = 1 TO 10 PRINT counter;" "; NEXT NEXT is a word which (slightly clumsily) means "the code block ends here", and is therefore the equivalent of Inform's }. The whole is used to mean "for values of the counter running through 1 to 10, do...", hence the choice of the word FOR. Inform (like the language C) uses a more flexible construct than this, but which is still called for. It can produce any loop in the form while () { ... } [page: 26 / footer: 1 The language of routines] where and are assignments. The notation to achieve this is for (: : ) ... For example, the loop described above is achieved by for (counter=1 : counter<=10 : counter++) print counter, " "; Note that if the condition is false even the first time, the loop is never executed. For instance, for (counter=1 : counter<0 : counter++) print "Banana"; prints nothing. ø At this point it is worth mentioning that several assignments can be | combined into a single statement in Inform. For example, | | i++, score=50, j++ | | (three assignments separated by commas) is a single statement. This is | never useful in ordinary code, where the assignments can be divided up | by semicolons in the usual way. In for loops it is useful, though: | | for (i=1, j=5: i<=5: i++, j--) print i, " ", j, ", "; | | produces the output "1 5, 2 4, 3 3, 4 2, 5 1,". Any of the three parts of a for statement can be omitted. If the condition is missed out, it is assumed to be always true, i.e. there is no check made to see if the loop should be ended and so the loop continues forever. On the face of it, the following loops all repeat forever: while (true) do until (false) for (::) But there is always an escape. One way is to 'return' from the current routine. Another is to 'jump' to a label outside the loop ('jump' will be covered in § 1.13 below). It's neater to use the statement 'break', which causes execution to "break out of" the current innermost loop or 'switch' statement: it can be read as "finish early". All these ways out are entirely "safe", and there is no harm in leaving a loop only half-done. The other simple statement used inside loops is continue. This causes the current iteration to end immediately, but does not end the whole loop. For example, for (i=1: i<=5: i++) { if (i==3) continue; print i, " "; } will output "1 2 4 5". [page: 27 / footer: 1 The language of routines] §1.12 Example 5: A number puzzle The routine RunPuzzle is an interesting example of a loop which, though apparently simple enough, contains a trap for the unwary. [ RunPuzzle n count; do { print n, " "; n = NextNumber(n); count++; } until (n==1); print "1^(taking ", count, " steps to reach 1)^"; ]; [ NextNumber n; if (n%2 == 0) return n/2; ! If n is even, halve it return 3*n + 1; ! If n is odd, triple and add 1 ]; The call RunPuzzle(10), for example, results in the output 10 5 16 8 4 2 1 (taking 6 steps to reach 1) The source code assumes that, no matter what the initial value of n, enough iteration will end up back at 1. If this did not happen, the program would lock up into an infinite loop, printing numbers forever. The routine is apparently very simple, so it would seem reasonable that by thinking carefully enough about it, we ought to be able to decide whether or not it is "safe" to use (i.e., whether it can be guaranteed to finish or not). And yet nobody knows whether this routine is "safe". The conjecture that all n eventually step down to 1 is at least fifty years old but has never been proved, having resisted all mathematical attack. (Alarmingly, RunPuzzle(27) takes 111 iterations to fall back down to 1.) §1.13 quit, jump and the program state There are four statements left which control the flow of execution. quit ends the program immediately (as if a return had taken place from the Main routine). This drastic measure is best reserved for points in the program which have detected some error condition so awful that there is no point carrying on. Better yet, do not use it at all. The jump statement transfers execution to some other named place in the same routine. (Some programming languages call this goto. Since it can be and has been put to ugly uses, the construct itself was at one time frowned on as a vulgar construct leading programmers into sin. Good use of control constructs will almost always avoid the need for jump and result in more legible programs. But sin is universal.) [page: 28 / footer: 1 The language of routines] To use jump a notation is needed to mark particular places in the source code. Such markers are called "labels". For example: [ Main i; i=1; .Marker; print "I have now printed this ", i++, " times.^"; jump Marker; ]; This program has one label, Marker. A statement consisting only of a full stop and then an identifier means "put a label here and call it this". øø An Inform program has the ability to save a snapshot of its entire | state and to restore back to that previous state. This snapshot | includes values of variables, the point where code is currently being | executed, and so on. Just as we cannot know if the universe is only six | thousand years old, as creationists claim, having been endowed by God | with a carefully faked fossil record; so an Inform program cannot know | if it has been executing all along or if it was only recently restarted. | The statements required are save and restore: | | save