# TADS 3 Change History

For information on changes to the library (adv3), refer to the Recent Library Changes list.

### Changes for 3.0.18.1 (May 5, 2009)

- The behavior of the multi-method inherited() operator has changed. The operator now chooses the inherited function to call based on the actual argument values, rather than the formal (declared) parameters to the current function. This is more consistent with the inherited() operator for regular methods.
- A bug in the compiler, versions 3.0.17, 3.0.17.1, and 3.0.18, caused incorrect (too small) stack size requests to be generated for some functions and methods. This generally had no noticeable effect on valid programs, but it made it possible for an errant program (with infinite recursion, for example) to cause a stack overflow that the interpreter doesn't detect immediately, which could conceivably crash the interpreter. An actual crash would require an unlikely combination of factors, even with an errant program compiled with this bug, so you'll probably never notice it. Even so, if you distributed any .t3 files compiled with t3make versions 3.0.17 through 3.0.18, we recommend recompiling with the current t3make version and replacing your previously distributed files, if it's easy for you to do so.

### Changes for 3.0.18 (April 28, 2009)

- The `inherited` operator can now be used within a multi-method to inherit an overridden version of the method. The new syntax `inherited<type-list>(arg-list)` lets you inherit a specific version of the multi-method, while the basic syntax `inherited(arg-list)` automatically selects the next more general version of the multi-method. See the System Manual section on multi-methods for documentation.
- The compiler pre-defines the new preprocessor symbol (i.e., macro) __TADS3, which expands simply to the number 1. This provides an easy way to detect that the compiler is a TADS 3 compiler (as opposed to a TADS 2 compiler) for conditional compilation purposes. (This might seem redundant with the existing symbol __TADS_SYSTEM_MAJOR, but __TADS3 can be used in one way that __TADS_SYSTEM_MAJOR can't. If for some reason you wanted to create a single source file that could be compiled under TADS 2 or TADS 3, using conditional compilation to handle the syntax differences between the language versions, you couldn't do it with __TADS_SYSTEM_MAJOR. This is because TADS 2 doesn't support #if, which is the only way you could use __TADS_SYSTEM_MAJOR to conditionally compile based on compiler version (e.g., `#if __TADS_SYSTEM_MAJOR == 3`). Since TADS 2 and 3 both support #ifdef, though, you can use the presence or absence of the __TADS3 symbol to conditionally include or omit code based on language version. Of course, since older versions of the TADS 3 compiler also lack this symbol, this approach requires using 3.0.17.2 or later on the TADS 3 side.)
- In past versions, writing to text files with a UTF-16 encoding generated incorrect newline sequences when running on Windows. The problem had to do with the two-character representation of a newline in Windows. This has been corrected.
- In the past, multi-methods defined in one source file and called from another resulted in an "undefined symbol" error. This has been corrected.

### Changes for 3.0.17.1 (8/12/2008)

- A compiler bug introduced in 3.0.17 caused Workbench (and the stand-alone interpreter) to crash when loading certain games when compiled for debugging. The compiler was mis-calculating some internal data structure sizes, which effectively corrupted the .t3 file; this happened when the byte code for a function plus its debug symbols was over a certain threshold size. This has been corrected.

### Changes for 3.0.17 (8/9/2008)

- The compiler has a new feature called "multi-methods." This implements a relatively new object-oriented programming technique known as multiple dispatch, in which the types of multiple arguments can be used to determine which of several possible functions to call. The traditional TADS method call uses a single-dispatch system: when you write "x.foo(3)", you're invoking the method foo as defined on the object x, or as inherited from the nearest superclass of x that defines that method. This is known as single dispatch because a single value (x) controls the selection of which definition of foo will be invoked. With multiple dispatch, this notion is extended so that multiple values can be considered when selecting which method to invoke. For example, you could write one version of a function "putIn()" that operates on a Thing and a Container, and another version of the same function that operates on a Liquid and a Vessel, and the system will automatically choose the correct version at run-time based on the types of both arguments. This new system is described more fully in the System Manual.

- The compiler can now generate information in each object about the source file where the object was defined. This new information is stored in a new property, sourceTextGroup; this supplements the existing sourceTextOrder property. Since the new information takes up extra space in the compiled file, it's not generated by default. To generate it, include the new compiler option "-Gstg" in your makefile or command line, or place the directive `#pragma sourceTextGroup(on)` directive in each source module where you wish to generate the information. The #pragma lets you selectively generate the information in specific source files, or even in specific portions of specific source files: the corresponding directive `#pragma sourceTextGroup(off)` lets you turn off the information in a section where you don't need it.

  When you turn on sourceTextGroup generation, the compiler automatically adds a sourceTextGroup property to each object, just as it automatically adds a sourceTextOrder value. The sourceTextGroup value is a reference to an anonymous object that the compiler automatically creates. One such object is generated per source module for which sourceTextGroup generation is activated. This object contains two properties: sourceTextGroupName is a string giving the name of the module, as it appeared in the compiler command line, makefile (.t3m), or library (.tl) file; sourceTextGroupOrder is an integer giving the relative order of the module among the list of modules comprising the overall program.

  sourceTextGroup is useful in cases where you want to establish the order of appearance in source files among objects in multiple modules. For a given object `x`, `x.sourceTextGroup.sourceTextGroupOrder` gives you the relative order within the overall build of the module where `x` was defined, and `x.sourceTextOrder` gives you the relative order of `x` among the objects defined within that module. Between the two values, you can establish a linear ordering for all of the statically defined objects in the entire program.

- The compiler now stores "links" to resource files in the .t3 file when compiling in Debug mode. This makes it easier to test a game that uses multimedia resources, by making the Build environment match the Release environment more precisely.

  In the past, when building in Debug mode, the compiler completely ignored multimedia resource files listed in the "-res" section of the command line or makefile. This was by design; the reasoning was that when you're compiling in Debug mode, you'll only be running that copy on your development machine, within your build environment, where all of the resource files are available as local files; and since the files are all available as separate local files anyway, we can make the compilation go faster by skipping the step where we copy those files into the .t3 file.

  This worked fine most of the time, but it didn't work in the occasional case where the resource name is different from the corresponding local file's name in the file system. One example is the Cover Art file, which is always stored in the game under the resource name ".system/CoverArt.jpg", which is usually not the same name the file has locally. This meant that if you tried to refer to such a resource via HTML (such as with an <IMG> tag), the resource was reported as missing when running the debug build.

  The new arrangement fixes this problem without giving up the time savings. With the new scheme, the compiler stores a link for each resource in the .t3 file: this simply records the mapping from resource name to local file name. The HTML renderer can then look up the appropriate local file for each resource, including any resources that have special names. As before, the actual contents of the resources are not copied.

  Note that none of this affects Release builds. The compiler has always copied the full contents of all resources into the .t3 file when doing a Release build, and continues to do so. Release builds continue to be fully self-contained, so that you only have to distribute the .t3 file to players, not the individual graphics and sound files it refers to.

- The compiler's status output didn't add a line break after each resource files being added to the project, resulting in poorly formatted displays. This has been corrected.

### Changes for 3.0.16 (4/10/2008)

- The Author's Kit installer now gives you an option to skip creating the Windows file type associations for Workbench (specifically, project (.t3m) files).
- The main startup routine in the library now performs an explicit garbage collection pass just before performing pre-initialization. In most cases, this is unnecessary (and harmless, obviously, apart from the added execution time required to perform the GC pass). However, under a certain combination of conditions, it can be important. In particular, it's important when a program is compiled so that preinit is performed at run-time rather than compile-time (this is normally the case for a "debug mode" build, but can be explicitly selected for a release build as well), and the program has pre-initialization code that performs global object loops. In such a program, a RESTART would re-run preinit, which could then encounter garbage objects still around from before the RESTART. The explicit GC pass just before preinit ensures that preinit sees only reachable objects in any global object loops it performs.
- A bug in the ByteArray intrinsic class caused an interpreter crash when copying exactly the full bounds of an array onto itself. This has been corrected.
- The rexReplace() intrinsic function got stuck in an infinite loop when the pattern to be replaced matched zero characters of the subject string. For example, a match pattern of "x*" is able to match any number of "x" characters in a row, including zero of them. The problem was that the function simply spun its wheels, repeatedly finding the same zero-character match and replacing it over and over. This no longer occurs: the function will apply each zero-character replacement once only, and then move on to the next character of the subject string before attempting a new match.
- The rexSearch() and rexReplace() functions didn't properly take into account "^" (start-of-string) pattern specifiers when a starting offset for the search was explicitly specified. The functions incorrectly considered "^" to match the start of the substring starting at the given starting offset, whereas it should have only matched the start of the entire string. In other words, "^" should never match when the starting offset is greater than 1. This has been corrected.
- A bug in the t3DebugTrace() intrinsic function sometimes caused the debugger to stop execution at the second line after the t3DebugTrace() function, rather than at the next line. This happened if you used the "Go" command to resume execution from the point where t3DebugTrace() stopped, then encountered the same t3DebugTrace() call without any intervening debugger activity. This has been corrected.
- Comparing another object value to "self" in a global breakpoint expression sometimes caused the debugger to crash in past versions. This has been corrected.
- In the past, the compiler returned a "success" indication to the operating system shell as long as no error messages were displayed during the compilation. This was incorrect in cases where the "treat warnings as errors" option was enabled and one or more warning messages were displayed; in these cases, the compiler should have returned a "failure" indication to reflect the fact that warnings count as full-fledged errors under this option setting. This has been corrected.
- Applying toInteger() to BigNumber values near the capacity limits of the 32-bit integer type, but not exceeding them, sometimes produced spurious "numeric overflow" errors. In particular, values over 2147483640 or under -2147483640 that needed to be rounded up in their fractional parts (e.g., 2147483640.9) produced this spurious error. This has been corrected.

### Changes for 3.0.15.3 (11/2/2007)

- A bug in the compiler made it impossible to refer to items in global scope (such as enum values or objects) in constant expressions within anonymous functions. For example, it was impossible to use an enum value or object name as a 'case' label in a 'switch' statement within an anonymous function. This has been corrected.
- A bug in the GrammarProd intrinsic class caused incorrect results in some cases for an empty production (i.e., a grammar rule consisting of no tokens). The problem had to do with the way the empty production figured its position in the input token list; since enclosing levels in the match tree find their positions relative to child nodes, the problem typically manifested itself by giving incorrect token list positions for one or more match levels enclosing an empty match. This is now fixed.

### Changes for 3.0.15.2 (9/13/2007)

- The inputFile() function now makes some additional checks when the filename is supplied by an active event script file. If the dialog type is InFileOpen, the function checks to make sure the filename read from the script refers to an existing file. If the dialog type is InFileSave, and the named file doesn't already exist, the function tries to create a dummy copy of the file; if that succeeds, the function immediately deletes the dummy copy. The function also still tests, as it did before, to make sure the file doesn't already exist for InFileSave dialogs. If any of these tests fail, the function warns the user about the problem and offers the same options it did in the past for the save-overwrite case: use the filename as given in the script, choose a different file, or cancel the script playback.
- A bug in the VM caused sporadic, unpredictable errors when finalizers were used. The problem affected one opcode (OPCGETPROPR0); if a finalizer invocation happened to interrupt this particular opcode, the result was unpredictable, but could include spurious run-time errors or corruptions of calculated results. This has been corrected.

### Changes for 3.0.15.1 (7/19/2007)

- The keyword `replaced` can now be used within anonymous functions that are nested in modifier functions (i.e., functions defined with `modify funcname ...`). In the past, the compiler only allowed `replaced` to be used directly within a modifier function - not in nested anonymous functions defined within a modifier function. There's no inherent reason for disallowing this construct; it was simply a limitation of the compiler, which has now been lifted.
- In the system library, the several internal convenience macros defined with the Tokenizer class (tokRuleName, tokRulePat, tokRuleType, etc) have been moved from the tok.t class file to the tok.h header file. The macros are unchanged, so this change won't affect existing code. The macros were formerly defined in tok.t rather than in the header because they were meant as private macros for internal use within the Tokenizer class itself, not for client code that uses the Tokenizer class. However, they're also useful in subclasses of Tokenizer, so it's desirable to have them defined in a header - that way, user code implementing Tokenizer subclasses can access the macros simply by #including tok.h.
- The compiler is now stricter about interpreting tokens as BigNumber constants. In the past, the compiler treated an "E" following a numeric constant as an exponent signifier, even if no digits followed. For example, "3E-a" was taken to be the BigNumber constant "3E-0", followed by a separate token "a". The compiler now treats an "E" as the start of a separate token if no digits follow it (or the optional + or - sign after the "E"), so "3E-a" would now be treated as four tokens: "3", "E", "-", and "a".
- The compiler now displays a specific error if it finds a decimal digit within an octal constant value. In the past, the compiler simply assumed that a decimal digit terminated the octal constant token and started a new token. This typically led to a confusing parsing error, since the compiler saw two consecutive numeric constant tokens where the user almost always intended one. The compiler now flags a specific error about the ill-formed octal value, and skips any decimal digits following the octal constant, which makes the error much easier to pinpoint.
- The compiler is now strict about disallowing the old TADS 2 "<>" (unequal-to) operator. This variation was not documented, but has up to now been allowed.
- The compiler no longer treats `delete` as a reserved word. (It did so in the past as a hold-over from TADS 2, where `delete` is indeed reserved.)

### Changes for 3.0.15 (3/8/2007)

- When an input event script is being played back, the inputFile() function now prompts the user if the result would likely overwrite an existing file. inputFile() in this case prompts the user interactively, momentarily halting script playback until the user responds. This is described more fully in the Input Scripts section of the System Manual.
- The compiler reported an internal error ("too much unsplicing") in certain complex expressions involving multi-line string literals as macro arguments in embedded << >> expressions. This has been corrected.

### Changes for 3.0.14 (2/9/2007)

- The raiseToPower() method of the BigNumber class incorrectly returned 1 as the result of raising 0 to a non-zero exponent. The correct result should, of course, be 0 for any positive exponent, and an exception for any non-positive exponent (as 0^0 is undefined, and 0^n with n<0 is effectively division by zero). The method now yields these results.

### Changes for 3.0.13 (1/19/2007)

- A new t3make option, -we, tells the compiler to treat warnings as though they were errors, for the purposes of determining whether or not to proceed with compilation after a warning occurs. When the compiler finds an error within a source file, it stops the build process after finishing with that compilation unit, requiring you to fix the error before continuing. In contrast, warnings do not, by default, interrupt the build. This is because a warning message indicates a situation that's technically correct, but which contains a common pitfall. Compiler warnings tend to be right often enough to warrant close inspection, so many programmers adhere to the discipline of insisting on "clean" builds every time - that is, with no warning messages. The -we option is a convenient way of enforcing that discipline. When you specify the -we option, the compiler will stop the build after finishing with any module that generates any warning messages, just as it does for error messages. If you want to explicitly set the default mode, where warnings do not interrupt the build, use the -we- option.
- A new interpreter (t3run) option, -I, runs a command script in "echo" mode. This works almost the same as the existing -i option, but -I causes all output to be displayed to the console as the script is read; in contrast, -i reads the script in "quiet" mode, meaning that no output is displayed while the script is running.
- The command script recorder and player can now handle virtually any input event type, not just command lines. The script mechanism can now handle keyboard input, hyperlinks, ad hoc dialogs, and file dialogs; the functions inputKey(), inputEvent(), inputFile(), and inputDialog() can now take their input from a script. (inputLine() and inputLineTimeout() have always been able to read from scripts.) To handle the greater range of event types, a new script file format has been added; files written in new format are called Event Scripts. Event scripts are identified by a special signature: the first line of the file must read `<eventscript>`, with nothing else on the line (not even spaces). If a script doesn't start with this signature, the script reader will interpret it as the original script format, which is now called the Command-line Script. This allows old scripts to work without changes; of course, Command-line Scripts can only contain line input events, as they always have. When you create a script with RECORD or the with the Interpreter's -o option, the script is now recorded in the new Event Script format, and the recorder will automatically include all event types in the script. (There's no option with RECORD or -o to record an old-style Command-line Script instead - there wouldn't seem to be much call for this, as the functionality in Event Scripts is a superset of that of Command-line Scripts.) The new scripting functionality is described in the "Input Scripts" chapter of the System Manual.
- The setScriptFile() intrinsic function now accepts a new type code, LogTypeEvent. This type signifies that a new-style Event Script should be created. The code LogTypeCommand, which was present in previous versions, continues to signify that an old-style Command-line Script should be created.
- Input scripts now nest during playback. In the past, reading from a new input script terminated reading from any input script already in effect. Now, the console suspends the original script, and resumes reading from it upon reaching the end of the new script. Scripts can be nested to any depth. This allows an input script to "include" another by using, for example, the REPLAY command within the script.
- In the past, the getFuncParams() intrinsic function didn't accept an anonymous function as its argument. Anonymous functions are now accepted.
- The inputLine() intrinsic function (in the 'tads-io' function set) didn't correctly map non-ASCII characters (such as accented letters) from the user's input to Unicode. This has been corrected.
- A compiler bug caused a crash if a "modify" or "replace" statement in one source module referred to a symbol that was actually defined in a source module that was included in the build after the first source file. This is an error condition anyway - a symbol has to be defined in the build before it can be modified or replaced, so the original definition has to occur in a source module listed earlier than the modifying module. However, the compiler now handles such an error properly, by displaying the appropriate error message and halting the build.
- A bug in File.writeBytes() caused unpredictable results, sometimes including an interpreter crash, if a zero or negative value was passed for the starting index. The starting index is now checked for range.
- Some internal changes to the portable VM and compiler code have been made to improve portability to 64-bit architectures.

### Changes for 3.0.12 (9/15/2006)

This is the TADS 3.0 General Release version.

- A couple of compiler error messages were internally mis-numbered, which could have caused the compiler to report the wrong error message for the affected error codes. These have been corrected.

### Changes for 3.0.11 (9/8/2006)

- The % operator now accepts only integer operands. (In the past, it failed to throw an error if a BigNumber operand was used, and instead produced a meaningless result.)
- A comparison of the form "a==b", where a is an integer value and b is a BigNumber value, now coerces the integer to a BigNumber before comparing it. In the past, this type of comparison coerced the integer to a BigNumber only when the BigNumber was the left-hand operand. This correction ensures that "a==b" and "b==a" yield the same results when comparing integers and BigNumber values. The same change applies to the != operator.
- In the past, the compiler reserved the names `void`, `int`, `string`, `list`, `boolean`, and `any`. These names are no longer reserved and thus can now be used freely as symbol names (for local variables, object names, etc). (These names were originally reserved in anticipation of the eventual introduction of optional static type declarations. Reserving the keywords ensured that no one would write code that would be incompatible if the feature had ever been added. The static typing feature will definitely not appear in the official 3.0 release, and at this point it seems very unlikely to be in any future version, so there's no longer any good reason to reserve these names.)
- A compiler bug caused invalid code to be generated in the following situation:

         x: object
           m(p) { }
           n = (p)  // bad code generated here
           p = nil
         ;

  The bad code resulted from the compiler mistakenly using the local symbol table from the method m(p) while generating the code for n; so the compiler incorrectly treated p as a parameter variable in n, even though n has no parameters. This has been corrected.

  The local-to-Unicode character set mapper now converts any unmappable character found in a source string to Unicode U+FFFD, the standard Unicode "replacement character." In the past, the mapper converted unmappable characters to question marks, "?". Converting to question marks was undesirable because of the ambiguity it created. When compiling source code, for example, it led the compiler to think that the source file literally contained a question mark where the unmappable character was found; the diagnostics the compiler reported in these cases were thus confusing and misleading. Unicode defines the character U+FFFD specifically for the purpose of replacing source characters that cannot be mapped to Unicode; this gives the compiler and other consumers of mapped characters an unambiguous indication that the original input character was unmappable. The compiler uses this new information to report a specific diagnostic message when it finds a U+FFFD in the input stream.

### Changes for 3.0.10 (8/17/2006)

- Libraries (".tl" files) can now easily include their own multimedia resources in a build. In the past, there was no direct support for multimedia resources in libraries; an author using a library that included multimedia resources would have had to copy the library resources into the game's directory tree and then explicitly add those resources to the build. This is no longer necessary. Two new features support library resources:
  - First, Workbench for Windows now automatically adds each top-level library's directory path to the search list for individual resource files (.jpg, .png, .ogg, etc). Note that a "top-level" library is a library included directly in the Project window; a library included from within another library isn't top-level, so it's directory won't be included in the search list. When running the game under the debugger, this allows individual resources to be found under any library's directory tree.
  - Second, the compiler accepts a new "resource:" keyword in library (.tl) files. After this keyword, list one individual resource file, or one directory containing resource files. You can use this keyword as many times as you like to include multiple files or directories. As usual for library files, the file or directory mentioned after the "resource:" keyword is given with a URL-style relative path, relative to the library containing the library file.
  These new features allow a library to include multimedia resources with complete transparency to game authors using the library - game authors won't have to do anything extra to use the library multimedia resources. Library authors only have to perform a few easy extra steps. First, create a subdirectory of your library directory to contain the resources. For example, if your library is called mylib.tl, create a "mylibres" subdirectory under the directory containing mylib.tl. (The name isn't important, but it's desirable to pick a unique enough name that there won't be any conflict with other libraries that game authors might also be including. Your resources will be named relative to the subdirectory name, so don't pick a generic name like "resources" - it's best to use a name that incorporates your library name.) Second, put all of your library's resources (.jpg files, .png files, etc.) in your new subdirectory. Third, add the line "resource: mylibres" to your .tl file; this will tell the compiler to bundle all of the files in the "mylibres" subdirectory into the compiled .t3 file when a game includes your library. Finally, in the HTML that your library generates to reference your resources, refer to them using your subdirectory path - for example, you'd write <IMG SRC="mylibres/compass.png"> to refer to an image resource file.
- The t3GetStackTrace() function (in the 't3vm' function set) has a new optional argument that lets you get information on a single stack level. This provides more efficient access to stack trace information in cases where you only want information on a specific level, such as the immediate caller.
- When a game is compiled into a stand-alone executable (on systems where this is implemented, such as Windows), it's now possible to pass command-line arguments to the embedded .t3 program. To do this, use a dash ("-") to separate the interpreter arguments from the program arguments. The stand-alone version of the interpreter is also now strict about not accepting an image file argument; this means that you can't use a bundled stand-alone game to run a different .t3 image file.
- You can now write directly to the main game window's log file, if one is open. (This is the log file that's opened via the setLogFile() function - the one that the library creates when the player types the SCRIPT command.) There are two ways to write to the log file. The simple way is to use the new <LOG> tag - this tag is simply the complement of the <NOLOG> tag: any text enclosed between <LOG> and </LOG> will be included only in the log file, and hidden in the game window. This approach is usually the right one, because you can mix your log-only text directly with other output text, ensuring that it's processed through the usual stack of output filters and the like. However, on occasion it's useful to be able to bypass the usual output stream mechanism, which brings us to the second way: you can use logConsoleSay(), passing in the special handle value MainWindowLogHandle as the handle. Using this approach bypasses mainOutputStream and all of its filters, and goes directly to the log file.
- The compiler now warns on nested block comment ("/* ... */" comments). If the compiler finds a "/*" sequence within a block comment, it generates a warning. (Nested block comments aren't allowed, so a "/*" within a block comment usually indicates that a previous comment wasn't terminated properly. The warning makes it easier to notice such cases.)
- The compiler now automatically word-wraps error messages to 80 columns when the "verbose" error message option is selected. This makes the long error messages much easier to read, especially in Workbench, which has an essentially infinitely wide message window - the word-wrapping saves you the trouble of manually scrolling horizontally to see the full message text.
- A bug in the compiler sometimes caused a crash if a 'foreach' statement was used in a source file which never #included the system headers. The compiler correctly flagged the error, but didn't always recover properly. The compiler now handles this situation gracefully.
- A bug in the compiler caused the compiler to ignore the last line of a library (.tl) file when the last line didn't end in a newline character of some sort. The same bug affected Workbench on Windows. This has been corrected.
- A bug in the compiler caused incorrect results when a 'grammar' statement's token list started with an empty alternative. For example, the token list "( | 'x')" was compiled incorrectly. This problem only occurred when the empty alternative was the first element of the entire token list. This has been corrected.
- In the past, the TadsObject type didn't retain 'undo' information when the superclass list was changed with setSuperclassList(). This meant that if an object's superclass was changed, an 'undo' operation didn't properly restore the original superclass list. This has been corrected; this undo information is now properly retained and applied.
- A bug introduced in 3.0.9 caused the interpreter to misinterpret certain Unicode characters outside of the plain ASCII range when entered on a command line. This has been fixed.
- A bug in TadsObject.setSuperclassList() caused sporadic problems. The bug was most likely to manifest itself as a stack overflow error when a call to self.setSuperclassList() was the first (or nearly the first) executable code within a method. The bug is now fixed.
- The regular expression parser didn't accept the special character pattern <tab>, which is documented as matching the character '\t' (or, equivalently, '\u0009'). This has been corrected.
- The regular expression parser didn't formerly classify as whitespace several control characters that are conventionally considered whitespace. This was due to a strict interpretation of the character properties defined in the Unicode character database, which defines all of the ASCII control characters as class "Other" rather than "Separator." The Unicode database has some additional property information, though, that does mark the appropriate control characters as whitespace, and the character classifier now takes this extra information into account. This means that characters \u0009 (tab), \u000A (line feed), \u000B (line tab), \u000C (form feed), \u000D (carriage return), \u001c (IS4), \u001d (IS3), \u001e (IS2), and \u001f (IS1) are now considered whitespace, and thus match the <space> character class pattern in regular expressions.
- In the past, the compiler always assumed it was running under a DOS box, so it used the DOS box code page for any messages it displayed. On most systems, depending on localization, the DOS box uses a different code page from the Windows code page used by native Windows applications; this is because the DOS box is designed for compatibility with old MS-DOS applications, which sometimes rely upon the DOS line-drawing characters and so forth. This occasionally caused odd character mapping problems in error messages when compiling from Workbench, because Workbench uses the standard Windows code page instead of the DOS code page. This has been corrected, as follows: the compiler now checks to see if it's associated with a DOS box window, and uses the DOS box code page for its error messages if so, or the regular Windows code page if not.

### Changes for 3.0.9 (8/29/2005)

- The banner API has a new pair of style flags: BannerStyleHStrut ("horizontal strut") and BannerStyleVStrut ("vertical strut"). These style flags let you specify that bannerSetSize() should take a child banner's width (horizontal strut) and/or height (vertical strut) into account when figuring the parent banner's content size. By default, only the contents of the parent banner are considered, but these new styles let you include a child's contents in the parent banner's size calculation.
- The File intrinsic class has a new feature in its various "open" methods. The filename passed to an "open" method can now be one of a set of distinguished values (defined in file.h) that identify "special" files. These are files that are meant to be used for particular purposes. Rather than opening these files by name, you open them by specifying their special identifiers. The interpreter determines the actual name and location of a special file in the local file system. This allows the interpreter to use different names of paths on different systems, to better conform to local conventions. Currently, there's only one special file defined: LibraryDefaultsFile, which is a text file that's used to store the library's global settings.
- The new GrammarProd method getGrammarInfo() provides programmatic access to information on GrammarProd objects, which allows the game to retrieve full information on the 'grammar' statements in the source code. Sample code demonstrating how to use the new method to display a production's internal information in human-readable format is included in the samples directory, in the file gramdisp.t.
- The interpreter now uses the default file-contents character set rather than the display character set as the default for log file output. On most systems, this change won't have any noticeable effect, as the default display and file-contents character sets are usually the same anyway. However, on a few systems, the display and file-contents character sets can differ; it makes more sense on these systems to use the file-contents character set for log files than it does to use the display character set, since it's usually desirable to treat log files as ordinary text files.
- The new interpreter option "-csl charset" lets you explicitly specify the character set for log files, overriding the default. (The default log file character set is the file-contents character set, as described above.)
- The logConsoleCreate() function now accepts nil for the character set argument. This chooses the default log file character set.
- In tadsio.h, the constant InEvtNotimeout has been renamed to InEvtNoTimeout (that is, the "T" in "Timeout" has been capitalized). This change is simply cosmetic, for better consistency with the naming convention that each word in a symbol name starts with a capital letter. (The "o" in "Timeout" is still a minuscule, and this is consistent with the naming convention: in computerese, "timeout" is usually considered a single word.) To avoid breaking compatibility with code based on previous versions, the old name is still defined as a synonym for the new name.
- The Vector class's constructor now throws an error ("value out of range") if the maximum-length argument exceeds 65535, which is the maximum number of elements that a Vector can have. (In the past, attempting to create a vector with a maximum length of more than 65535 appeared to succeed, but didn't really; it actually created a vector with a maximum of n mod 65536, where n was the given length.)
- The compiler incorrectly considered the statement following a 'do-while' loop reachable if the loop's condition wasn't a constant 'true' expression, even if the condition itself was never reachable and the loop contained no 'break' statements. This caused the compiler to issue spurious warnings in certain obscure situations, such as when such a 'do-while' was at the end of a function that had returned values elsewhere; it also caused the compiler to fail to generate an "unreachable statement" warning when a statement followed such a loop. The compiler now correctly realizes that the statement following such a loop is unreachable, and generates control flow warnings accordingly.
- A compiler bug sometimes caused problems when generating code involving a nested anonymous function (that is, an anonymous function defined within another anonymous function), which was defined within an object method, and which made reference to local variables defined within two or more enclosing lexical contexts. The problem only affected code with all of these attributes, and then only showed up some of the time. The problem manifested itself as a spurious run-time error ("invalid index operation - this type of value cannot be indexed") when the nested anonymous function was invoked. This has been corrected.
- A bug in the compiler caused sporadic problems that sometimes included crashing the compiler when source code contained a constant expression involving a list indexed by a value exactly one greater than the number of elements in the list, as in "[1,2][3]". The problem only occurred when everything in the expression - all of the list elements, as well as the index value - was a constant. This has been fixed.
- Due to a bug, the compiler didn't recognize the "^=" (XOR-and-assign) operator. This has been corrected.
- A bug in the rexGroup() function caused the interpreter to crash in a particular, rare situation: specifically, when rexGroup() was called immediately after a call to rexSearch() or rexMatch() that caused a run-time error. This has been corrected.
- A bug in the interpreter sometimes caused unpredictable behavior, including crashes, when t3SetSay() was used to set a property pointer handler, and a double-quoted string was then displayed from within a function (not an object method). This has been fixed.
- A bug in the interpreter's console-output subsystem's HTML mini-parser caused subtle problems in some rare cases with the full multimedia interpreters (but not in text-only interpreters). For the most part, in the full HTML interpreters, the console subsystem just passes HTML markups directly through to the HTML renderer. It does, however, keep track of HTML sequences for its own purposes. One of these is to apply the "\^" and "\v" (capitalize and un-capitalize) flags to actual text rather than to HTML markups. The bug caused the HTML tracker to lose track of where it was in an HTML sequence when a tag included quoted attribute values. The only known symptom of the bug was that a "\^" or "\v" flag that appeared immediately before an HTML tag that contained quoted attribute values was sometimes misapplied to text within the HTML tag, effectively losing the effect of the flag. This has now been fixed.
- A bug in the Dictionary class caused problems when setting a string comparator object that wasn't a StringComparator object. The Dictionary allowed setting the new comparator, but would then generate a spurious error (usually "invalid type") on calling any of the methods that called comparator methods (addWord, findWord, etc). This has been corrected.
- The Vector.copyFrom() method had a bug that caused the wrong number of elements to be copied in some cases. In particular, when the destination vector had to be expanded to hold the new elements, the method copied one fewer element than was requested. This has been fixed.
- A compiler bug caused duplicate "unreachable statement" to be displayed when a 'switch' contained a case with an unreachable 'break' statement. The duplicate messages no longer occur.
- Due to a bug, the compiler sometimes crashed if a 'switch' statement contained an unreachable 'break' statement in one of its cases, and the statement immediately after the 'switch' was also unreachable. This has been fixed.
- The compiler is now more consistent about where double-quoted strings are allowed and not allowed. First, superficial parentheses are now accepted around double-quoted strings wherever the strings would otherwise be legal. Second, the comma operator can now be used to juxtapose two or more double-quoted strings; the effect is simply to display the strings in the order given, as though they had been concatenated into a single string. Third, the compiler formerly accepted double-quoted strings, incorrectly, if they were used within the 'true' or 'false' operands of a '?:' operator that was embedded within any larger expression. The compiler now correctly flags this as an error.
- The compiler is now stricter about flagging errors for a few syntactically invalid constructs that were formerly accepted. It's probably counterintuitive that more error messages are a good thing, but, really, they are in cases like this - if a construct is invalid, you're better off if the compiler catches it and tells you about it, because otherwise the compiler is going to do something poorly defined with the input. Without an error message, it won't be obvious that anything is amiss until the program starts behaving unexpectedly at run-time. The compiler now properly flags errors when it detects these constructs. Specifically, the compiler now enforces the following grammar rules:
  - Each formal parameter in a 'propertyset' declaration, including the "*" parameter, must be separated by exactly one comma from adjacent parameters.
  - 'transient' cannot be used in the definition of a new template - that is, "transient class template ..." is illegal.
  - Empty templates ("class template;") are illegal.
  - Parentheses are required around the condition expression of a do-while statement.
- The compiler now allows "local" declarations to be labeled (via regular labels as well as "case" and "default" labels). In the past, the compiler didn't allow labeled local declarations. There wasn't any good reason for this restriction; it was just a quirk of the way the compiler's grammar was defined.
- The toString() function formerly failed on conversions to base 2 of a value over 262143, with a run-time exception. This has been corrected, so the function should now properly convert any 32-bit integer value to a base 2 string representation.
- The toInteger() function now accepts base 2 as the input format.

- The compiler is now more tolerant of different newline formats in library (.tl) files. In the past, the compiler generally expected .tl files to conform to local newline conventions; this made it more difficult to re-use libraries on different operating systems, since it was sometimes necessary to convert newlines first. Source code files (.t and .h files) were never affected by this, but the part of the compiler that read .tl files wasn't as flexible. The compiler's .tl file reader now accepts essentially any newline format: it will accept newlines consisting of CR-LF sequences, LF-CR sequences, simple CR newlines, and simple LF newlines. It doesn't matter what your computer's native newline conventions are - every port of the compiler will now accept any of these formats.
- Due to a bug, the compiler's macro preprocessor didn't properly expand macros that included the #ifempty or #ifnempty operators. In particular, any text in the macro's definition prior to the #ifempty or #ifnempty was effectively discarded; the text wasn't included in the expansion. This is now fixed.

  ### Changes for 3.0.8 (9/12/2004)

  - The compiler now enforces unique naming for all of the modules in a project. Using the same name for two (or more) modules can cause problems, mostly because both modules would have the same filename for their object files and thus one would overwrite the other. In the past, when a module name conflict caused this kind of problem, the compiler reported the errors caused by the name collision, but it wasn't always easy to figure out that the name collision was the root cause. To avoid this potential source of confusion, the compiler now checks the entire project for module name collisions, and flags an error if any collisions are found.
  - The "file safety" levels have changed slightly to provide better security against malicious game programs. First, level 2, which formerly provided global read access but no write access, now instead provides read/write access to the current working directory only (the game isn't allowed any access to files outside of the working directory). Second, the default safety level is now level 2. In the past, level 1 (read from any file/write to current directory only) was the default, which left open the possibility that a game could access data outside of the working directory. A malicious game could conceivably have exploited this by, for example, secretly copying sensitive data to the game directory for later use by a coordinating network worm, or by encoding the data in a hyperlink (displayed in an HTML-enabled game) that takes the player to a spyware site when clicked. The new default setting should effectively eliminate these risks by barring access to any files outside of the working directory.
  - Several of the system headers formerly lacked #include directives for other headers they depended upon. This didn't cause problems most of the time, since the necessary headers were usually included from somewhere else anyway, but it meant that you had to include system headers in the right order to avoid compiler errors. Each of the system headers now explicitly includes any other headers it depends upon, which ensures that each system header can be included in isolation, and in any order with respect to other headers.
  - The saveGame(), restoreGame(), and restartGame() intrinsic functions can now be called from recursive VM invocations (that is, from contexts where a call to an intrinsic function or method has invoked a byte-code callback function, such as an anonymous function passed to an iteration method on a collection object). This restriction was needed in the distant past, but it's been vestigial since version 3.0.5a (when the save/restore mechanism was overhauled to exlude the call stack and execution context from the saved state information). Since the restriction is no longer necessary, it's now been removed.
  - In the intrinsic function getLocalCharSet(), the new constant CharsetFileCont can be used to retrieve the name of the character set typically used for the contents of text files on the local system. (Note that this is only the typical character set for text files on the local system; there's no guarantee that any particular file uses this character set. The actual character set of a given text file is determined by the user and application that created the file.)
  - In tadsio.h, the constant CharsetFile (for use with the getLocalCharSet() function) has been renamed to CharsetFileName. The name change is to emphasize that the constnat refers to the character set used in the local file system for names of files, as opposed to the contents of text files.
  - The compiler sometimes incorrectly complained about a missing option argument when a "-x" option (with a valid argument supplied) was used at the very end of a command line. This has been corrected.
  - A bug in the compiler occasionally caused floating point constants that included exponential ("E" suffixes) to be mis-parsed. When this happened, one or more spurious, random extra digits of precision were added to the end of the number's mantissa. This has been corrected.

  ### Changes for 3.0.7 (6/12/2004)

  There are no changes to the compiler or interpreter core in this release. The only changes in the adv3 library and the Windows HTML TADS interpreter.

  ### Changes for 3.0.6q (5/9/2004)

  There are no changes to the compiler or interpreter core in this release. The only changes are in the adv3 library and the Windows HTML TADS interpreter.

  ### Changes for 3.0.6p (4/25/2004)

  - The regular expression parser now accepts the special character codes <lbrace> and <rbrace> for left and right "curly" braces, "{" and "}", respectively. Since curly braces are special characters in regular expressions, it's convenient to have named character codes for them.
  - In the past, the regular expression parser accepted a closure modifier (a "*", for example) directly following an assertion expression. Since assertions don't consume any input text, repeating one with a closure doesn't change the meaning of an expression, so a closure following an assertion is meaningless. However, doing so had the undesirable effect of creating an infinite loop, as the regular expression matcher tried pointlessly to find out how many times a successful assertion could be successful (the answer is always: as many times as you try). The regular expression parser now avoids such infinite loops by simply ignoring any closure modifier that's applied to an assertion. (Note, however, that you can still trick the parser into building an infinite loop with a more complex expression. For example, you can enclose one or more assertions in parentheses, and then apply a closure to the parenthesized group. The regexp parser isn't sophisticated enough to detect these more subtle infinite loops; it can only detect the obvious kind where a closure is applied directly to an assertion.)
  - A bug in the compiler caused incorrect results when an anonymous function referred to a property of "self," when the function was defined within a list value of a property. The property evaluation within the anonymous function typically yielded nil in these cases, even when that property had a non-nil value in the object containing the property with the list value containing the anonymous function. The same problem showed up whether the property containing the list value was defined with the ordinary "prop = val" syntax or with a template. This has been corrected; properties of self will now yield correct results in these cases. To be more concrete, in the example below, evaluating testObj.prop1[1]() should display "hello!" on the console, and now does this correctly; but in the past, this example displayed nothing, because the evaluation of prop2 within the anonymous function yielded nil.

          testObj: object
            prop1 = [ {: say(prop2) } ]
            prop2 = 'hello!'
          ;

  - A bug in the compiler caused the compiler to crash in some cases when presented with an anonymous function within a list value of an object property defined with a template. The problem has been corrected.
  - The compiler incorrectly reported a standard-level warning when a function or method "list parameter" was unused within the function or method. (A list parameter is a formal parameter defined in square brackets to indicate that it receives a list containing the actual parameters, which can vary in number, when the method is called.) The compiler also incorrectly reported the warning as an assigned but unused value; it should have reported it as an unused parameter instead. The compiler now reports the correct warning, and only reports it at "pedantic" level; this makes the handling of list parameters consistent with the treatment of ordinary formal parameters.

  ### Changes for 3.0.6o (3/14/2004)

  - The MIME type for saved position files has been changed to "application/x-t3vm-state". The Windows installers have been updated to reflect the new MIME type.

  ### Changes for 3.0.6n (3/6/2004)

  - The debugger now automatically includes "self" in the local variable list whenever examining a frame in which "self" is valid.
  - On Windows, the installers now add the MIME type for the compiled game file type (.t3) and the saved position file type (.t3v) to the system registry. This information can be helpful to applications, particularly those that perform file transfers. (The MIME type for a compiled game is "application/x-t3vm-image", and the type for saved position files is "application/x-t3vm-save".)
  - A compiler bug caused the compiler to crash when certain obscure kinds of syntax errors occurred inside nested object definitions. This has been corrected.
  - A bug in the compiler caused the compiler to crash when it was attempting to parse a one-line function or method that contained an unclosed anonymous function. The problem was most likely to be seen when the errant one-liner was the last thing in a source file. The compiler now generates appropriate error messages and terminates normally.
  - A bug in the ByteArray class caused the VM to crash when a ByteArray was used as a key in a LookupTable. This has been corrected.
  - A bug in the BigNumber class caused the VM to crash in some cases when a string was used as the source value to construct a new BigNumber. This should now work reliably.
  - A bug in the debugger caused a crash when execution stopped inside an anonymous function with no 'self' context. The most common place to encounter this problem was at a run-time error in an anonymous function defined inside a list, such as in an EventList object. The problem has been corrected.
  - On Windows, the Author's Kit installer failed to create the samples\obj subdirectory. That subdirectory is required to build the sample game (sample.t3m) included in the kit, so you had to manually create the directory before you could compile the game. The installer now automatically creates the directory.
  - The BigNumber class incorrectly returned a result of zero when dividing zero by zero. (This only happened when the dividend was zero; for other dividend values, a divide-by-zero exception was correctly thrown.) This now throws a divide-by-zero exception.

  ### Changes for 3.0.6m (11/15/2003)

  Note: 3.0.6l was a library-only release, so there was no system release called 3.0.6l.

  - The propNotDefined mechanism is now invoked when 'inherited' fails to find a base class implementation of the method being inherited. This works almost exactly the same way it does when propNotDefined is invoked during a normal method/property call, with only one difference: when 'inherited' fails to find a base class property, it searches for a 'propNotDefined' using the same search pattern it used to seek the original inherited property. For example, consider this code:

          export propNotDefined;

          class A: object
            propNotDefined(prop, [args]) { "This is A.propNotDefined\n"; }
          ;

          class B: A
            propNotDefined(prop, [args]) { "This is B.propNotDefined\n"; }
            p1() { inherited(); }
          ;

          main(args)
          {
            local x = new B();
            x.p1();
          }

    When this program is run, the result displayed will be "This is A.propNotDefined". B.p1() attempts to inherit the base class definition of p1(); when it doesn't find an inherited definition, it searches for propNotDefined() using the same search pattern it used to find the inherited p1(). That is, the search starts with B's superclass, because that's where the search for the inherited p1() started from.

  - The t3SetSay() intrinsic function now returns the previous default output function or method. (The return value corresponds to the argument value: if the argument sets a new function pointer, the return value is the old function pointer; if the argument is a new property ID, the return value is the old property ID.) This allows code to save the old value for later restoration, if desired. In addition, the new special argument values T3SetSayNoFunc and T3SetSayNoMethod can be specified to cancel any existing default output function or method, respectively, and the function returns these values when needed to indicate the absence of a previous setting.
  - The t3SetSay() function now accepts an anonymous function as the default output function. (In the past, only a regular named function was acceptable.)
  - When propNotDefined() is invoked, the interpreter now sets 'targetprop' to &propNotDefined. In the past, the interpreter incorrectly set 'targetprop' to the property originally invoked. This was incorrect; one important consequence was that it didn't allow propNotDefined() itself to use 'inherited' to invoke the base class's implementation.
  - The compiler now automatically adds a property called 'sourceTextOrder' to each non-class object defined in a source file. The value of the property is an integer giving the object's order in the source file in which it's defined. This value is defined to increase monotonically throughout a source file, so you can use it to sort a collection of objects into the same order in which they appear in the source text. This property is useful when you want to create an initialized structure of objects (such as a list or a tree), and you want objects within the structure to have the same order at run-time that they have in the source text. In the past, there was no straightforward way to guarantee source text ordering, because the compiler and linker assign object ID's in arbitrary order. This new property is guaranteed to reflect the original source text order, so you can use it to initialize the run-time order. Note that a 'modify' statement doesn't assign a new sourceTextOrder to the underlying object; the original sourceTextOrder is retained for a modified object. Note also that sourceTextOrder only tells you the relative order of objects within a single source file; the compiler resets the counter at the start of each new source file, so it's not meaningful to compare sourceTextOrder values for objects in different source modules.
  - The toInteger() function now accepts an integer value as its first argument. If the first argument is an integer, the function simply returns the same value; the optional second argument (the radix value) is ignored if present.
  - The BigNumber constructor now accepts another BigNumber as the source value. This creates a new BigNumber with the given source value at an optional new precision, rounding the original value if the new precision is less than that of the source value.
  - The BigNumber method formatString() incorrectly returned an empty string when formatting a fractional number if the maximum digit count for formatting was insufficient to reach the first non-zero digit of the fractional value. For example, 0.0001.formatString(3) returned an empty string. The method now returns '0' for these cases.
  - In most of the character-mode interpreters, if a line of highlighted or colored text appeared just before a "MORE" prompt, subsequent text was incorrectly highlighted or colored like the line before the "MORE" prompt. This has been fixed.
  - The character-mode interpreters very occasionally crashed on exit, due to a bug in the termination code. This has been corrected.
  - In most of the character-mode interpreters that support the "-plain" mode, the interpreter is now more thorough about flushing the standard output before stopping to read input. This makes the plain mode interoperate better with other programs using "pipes" and similar OS-specific input/output redirection. This change pertains to the MS-DOS and Unix versions, and to any other platforms based on the common character-mode layer (known technically as "osgen3").
  - The rand() function now accepts a Vector as its argument. A vector argument behaves the same as a list argument: the function randomly chooses one of the elements of the vector and returns it.
  - A bug in the TadsObject.createInstanceOf() method caused an incorrect value to be left on the VM stack during creation of the new object. This showed up as an incorrect argument value if a method was invoked on the new object as part of the createInstanceOf() expression. This has been corrected.
  - The text-only interpreters incorrectly paid attention to a <BODY> tag within an <ABOUTBOX> tag, setting any color scheme specified in the <BODY> tag. This improperly set the main text window to the color scheme intended only for use inside the about-box. This no longer occurs.
  - The forEachAssoc() method of the List and Vector intrinsic classes incorrectly passed a zero-based index for the 'key' parameter to the callback (that is, the first element was identified by index 0, the second by index 1, etc., C-style). This should have been a one-based index for consistency with all of the other indexing operations for List and Vector. This is now fixed.
  - Vector.setLength() will now throw an error if the given length is less than zero. (In the past, it accepted an invalid length, leading to unpredictable results.)
  - Under certain conditions, the debugger didn't stop in response to a "Break" key (Ctrl-C, Ctrl+Break, or whatever key is appropriate to local convention). In particular, if a single line of code contained an infinite loop, and the user ran the program, broke into the loop once, and then resumed execution, the debugger ignored subsequent break keys. This has been corrected.
  - The compiler incorrectly reported errors in the branches of an 'if' statement at the line of the 'if' itself if the branches were bare statements (not enclosed in braces). The same applied to 'while', 'for', and 'do while' statements when their bodies were bare statements. The compiler now reports these errors at the sub-statement locations.
  - The compiler generated an incorrect debugger line number record under certain obscure circumstances: if the source file contained an object or class based on multiple superclasses, and the class didn't define an explicit constructor, then the compiler generated an incorrect line record for the last executable line of code in the file. This is now fixed.
  - The compiler now shows Unicode escape sequences when displaying an error message containing characters from the source file that can't be represented in the compiler console character set. For example, if you're running the compiler in a terminal window on Unix, and your terminal window is set up to display Latin-1 (ISO-8859-1) characters, and you're compiling a source file prepared in Latin-2, your terminal window would be unable to correctly display some of the characters in the source file, because Latin-2 has characters that aren't part of Latin-1. In the past, if any of these "unmappable" characters were shown as part of a compiler error message, the compiler showed them as question marks. Now, the compiler shows them as "backslash" escape sequences. For exampe, Latin-2 character 171, "T with caron," would be displayed as "\u0164", since its Unicode code is 0x164. This change doesn't affect the display of compatible characters - all mappable characters will still be displayed in the local character set. This only affects characters that were formerly displayed as question marks.
  - The default "file safety level" is now 1, which allows reading from any file and writing only to the current working directory. This default setting provides games with reasonable flexibility, but helps prevent the possibility that a malicious author can modify important files on your hard disk by limiting writing operations to the game's working directory only. You can override this using the "-s" option if you want to set a more permissive or more restrictive safety level.
  - In Workbench for Windows, the "Build for Release" command didn't properly invoke the "t3res" command for building external resource files (.3r0, etc). This now works properly.
  - A problem in the debugger caused sporadic bad behavior when a finalizer method threw an exception (out of the finalize() method; throwing around exceptions within a finalizer was fine, as long as the exception was caught entirely within the finalizer). This manifested itself in numerous different ways, ranging from no visible effects to full Workbench crashes. The problem only occurred in the debugger; the regular non-debug VM didn't have the problem. This has now been corrected.
  - The VM now recovers more gracefully from stack overflow exceptions. In the past, stack overflows tended to be unrecoverable because the VM would usually encounter a second stack overflow in the course of trying to create an exception object to represent the original stack overflow, forcing the VM to terminate the game summarily to avoid an infinite loop of exceptions thrown while handling exceptions thrown while handling exceptions, ad infinitum. The VM now keeps a small emergency reserve of stack space for handling stack overflow errors, which should in most cases allow an exception object to be created normally, which in turn allows the game to catch and handle the exception just like any other run-time error.
  - The debugger now gives you more flexibility in recovering from stack overflow errors. In the past, if your program caused a stack overflow (due to infinite recursion, for example), the debugger itself was unable to evaluate expressions without itself encountering stack overflows, since the debugger shares the stack with the VM. The debugger now holds some of the stack in reserve specifically for handling stack overflows; when a stack overflow occurs, the debugger uses the reserve for its own purposes, allowing you to evaluate expressions and carry on normally within the debugger. This makes it easier to figure out why the stack overflow occurred. Note that you can often use the debugger to recover from a stack overflow by manually moving the execution pointer to a 'return' statement (or the end of the method), breaking off the infinite recursion that caused the overflow.
  - The debugger now shows anonymous functions more descriptively in stack traces. In the past, these showed a string like "[1234].prop#0(5,6)"; now, the debugger shows "{anonfn:1234}(5,6)" instead. The "1234" is an internal object identifier for the anonymous function; this conveys no specific human-readable meaning other than to distinguish one function from another. The corresponding change has also been made in reflect.t, in reflectionServices.formatStackFrame().

  ### Changes for 3.0.6k (8/17/2003)

  - The debugger now supports stop-on-change conditional breakpoints. When you create a breakpoint with a condition expression, the debugger now offers a choice between stopping when the expression evaluates to true or stopping when the expression's value changes. In the past, there was no choice, and only stop-when-true conditions were supported. Stop-on-change is now the default when creating a new global breakpoint.
  - The system.tl library now includes the default system startup module, _main.t. In addition, it sets the new library flag, "nodef", to indicate that the library replaces the default system modules that the compiler would otherwise include in the build automatically. This change primarily benefits users of Workbench for Windows, in that it causes Workbench to include _main.t explicitly in the list of source files. This makes it more convenient to view the file within Workbench, set breakpoints inside it, and trace into it. (This change will have no effect on most existing games. The only games affected would be those that include system.tl and include a non-standard startup module, using the "-nodef" compiler flag to suppress the default inclusion of _main.t. This is an unlikely scenario, but if it applies, here's what to do: drop the "-nodef" compiler flag from your project file, and instead add "-x _main" immediately after the "-lib system" inclusion.)
  - The new directive "nodef" can appear within a library (.tl) file. This instructs the compiler that the library includes the same modules that the compiler would include by default, or replacements for the standard modules. If a library includes the "nodef" directive, then including that library in the build has the same effect as including the "-nodef" option on the compiler command line or in the project (.t3m) file.
  - In the past, the text-only interpreters didn't properly handle banner size settings that exceeded the available screen size. The text-only interpreters will now limit a banner's size to the available space on the screen when the requested size is too large.
  - The AnonFuncPtr intrinsic class now correctly identifies itself as a subclass of Vector (via ofKind and getSuperclassList).
  - The AnonFuncPtr intrinsic class now compares and hashes by reference, rather than by value as its Vector base class does.
  - The banner function bannerSetSize(), when applied to a text window (BannerTypeText), now takes into account the space used for margins and borders when sizing in "absolute" units. This ensures that if you ask for a height of five rows, for example, then the window will actually be large enough to display five rows in the default font, without any scrolling. In the past, the margins weren't taken into account, so the actual capacity of a banner wasn't necessarily the same as the requested nominal size in absolute units.
  - The run-time symbol table now omits "intrinsic class modifier" objects. These objects have been filtered out of firstObj/nextObj iterations since 3.0.6c; they're now filtered out of the symbol table for the same reasons, and for consistency with firstObj/nextObj. (In the past, these objects appeared as symbols of type object, with names of the form " 99", and with no superclasses. These are internal implementation objects that are meaningless to the game program, so there's no reason for the symbol table to include them.)
  - A problem in the List and String classes caused the VM to crash in certain very rare cases when evaluating properties of constant list or string values. This has been corrected.
  - A bug in the Dictionary intrinsic class's findWord() method sometimes caused strange behavior, most noticeably as corruptions in the values of local variables in the invoking code. The problem only occurred when the method was called in its single-argument form. The problem has been fixed.

  ### Changes for 3.0.6j (8/2/2003)

  - The new TadsObject method setSuperclassList() enables the game program to change an object's superclass list dynamically. The method takes a list giving the new superclass list for the object.
  - It's now legal to explicitly define a 'location' property in an object definition that also uses the '+' notation to set the object's location. The compiler specifically treats an explicit 'location' property setting as overriding the value set with the '+' notation, rather than considering the redefinition a conflict as it did in the past. This allows logically related object definitions to be kept close together in the source code even when some of the objects are part of a location tree and others are not; this happens fairly frequently, because simulation objects sometimes have abstract helper objects that don't participate in the normal location hierarchy.
  - Templates can now include alternative groups that are optional. If any element of an alternative group is marked as optional, then the whole group of alternatives is optional.
  - The new macro perInstance(expr), defined in the system header file tads.h, can be used to define a property in a class such that the property will be set to the value of the expression 'expr' separately for each instance of the class. For each instance, the expression is evaluated the first time that instance's value of the property is accessed, and then stored with that instance.
  - The compiler now has the ability to bundle resource files into the image (.t3) file as part of the main compilation ("t3make") step, without running the "t3res" utility as a separate step. This lets you include resource files in your project's makefile (the .t3m file), which means the makefile can now specify the entire build procedure for most types of projects. To add resources with t3make, add the new "-res" option after all of your source and library modules in the .t3m file, and list your resource files after the "-res" option. The syntax for the resource list following the "-res" option is the same as the "t3res" utility, except that the "-add" option is not allowed (as adding resources is the only possibility).
  - Workbench for Windows now allows you to add a resource file to a project before the resource file exists. To add a resource file that you haven't yet created, use the usual menu command to add a resource file, then type the name of the file into the file selector dialog. The dialog will allow you to type the name of a file that doesn't yet exist. This is handy when you want to include a resource file that won't be created until your pre-initialization code runs, such as the "gameinfo.txt" file.
  - The compiler is now able to determine automatically if relinking is needed due to a change in the set of modules included in the build. This is accomplished by checking a small bit of additional data in the .t3 about the set of object modules involved in the build. (The new information is simply a 32-bit "checksum" of the module source file list, so it adds only four bytes to the image file. It's not enough information to allow a user to recover a list of your source files by reverse-engineering the image file, so you don't have to worry about any possibility that a user could obtain "hints" this way. Because only a checksum is stored, there's a very small possibility that a change to the source file list could result in an identical checksum, in which case the compiler would not notice that relinking is required. The probability of this happening is extremely small, but if you ever suspect it, you can always use the "-al" option to force a relink.) Note that this doesn't affect the compiler's use of file timestamps to determine build dependencies; this is simply an additional check the compiler makes to detect when a new module is added to the build or an old module is removed.
  - The ByteArray intrinsic class has two new methods, readInt() and writeInt(), that make it easy to translate between integer values and byte representations of those values. This is especially useful for reading and writing binary files. The new methods let you read and write integers in 8-bit, 16-bit, and 32-bit sizes, signed or unsigned, and in little-endian or big-endian format.
  - The File intrinsic class has a new method, getFileSize(), which returns the size in bytes of the file.
  - A bug in the File intrinsic class sometimes caused the VM to crash when a read operation was attempted after a seek operation. This has been corrected.
  - The starter game templates now include startup handling for startup-and-restore. When the player launches the interpreter using a saved-game file, the interpreter invokes the startup-and-restore code, which the game must provide in a routine called mainRestore(). The starter templates now include a mainRestore() routine, and handle main() and mainRestore() using a common subroutine called mainCommon(). This change will make it much simpler for authors to include proper startup-and-restore support in their games, by providing a ready-made framework with the necessary code.
  - Fixed a bug in Workbench for Windows: checkboxes in the Project window didn't work for nested libraries; clicking on the checkbox for a nested library simply had no effect. These checkboxes now work properly; clicking on a library checkbox checks or unchecks the library and all of the files within the library.
  - The Win32 character-mode interpreter (t3run.exe) now includes a desktop icon in the executable file. This allows you to use the "-icon" option with maketrx32 to add your own custom icons to games you bundle as executables using the console-mode interpreter.
  - A bug in the regular expression matcher failed to handle the shortest-match closure modifier (specified with a '?' suffix to a '*' or '?' operator) properly. This bug was introduced in the regular expression processor rework in 3.0.6h, and has now been corrected.
  - In certain unusual cases, the debugger incorrectly included a property in property enumerations when the property was actually a method. This happened when a method overrode a property defined as a simple data value in a superclass. The debugger isn't meant to show methods in property enumerations, since invoking a method will naturally invoke any side effects of the method. This has been corrected.
  - In Workbench for Windows, projects created in the root directory of a disk (C:\, D:\, etc) caused a number of problems, including crashes during compilation. These problems have been corrected, so creating a project in a root directory is now safe.
  - In Workbench for Windows, the compiler incorrectly wrote the object files to the working object directory when compiling for release, overwriting the object files for the debug build. This didn't do any harm apart from requiring a full recompile for debugging after any release build, which the compiler automatically sensed and performed, but it caused an unnecessary delay. The compiler now correctly sends release build object files to a temporary directory, so that the debug build object files are retained through a release build.
  - The new-project wizard in Workbench for Windows will no longer accept a source filename that ends in an extension reserved for makefiles or compiler-generated files (.t3m, .t3, .t3o, .t3s). This makes it more difficult to accidentally create a source file that will be overwritten by the compiler or by Workbench with generated files.
  - The compiler will now recompile an object file if the symbol file is more recent. Compilations that fail due to a syntax error can leave a project partially compiled, so that all of the symbol files but not all of the object files have been recompiled. In the past, correcting such an error and then recompiling did not always compile all of the necessary modules. This change ensures that all modules noted as requiring compilation on the first attempt will be noted again on subsequent attempts, even if the first attempt fails part-way through.
  - Due to a bug in the VM, throwing exceptions out of a native-code callback context (such as out of the callback to a Vector or LookupTable iteration method) sometimes caused the VM to lose track of the calling exception handlers; this caused symptoms such as sending the exception to a "catch" block other than the innermost eligible one. This problem tended to show up when an exception was thrown out of a callback context, and then the same exception was thrown again on a later invocation. This has been corrected.
  - If a Vector contains a reference to itself, or to a Vector containing a reference to the first Vector, indirectly to any depth, then an attempt to compare the Vector to another Vector, or an attempt to use the Vector as a key in a LookupTable, will fail with a run-time exception ("maximum equality test/hash recursion depth exceeded"). Since Vector equality comparisons and hash calculations are defined recursively by value, Vectors with direct or indirect self-references cause the equality and hash calculations to recurse infinitely; the Vector class avoids this infinite recursion by throwing the exception when the recursion becomes too deep. Note that this also effectively limits the depth of a Vector tree when used in an equality test or hash value calculation, even if the tree is acyclic; the limit is 256 levels.
  - When reading input from a script (using the REPLAY command, for example), the interpreter now ignores morePrompt() calls. This allows script replay to proceed unattended, without unnecessary interactive pauses.
  - In the debugger, if the game was interrupted by a real-time event while the player was editing a command line, and the debugger took control (via a breakpoint, for example) inside the real-time event, and the game was then terminated from within the debugger (while still stepping through the real-time event code) and then later restarted, a bug in the console manager caused strange behavior, sometimes including crashing the debugger. This has been corrected.

  ### Changes for 3.0.6i (6/15/2003)

  - Due to a compiler bug, when a template was defined using the "|" symbol to list a set of alternatives for a token position, object definitions using the template failed to match the last alternative of a set. All alternatives in a set are now properly recognized.
  - The gameinfo.t module has been removed. In its place is a new mechanism in the library that writes the GameInfo file automatically during pre-initialization, based on the definitions in the game's GameID object.
  - The Tokenizer class now gives each rule a name, which is simply a string value by which the rule can be identified. This changes the format of the rule list entries - each rule list entry has the new name value as its first element. Any subclasses or modifications of Tokenizer must use the new rule format.
  - The Tokenizer class has some new methods that allow rules to be added or removed. insertRule(rule, curName, after) inserts the new rule given by 'rule' before or after the existing rule named 'curName'; the new rule is inserted before the existing rule if 'after' is nil, after the existing rule if 'after' is true. insertRuleAt(rule, idx) inserts the new rule given by 'rule' at the index given by 'idx' in the rule list. deleteRule(name) deletes the existing rule with the given name, and deleteRuleAt(idx) deletes the existing rule at the given index in the rule list.

  ### Changes for 3.0.6h (6/7/2003)

  - The "modify" keyword can now be used to define functions. Modifying a function works just like replacing a function with the "replace" keyword, except that the new function can invoke the previous version of the function by using the "replaced" keyword. Refer to the Procedural Code section of the documentation for details.
  - Two new TadsObject methods, createInstanceOf() and createTransientInstanceOf(), enable a program to dynamically instantiate an object based on multiple superclasses. Refer to the TadsObject reference for details of the new methods.
  - The object template syntax has been extended to include optional elements and alternative elements. An element is marked optional by placing a question mark after it; alternative elements are separated by '|' tokens.
  - Several string search and regular expression intrinsics accept a new optional argument specifying the starting index in the string for the search. If the index argument is specified, then the search will start from the given character index; the index value 1 indicates that the search starts from the first character of the string, which is the default if the index parameter is omitted. This change allows algorithms that search for repeated occurrences of a substring or pattern to be written more efficiently, since they won't have to split up the source string to continue searching for additional occurrences.
    - String.find(str, index?)
    - String.findReplace(origStr, newStr, flags, index?)
    - rexMatch(pat, str, index?)
    - rexSearch(pat, str, index?)
    - rexReplace(pat, str, replacement, flags, index?)
  - A new banner style flag, BannerStyleMoreMode, causes a banner window to use "MORE" mode. This means that any time text displayed to the banner fills the available vertical space in the banner window, the interpreter will display some sort of prompt to the user, and then wait for the user to acknowledge the prompt. The exact nature of the prompt and acknowledgment varies by platform; usually, the interpreter displays a prompt like "[MORE]" at the bottom of the overflowing window, and waits for the user to press a key. The purpose of MORE mode is to ensure that the user always has a chance to read all of the displayed text before it scrolls off the screen. Note that BannerStyleMoreMode implies BannerStyleAutoVScroll, since it only makes sense to pause for a MORE prompt when new text would cause old text to scroll away, and this only happens when the auto-vscroll style is used.
  - The forEachInstance() function now allows the callback to break out of the iteration loop by throwing a BreakLoopSignal exception. Throwing this exception simply terminates the loop and returns to the caller of forEachInstance(). You can conveniently throw the exception using the "breakLoop" macro (defined in tads.h).
  - A new utility function has been added to the base library (in _main.t): instanceWhich(cls, func). This function iterates over instances of the given class cls, and calling func on each instance; func is a pointer to a function taking one parameter, which is the current instance in the iteration. instanceWhich() returns the first instance for which the callback function func returns a non-nil and non-zero value. Note that the function iterates instances in arbitrary order, so if there are multiple instances of cls for which func returns true, the return value will simple be the first of these visited in the arbitrary iteration order. If func doesn't return a non-nil/non-zero value for any instance of cls, the function returns nil.
  - The setLogFile() function now takes an optional second parameter specifying the type of log file to open or close. The possible values are LogTypeTranscript, to create a transcript of all input and output; and LogTypeCommand, to create a record of only the input commands. The default, if the parameter is omitted, is LogTypeTranscript.
  - The character mapper now accepts the IANA standard names for the various Unicode encodings supported in TADS 3: "UTF-8", "UTF-16BE" (for the 16-bit big-endian encoding), and "UTF-16LE" (for the 16-bit little-endian encoding). These names are case-insensitive, and can be used anywhere a character encoding name is required (#charset, new Charset(), etc). The old non-standard names for the same character sets ("utf8", "unicodeb", and "unicodel") are still accepted as well.
  - The compiler now accepts source files that start with a Unicode UTF-16 byte-order marker (i.e., the "FF FE" or "FE FF" byte sequences) and also specify a #charset directive. The #charset directive in such cases must (1) itself be encoded in the 16-bit Unicode encoding implied by the byte-order marker, and (2) designate the character set name that matches the byte-order marker (so a file encoded in big-endian UTF-16 must have a #charset "utf-16be" directive, and a file encoded in little-endian UTF-16 must have a #charset "utf-16le" directive). The #charset directive is optional in these cases, since the compiler can correctly infer the encoding based on the byte-order marker alone.
  - The compiler now accepts source files that start with a Unicode UTF-8 byte-order marker. The compiler infers that the file is encoded in UTF-8 if it sees this sequence. Note that there is only one valid UTF-8 encoding, so the UTF-8 byte order marker is always the same (i.e., there is no "big-endian" or "little-endian" flavor of UTF-8; there's only UTF-8). A #charset "utf-8" directive is allowed but not required immediately after the UTF-8 three-byte byte-order marker sequence. This change is required because some text editors that save in UTF-8 format write the byte-order marker character at the start of the file.
  - A new compiler option, -quotefname, tells the compiler to quote filenames when reporting the source file location of an error. If this option is specified, the compiler encloses these filenames in double quotes, and "stutters" any double-quote characters that are part of the filenames themselves (that is, each double-quote character that's actually part of a filename is shown as two double-quote characters in a row). This change is intended to make it easier for automated tools to parse the compiler's error message output, by ensuring that filenames can be predictably parsed regardless of any special characters that might appear within.
  - The compiler now displays an initial status message indicating the number of files it will need to build. This is designed for use by automated tools, to give them an estimate of the amount of work to be done; this can be used, for example, to show a progress bar indicator as the compilation proceeds.
  - In the compiler options file (the .t3m file), certain options (-I, -o, -Os, -FL, -FI, -Fs, -Fy, -Fo, -source, -lib) can be specified using URL-style notation, to ensure portability of the .t3m file across different operating systems. In the past, the compiler didn't properly translate these options to local conventions when they contained '/' characters to separate path elements. The compiler now properly converts URL-style paths to local conventions.
  - When an object is defined with an undefined or invalid superclass name, and the object definition uses a template to define property values, the compiler now reports an "undefined superclass" error rather than an error with the template format. In cases where a superclass name is merely misspelled, the compiler will naturally fail to find a matching template for the object, since the misspelled superclass name probably doesn't have any templates associated with it; thus, the template error is secondary to the true problem, which is the misspelled superclass name. This change should make the diagnostics more useful by reporting the true problem rather than the missing-template side effect.
  - Text Grid windows no longer consolidate runs of whitespace; instead, all whitespace written to a text grid window is treated literally.
  - Text Grid windows incorrectly interpreted HTML markups in the text-only interpreters. This has been corrected; text displayed to text grids is now treated literally on all interpreters.
  - Workbench now automatically saves the project (.t3m) file settings upon starting execution of the game in the debugger, and also saves the recent game order whenever a new game is loaded. These measures help reduce the chance of data loss in the event that Workbench crashes while the game is running (which it ideally should never do at all, but until the glorious day when it's perfectly bug-free, this extra saving will at least make crashes a little less painful).
  - Due to a bug, Workbench on Windows did not start up correctly when it was started by double-clicking on a .t3m file from the Windows desktop. (Workbench started with a blank interpreter window, but didn't show the main Workbench IDE window at all.) This has been corrected.
  - A bug in the debugger caused the debugger to crash under certain obscure circumstances. In particular, the crash occurred if the game caused a stack overflow, and the overflow happened to occur on a recursive VM invocation from an intrinsic method (such as when an intrinsic class method invokes an anonymous function callback). This has been corrected.
  - In the past, the compiler generated an output function call for the intial empty portion of a double-quoted string of the form "<<expr>>..." (in other words, a string with an embedded expression immediately after the open quote). The compiler no longer generates this superfluous empty string output operation, slightly reducing code size and execution time.
  - The String intrinsic class failed to enforce the 64k length limit for an individual string in some cases; exceeding the limit caused problems ranging from corrupted string text to crashes. This has been corrected; the interpreter now throws a run-time exception ("string is too long") if creating a string (via concatenation, for example) would exceed this limit. The List intrinsic class is likewise more assertive now about enforcing its 64k limit as well.
  - The regular expression functions (rexMatch, rexSearch, rexReplace) were capable of causing the interpreter to crash (with a system stack overflow) when asked to match a pattern to an extremely long string. The exact limits varied by platform according to the amount of system stack space available; on Windows, the problem started occurring with strings about 5,000 characters long, although the exact length was also a function of the complexity of the regular expression pattern. This has been corrected; the regular expression matcher no longer uses a recursive algorithm, so its consumption of system stack space is now fixed and small. The matcher still consumes memory that scales according to the length of the input string and the complexity of the regular expression, since such memory consumption is inherent in the task; but the memory consumed is no longer in the system stack, which means among other things that the matcher can now recover gracefully (by throwing an "out of memory" run-time exception) if it should exhaust available memory while working.
  - In the DOS/Windows version, the executable file bundler (maketrx32) didn't look for the character map library file (cmaplib.t3r) in the correct location; it looked in the directory containing the original interpreter executable rather than the "charmap" subdirectory of the interpreter directory; since the installer puts cmaplib.t3r in the subdirectory, the bundler failed to find the file and omitted it from the bundled executable. The program now looks in the "charmap" subdirectory.
  - A bug caused the compiler to crash on certain types of syntax errors. If a long string (around 1,000 bytes or longer) was misplaced in a few specific contexts, the error message generator overflowed an internal buffer trying to include the text of the string in the error message. This should no longer occur.
  - The compiler now flags an error if a grammar production defines more than 65,535 alternatives. This limit is imposed by the .t3 file format for grammar rules, but it's undesirable to get anywhere close to the limit because of performance cost. It's possible to exceed the limit with relatively concise grammar rule definitions, because the compiler expands the permutations of rules defined with '|' alternatives. Grammar rules that contain complex sets of permutations using '|' alternatives should generally be rewritten using sub-productions, which will allow equally complex rules without the overhead of expanding the permutations.
  - In reflect.t, reflectionServices.valToSymbol() can now correctly identify the reflectionServices object itself. (Due to a bug, this caused a run-time error in the past.)
  - In reflect.t, reflectionServices.valToSymbol(), looking up an unnamed object now returns a string giving the superclass list of the object, if the superclass names are available. The format of the return value is now '(obj:sc1,sc2)', where 'sc1' and 'sc2' are the names of the superclasses (naturally, more or fewer superclass names will appear according to the actual number of superclasses of the object). The string 'obj' is literally present. If none of the superclasses have names, then the traditional result, '(obj)', is returned. If some superclasses have names but others don't, then the full list will be returned, with '(anonymous)' used for any unnamed superclass.

  ### Changes for 3.0.6g (4/12/2003)

  - The new interpreter option -R lets you specify the root folder for individual resources. By default, the root resource folder is the folder that contains the image (.t3) file. If -R is specified, then the interpreter will look for resources in the given folder when they can't be found in the image file itself or in a resource bundle file. Note that this isn't a search list; only one -R option can be in effect.
  - Added a new method, isRoundTripMappable(), to the CharacterSet intrinsic class. This new method provides an easy way to determine if a set of characters has an exact, one-to-one mapping in a given local character set.
  - The compiler now warns when a grammar rule ends with an empty alternative, or is completely empty. Empty rules at the top level of a grammar rule are uncommon, and it's easy to accidentally leave a '|' at the end of a rule, especially while actively defining new rules. To eliminate this new warning, you can use an empty pair of parentheses, "()", to explicitly indicate an empty rule. This warning only applies to the outermost grouping level of a rule; empty rules within parenthesized portions of rules are not flagged.
  - Fixed a problem in the console formatter that caused command lines read from a command input file to be copied into a script output file twice.
  - Fixed a problem in the Dictionary class that caused dynamic vocabulary to be forgotten if you saved a game to a file, ended the interpreter session, started a new interpreter session, restored the file saved earlier, saved again to a second file, and then later restored the second file. (The problem was that the Dictionary object was not being marked as being in need of being saved again after it was restored in the new session, so the second save didn't include the dynamic vocabulary entries. The Dictionary object is now properly marked as being in need of saving after being restored.)
  - Fixed a problem that caused the Object.propDefined() method to yield incorrect results when called on an intrinsic class object to retrieve information on methods added to the intrinsic class with 'modify'. The information returned was inconsistent with that returned from getPropList(). This has been corrected; the returned information should now be fully consistent.
  - Fixed a problem that caused sporadic crashes in the Windows debugger when an expression including the '&' operator applied to an undefined symbol was evaluated interactively. This crashiness should no longer occur.
  - Fixed two problems in the text-only interpreters relating to "&" entities. First, a few valid entity names were not recognized at all, causing the interpreter to show the entity source text (i.e., the "&" code itself). Second, entities whose names weren't properly terminated (with a semicolon, ";") had the last letter of their name incorrectly added to the display after the entity itself. These problems have been corrected.
  - Fixed a couple of bugs that caused interpreter crashes when running with "unicodeb" or "unicodel" character set mappings.
  - The versions of the interpreters that run in a Windows command prompt window now correctly remove the console window's scrollbars in all cases on Windows NT, 2000, and XP. In the past, the interpreters usually did this, but in some cases missed the scrollbars and left them intact. (Console scrollbars appear when the console properties are set so that the console has a "screen buffer" larger than the actual console window. This feature isn't available on the Windows 9x platforms, only on the NT branch, which includes 2000 and XP.) Leaving the scrollbars active created the confusing situation that the area of the console containing the interpreter window could be scrolled off the screen. The scrollbars are now correctly removed under all conditions. This affects t3run.exe and tr32.exe.

  ### Changes for 3.0.6f (3/23/2003)

  - Fixed a problem in the regular expression parser that misinterpreted character class expressions involving single Unicode characters outside of the plain ASCII range (for example: '<\u2019|\u201D>'). The regular expression compiler treated such expressions as invalid; it now handles them correctly.
  - Added a couple of new compiler options to allow more control over special system paths:
    - `-FI path`: overrides the standard system include directory with the given path. The compiler normally uses a path that depends on the operating system and installation configuration. Note that this option doesn't set up a search list the way -I does; there's only a single system include directory in effect at any given time.
    - `-FL path`: overrides the standard system library source directory with the given path. The standard library path depends on the operating system and installation configuration. As with -FI, there's only a single system library directory in effect at one time.

  ### Changes for 3.0.6e (3/16/2003)

  - A new HTML tag is now recognized: <NOLOG>. This is a container tag (so each <NOLOG> must have a corresponding </NOLOG> tag); it delimits text that is to be displayed only on the interactive console, not in any log file (transcript) being made. The tag has no effect on the display.
  - The getPropList() method previously only returned static methods when called on intrinsic class objects (such as TadsObject or BigNumber). This has been changed so that the method now returns both static and non-static methods. This change clarifies the meaning of getPropList() when called on an intrinsic class object: the method returns the full set of properties that the class defines for instances of the intrinsic class, which may not necessarily be methods that are meaningful when called on the intrinsic class object itself. This change is necessary for consistency throughout the class hierarchy for the reflection mechanism, so that a program can traverse a class tree to create an exhaustive list of properties on a class, including those inherited from intrinsic superclasses.
  - In the output formatter, the effects of the "\^" and "\v" sequences are now limited to the plain text outside of HTML markups. In the past, if an HTML tag or entity appeared after a "\^" or "\v" sequence and before any alphabetic character, the case conversion effect was applied to the first character of the tag or entity name. Entity names are case-sensitive, so this had the potential to invalidate an entity name; in addition, whether a tag or entity name interceded, the case conversion effect was effectively lost, since it was misapplied to the HTML markup. Now, with this output formatter change, the case conversion effect of "\^" and "\v" sequences skips past any HTML markups, so the case conversion is applied to the next plain text.
  - Fixed a problem in the console output formatter that caused explicit blank line sequences to be ignored in some cases immediately after reading input.
  - Fixed a compiler problem that caused spurious syntax errors in any object definition that used a template in which a list element followed a single-quoted string element.
  - Fixed a compiler bug that caused spurious syntax error reports in certain cases involving multi-line strings as macro arguments. If code involving a macro spanned multiple lines, and the macro arguments included a string spanning multiple lines, and the string was part of a larger expression that started with a non-string token, the compiler sometimes misinterpreted the string as ending before its actual terminating quote. This resulted in spurious syntax errors, as the compiler thought some of the string's continuation lines were non-string tokens. This has been corrected.
  - Fixed a bug in the console output formatter that allowed too many lines to be displayed between "MORE" prompts in some cases, which caused text to scroll off the top of the screen before the player could read it. (The problem was introduced with the typographical spaces in 3.0.6b.)

  ### Changes for 3.0.6d (2/23/2003)

  - Fixed a problem that caused the debugger to crash when attempting to stop a running game when the game was suspended in the debugger at a run-time exception that was thrown from within a callback invoked from a system intrinsic method (for example, from a callback invoked by the List.forEach() method). This has been corrected.
  - The inputKey() intrinsic function didn't return the correct square-bracket code for special keys (arrow keys, function keys, and so on) due to a bug introduced in an earlier patch release (3.0.6a). This is now fixed.
  - Fixed a problem in several methods of the Dictionary intrinsic class (addWord, removeWord, forEachWord) that sometimes caused stack overflows when calling these methods. Fixed the same problem in some File methods (setCharacterSet, closeFile, setPos, setPosEnd).

  ### Changes for 3.0.6c (2/1/2003)

  - Defining a template for an object class no longer creates an external reference to the object, so it's now legal to define templates for objects that are never defined in any of the modules linked into a program. In the past, merely defining a template for an object created a reference to the object. This change makes it easier to create more modular subsystems whose components can be linked a la carte, since templates included in a header for the subsystem won't by themselves drag in the modules where the template objects are defined. An object mentioned in a template will now be required at link time only if the template is actually used to create instances of the mentioned object.
  - The 'modify grammar' statement now accepts an empty grammar rule list to indicate that the rules defined in the base grammar definition are to be retained. This change makes it possible to modify the properties and/or methods of a grammar rule in isolation, without changing the syntax for the rule. In the past, to modify only properties or methods of a grammar rule, it was necessary to repeat the entire rule list from the base grammar definition, since the rule list in the 'modify grammar' statement always superseded the base object's rule list.
  - The firstObj/nextObj object iteration functions now filter out "intrinsic class modifier" objects. These are purely internal implementation objects in the VM; they serve as the repositories of properties and methods attached via the "modify" keyword to intrinsic classes, and are for all intents and purposes parts of the intrinsic classes they modify. There is no benefit in enumerating them as separate objects, and doing so created some confusing special cases for code using the reflection mechanisms, so they've been eliminated from the firstObj/nextObj results.
  - The "intrinsic class" declaration syntax now allows the superclass of the intrinsic class to be specified. This information is largely for documentary purposes; intrinsic classes are built into the VM, so the "intrinsic class" syntax doesn't actually define intrinsic classes but merely tells the compiler about the interfaces of the intrinsic classes being used. The system header files have been changed to take advantage of this new feature to provide superclass information for the intrinsic classes they declare. The one immediate effect of this change is that the compiler is now able to enforce the rule against using "modify" with intrinsic methods of intrinsic classes, and can do so for the entire inheritance tree; in the past, the compiler was unable to enforce this rule for inherited intrinsic methods, since it didn't have information on the inheritance relationships among intrinsic classes.
  - Workbench for Windows had a problem that, under certain circumstances, caused the same directory to be added to the "include" path in the build settings every time a project was opened. This happened when a file in the "include files" section of the project had a parent-relative path (a path starting with ".."). This should no longer occur.
  - Workbench for Windows had a problem that failed to recognize the library-relative path of a header file associated with a nested library (that is, a library referenced from within another library; for example, en_us.tl is nested within adv3.tl in the standard library configuration). This sometimes caused such header files to be listed in the "include files" section of the project window with absolute or parent-relative paths, when they should have been listed without any path prefix, since Workbench automatically looks for header files in the directories associated with libraries included in the build. The unnecessary path prefixes caused other undesirable side effects, such as including superfluous include paths in the build settings. Workbench should now correctly identify headers associated with nested libraries.
  - Workbench for Windows did not properly initialize the "recent projects" menu when configured to load the most recent game at startup. On the initial load at startup, the list of recent projects was always shown with full, absolute directory paths, rather than with paths relative to the initially loaded project's directory. (This was purely cosmetic, but was inconsistent, since the recent projects were always shown with paths relative to the active project after opening another project subsequently.) This has been corrected.
  - A problem in the command-line option parser prevented some combined TADS 2/3 interpreters from accepting the "-cs" (character set) option for TADS 3 games. This is now fixed.

  ### Changes for 3.0.6b (12/15/2002)

  - This version substantially overhauls the output formatter's word-wrapping rules. The changes are designed to give the game much greater control over the way that text lines are wrapped to fit the available horizontal space. The changes should be relatively transparent to existing code, because the new features mostly add optional new controls, but use defaults that provide roughly the old TADS 2 behavior. The changes are implemented in both the text-only and HTML interpreters. The new text-wrapping rules are described in detail in the Formatting documentation, but here's a summary of the changes:
    - The game can switch at any between "word-wrap" and "character-wrap" modes. In word-wrap mode, text can be broken only at word boundaries; in character-wrap mode, text can be broken between almost any two characters. The modes are selected with the new tag <WRAP>: <WRAP WORD> sets word-wrap mode, and <WRAP CHAR> sets character-wrap mode.
    - The formatter recognizes the Unicode character \uFEFF (HTML entity "&zwnbsp;"), the zero-width non-breaking space. This character doesn't show up on the display, but it tells the formatter not to break the line between the two adjacent characters, even if the text-wrapping rules would otherwise permit it.
    - The formatter recognizes the Unicode character \u200B ("&zwsp;"), the zero-width space. This character doesn't show up on the display, but it tells the formatter that it can break the line between the two adjacent characters, even if the wrapping rules wouldn't ordinarily allow a line break there.
    - The formatter recognizes several of the Unicode special-width space characters (en space, em space, etc). All of these are treated as quoted space, in that they don't combine with adjacent runs of ordinary whitespace. These spaces allow finer control over visual spacing, which facilitates a more typographical appearance in the HTML interpreters.
    - The "soft hyphen" character, \u00AD (HTML "&shy;") is now accepted by the formatter. This is invisible in most cases, but it tells the formatter that it can break the line by hyphenating. If the formatter does break a line at a soft hyphen, it displays the soft hyphen as an ordinary visible hyphen.
  - Added the new "log file console." This is a special kind of console object that has no display, but simply captures all of its output to a log file. This can be used to capture game output to a file, using the standard output formatting (including HTML interpretation and word wrapping), without displaying anything to the player. Refer to the tads-io function set documentation for details.

  ### Changes for 3.0.6a (11/23/2002)

  - The new `#pragma newline_spacing(on|off)` directive lets the program control the treatment of newlines in strings. By default, newline spacing is set to "on": when a newline character is found within a string, the compiler converts the newline plus any whitespace that immediately follows to a single space character. When newline spacing is set to "off", the compiler instead simply strips out the newline and any immediately following whitespace. Setting newline spacing to "off" is desirable in some languages, such as Chinese, where whitespace is not conventionally used as a token separator in ordinary text; turning off newline spacing can make it easier to write code in these cases, because it allows strings to be split over several lines without introducing unwanted whitespace.
  - The compiler now allows macro substitutions in library (.tl) files. In a library file, the value of a preprocessor symbol defined with the -D option can be substituted into the text of the library file using the notation "$(VARNAME)": the variable name is enclosed in parentheses preceded by a dollar sign. The adv3 library (adv3.tl) uses this capability to parameterize the language-specific library and message file selection. See Compiling and Linking for more information.
  - The text-only interpreters now treat "&nbsp;" as a true non-breaking space. (In the past, "&nbsp;" was treated the same as "\ ", the quoted space: the formatter did not combine such a space with other adjacent whitespace, or remove it from the start of a line, but did allow a line break to occur at an "&nbsp;" character.)
  - On Workbench for Windows, the Build Settings dialog has a new page that lets you set the directory paths to use for object files and symbol files. This new page's tab is labeled "Temp Files," as the symbol and object files are intermediate files that the compiler produces and reads during compilation. (These settings correspond to the -Fy and -Fs compiler options.)
  - When Workbench for Windows creates a new project, it automatically creates a subfolder (of the folder containing the project file) to store the project's object and symbol files. The new subfolder is called "obj". Workbench initializes the new project's object file and source file path options to the new subfolder. The purpose of using the subfolder is to keep the compiler-generated intermediate files separate from the project's source files, to make it easier to manage the files associated with the project.
  - A portability bug that caused interpreter crashes on some platforms (notably Solaris) has been fixed. (This bug only occurred when the interpreter was compiled with certain C++ compilers, and prevented the interpreter from running any games.)
  - The 'inherited' operator did not work properly to inherit a modified intrinsic class method from the intrinsic base class of a modified intrinsic class. For example, if a method defined with "modify TadsObject" used 'inherited' to inherit, and a method of the same name was defined with "modify Object", the Object modifier method was not properly inherited. This has been corrected.
  - The new compiler option "-errnum" causes the compiler to display the numeric error code for each warning or error message. By default, the compiler does not display the numeric codes for errors, because the code is mostly for the compiler's own use; however, the new option allows the user to show these codes if desired, for purposes such as cross-referencing with documentation.
  - The new compiler option "-w-nnn" causes the compiler to suppress the warning message identified by nnn, which is the compiler's internal numeric code for the warning. When this option is used, the compiler will not display any warnings of the given type, and will not include any such warnings in its summary error count. This option can be repeated to suppress multiple types of warning messages. Only warnings (and pedantic warnings) can be disabled with this option; specifying codes for errors of severity greater than warnings will have no effect. The complementary option "-w+nnn" can be used to explicitly enable a warning; by default, all warnings are enabled, so the only reason this option would be needed is to enable a warning previously removed with "-w-nnn" on the same command line, which might sometimes be useful with shell aliases or command scripts. Note also that the "-w+nnn" option cannot be used to selectively enable certain pedantic warnings without enabling pedantic mode; pedantic warnings are an entirely separate class of messages from regular warning, and can only be enabled as a group using the "-w2" option. Once pedantic warnings are generally enabled, you can use "-w-nnn" to disable specific pedantic warnings you wish to suppress. +
  - When searching for an external resource file (.3r0, .3r1, etc.), the interpreter now looks for a file with both a lower-case and upper-case version of each suffix. This is intended to make the naming convention more flexible on case-sensitive file systems, such as Unix; on systems with case-insensitive file naming, such as Windows or Mac, this change has no effect.
  - Added support for mixed multi-byte character sets to the character mapper; this allows the compiler to read source files encoded in multi-byte character sets, and allows the interpreters to use local system character sets with multi-byte encodings, both for displaying text on the screen and reading text from the keyboard. A number of widely-used character sets for Asian languages use this type of character set (Windows systems localized for Chinese and Japanese use multi-byte character sets, for example). Such character sets have always been supported in the character map compiler (mkchrtab), but the character mapper used in the compiler and VM did not implement the mapping logic for these types of character sets. Double-byte character sets are now fully supported; the character mapper can now handle any character set that uses two-byte sequences for all of its characters (usually called double-byte character sets), or that uses a mixture of one-byte and two-byte sequences (usually known as multi-byte or mixed-multi-byte character sets).
  - In Workbench for Windows, the Debug Log window displayed its contents using the same color settings as in the main game window. The Debug Log window now uses the color settings from the Workbench "options" dialog, the same as source file windows.
  - In the Build Settings dialog in Workbench for Windows, on the Installer page, a new field allows overriding the default character mapping library (cmaplib.t3r) with a custom mapping library. This is especially useful for authors working in Asian languages; the default character map library includes mappings for the common character sets for most European languages, but does not include the Asian character sets because of the large size of these sets. Authors working in languages which require character sets not included in the default mapping library can create their own mapping file or files (see the character mapping documentation), then bundle the file(s) into a custom library (a .t3r file) using the `t3res` tool. Specify this .t3r file in the new Character Map Library field, and the installer will automatically bundle this file into your game's executable file when building the install set.
  - Fixed a problem in Workbench for Windows that caused Workbench to reload a library (.tl) file every time Workbench became the foreground application (i.e., its main window was activated after another application had been in the foreground), if the library was ever modified after being loaded in Workbench in that session.
  - Fixed a problem in the UTF-8 character mapper that could have caused problems in rare cases when reading from a text file encoded in UTF-8. The mapper did not correctly figure the byte length of the last character when reading a three-byte character at the end of the buffer and the first two of the three bytes was read into the buffer. (This problem was extremely unlikely to actually occur in practice, but in any case it's now fixed.)
  - Fixed a problem in the GrammarProd class that caused interpreter crashes under certain circumstances. In particular, if a grammar rule was matched with a '*' element in the rule, and the matched input string had exactly six tokens, an internal memory corruption led to an interpreter crash. This has been corrected.
  - Fixed the t3make error message "error creating image file" to properly show the image file name as part of the message. This message incorrectly showed the filename as "s", regardless of the actual name of the image.
  - Fixed a problem in the DOS character-mode interpreters (t3run and tr32) that caused start-up error messages (in particular, errors relating to loading the .t3 file, such as a "game file not found" error) to be cleared from the display before the user had a chance to see them.

  ### Changes for 3.0.5 (09/22/2002)

  - The <BANNER> tag is no longer allowed for T3 HTML programs. T3 games should use the banner API instead. (The <BANNER> tag has been removed entirely because it interacts poorly with the banner API. The adv3 library uses the banner API for the status line, so this essentially forces programs using the library to do likewise. To reduce the potential for any confusion that could result from games inadvertantly mixing banner API calls and banner tags, we simply disallow banner tags entirely, to ensure that all T3 programs use the banner API uniformly.) For the moment, <BANNER> tags are actually disallowed only when the banner API is supported by an HTML interpreter; for HTML interpreters that don't yet support the banner API, the tags are still allowed. This support will be withdrawn soon, though; we're just waiting until we're sure that banner API support is available on all HTML interpreters.
  - The compiler now assumes that each filename and folder name specified in a ".t3m" file (a compiler makefile) is given relative to the folder location of the .t3m file itself. This makes the compiler essentially independent of the working directory when using a .t3m file, because the location of the .t3m file effectively becomes the working directory for any file and folder paths specified within. This treatment naturally does not apply to any filename given in a .t3m file with an absolute path (for example, a Unix path that starts with "/", an MS-DOS path that starts with "\" or a drive letter, or a Macintosh path that starts with a volume name), since an absolute path is already independent of the working directory.
  - The compiler now keeps information on the compiler version that was used to compile a module. The compiler checks this information and automatically rebuilds a module that was built by an older version of the compiler. This ensures that all components of a program are rebuilt whenever a new version of the compiler is installed. (In the past, the compiler did not consider itself to be a dependency of the derived files, which occasionally led to confusing link-time errors caused by mismatched object file information.)

  ### Changes for 3.0.5h (09/14/2002)

  - Some slight additional performance optimizations in the VM should improve execution speed by another 10% or so (vs. release 3.0.5g).
  - Fixed a problem in the Dictionary class that caused spurious run-time error when restoring games (particularly when restoring after a RESTART operation had been previously performed).
  - Fixed a problem in the regular expression parser: the counted-repeat operator ({n,m}) did not nest properly with closures.
  - Fixed a debugger problem that caused the debugger to fail to take control (i.e., pause the game program and enter the debugger UI) when a run-time error occurred under certain conditions when using the "Step Out" or "Step Over" commands.
  - Fixed a problem in the console-based text-only interpreters that caused the [More] prompt to be displayed at the wrong place (at the end of a line of text, rather than at the beginning) under certain rare conditions.

  ### Changes for 3.0.5g (09/08/2002)

  - The Dictionary intrinsic class has been substantially altered. The central change is that the caller can now specify a "comparator" object that defines how strings in the dictionary are compared to input strings; this allows the game to customize the rules for looking up dictionary words. Related to this, all methods related to truncation length have been removed; instead, truncation, if desired, is now handled through the comparator. Finally, the methods that look up words in the dictionary (findWord and isWordDefined) have changed slightly to provide additional information from the comparator about how an input word matches a dictionary word.
  - Added the StringComparator intrinsic class. This class works with the Dictionary intrinsic class to specify customized rules for matching input words to dictionary words. StringComparator provides options that specify whether or not upper- and lower-case letters are distinguished; whether words can be truncated (abbreviated) on input, and to what minimum length; and a set of equivalence mappings that allow alternative spellings on input, such as using unaccented equivalents of accented characters.
  - The GrammarProd intrinsic class method parseTokens() now uses the supplied Dictionary to perform comparisons to literal tokens. Each input token is compared to literal tokens in the grammar rules using the Dictionary's current comparator. Literal tokens in grammar rules thus are matched using the same rules as dictionary words. The matchValues() results are stored in the match tree objects in the new property tokenMatchList: this property is set in each object in the match tree, and contains a list of the matchValues() results corresponding to the token list elements.

  ### Changes for 3.0.5f (09/02/2002)

  - Added the new method findReplace() to the String intrinsic class. This new method is similar to the rexReplace() function, but is slightly more efficient for situations where the text to be replaced is a simple constant string rather than a regular expression pattern. It's also slightly simpler to use, since it's not necessary to worry about any special regular expression interpretation of the search string.
  - Added the new intrinsic class RexPattern. This new class encapsulates a "compiled" regular expression pattern, which can be used in place of a pattern string in the regular expression functions. Compiling an expression converts it from a string into an internal representation. When a particular pattern is used repeatedly in many searches, it's much more efficient to use a RexPattern object to conduct searches with the pattern, because the regular expression functions have to compile their search patterns internally anyway; by using a RexPattern, you perform the compilation for a particular pattern only once, in advance, rather than each time you use the pattern. Compilation takes a non-trivial amount of time, so if a pattern is used frequently, pre-compiling it to a RexPattern can make a difference in execution performance.

  ### Changes for 3.0.5e (08/25/2002)

  - This release has a number of VM, compiler, and intrinsic class changes intended to make programs run faster. The compiler now generates more optimized code (especially when compiling with no debug information), and VM executes code faster. The changes should be entirely transparent in terms of functionality, although a few new VM instructions have been added, so code compiled with this new version of the compiler will not run with older VM versions.
  - Added two new LookupTable methods: keysToList(), which returns a list consisting of all of the keys in the table; and valsToList(), which returns a list consisting of all of the values in the table. In both cases, the lists are in arbitrary order.
  - The compiler left out a final newline after the error/warning count summary at the end of a compilation that generated error or warning messages. This is now fixed.
  - Fixed a couple of dialog messages in Workbench for Windows that referred to ".t3x" files (the old version of the ".t3" extension).
  - Fixed a problem in Workbench for Windows that caused an unparseable compiler command line to be generated if an option argument (such as an Include path) ended with a backslash. The problem had to do with DOS's odd command-line quoting rules; the trailing backslash was treated as "quoting" the quote mark at the end of the option argument. This has been corrected.
  - The compiler's command line error diagnostics are now somewhat improved, to help pinpoint the source of an error. In the past, the compiler always simply showed its usage message if the command line had a problem, which didn't help much in identifying which argument was causing the problem. The compiler now shows the usage message only when the command line is empty (or when the argument "-help" is given); in case of error, the compiler now shows a message explaining the specific problem, and shows the particular option causing the problem if appropriate.
  - In Workbench for Windows, the folder selector dialog was started with an empty current folder, which made the entire dialog appear empty, in some cases (such as when adding a directory to the "Include" list in the Build Settings dialog). The dialog should now always start with a valid initial directory.

  ### Changes for 3.0.5d (08/04/2002)

  - Workbench for Windows now has a primitive but usable "profiling" feature. Profiling is a technique in which the programmer collects data on where the running program is spending its time. The purpose is to identify any areas where the program spends a disproportionate amount of time; this sometimes reveals obvious bottlenecks where the code can be sped up with simple improvements, and in any case usually reveals the areas where optimization efforts will yield the greatest results. Workbench collects profiling data with function/method granularity: each time the program enters or exits a function or method, Workbench can track the time spent in that code. The user can turn profiling on and off using the new "Profiler" menu; when profiling is turned on, Workbench collects profiling data until the profiler is turned off, at which point the system asks for a file to which to write the collected data. Workbench writes the data as a tab-delimited text file: the first column is the name of the function or method; the second is the number of microseconds spent directly in that code; the third is the number of microseconds spent in functions or methods called by that code (which excludes the time spent directly in the code itself); and the fourth is the number of times the function or method was invoked. This format can be easily loaded into an external analysis tool (such as a spreadsheet application) for inspection. (The profiling facility is designed mostly for use by library authors, so we probably won't go to great lengths in the area of ease of use; and we don't expect to build any integrated analysis tools, as a spreadsheet is more than adequate to analyze the data.)
  - Fixed some problems in the DOS interpreter's display management (these are generic character-mode interpreter fixes that will also take care of the same problems on Unix and other character-mode systems). The problems affected resizing the terminal window, interaction with "More" prompts in some situations, and cursor placement under certain conditions. In addition, the "review mode" status bar is back (it was missing from the first versions with the banner API); note, though, that the mode bar is now displayed at the top of the main game window rather than taking over the status line, which is necessary because of the possibility the banner API creates of non-standard status line layouts.
  - Fixed a problem in the VM that could conceivably have caused crashes or other misbehavior under certain extremely improbable conditions involving stack overflows.

  ### Changes for 3.0.5c (07/28/2002)

  - The banner creation function bannerCreate() has a slightly modified interface. The new interface allows the initial size of the banner to be set in terms of the natural sizing units of the window; in addition, percentage-based sizing is still possible as well.
  - Percentage-based banner sizing now behaves slightly differently than it used to. In the past, the percentage size was based on the size of the complete application window. The percentage size is now based instead on the "remaining space" at the point at which a banner is laid out during the screen layout process.
  - The new banner function bannerSetSize() complements bannerSizeToContents() by adding the ability to set a banner's size in terms of the natural sizing units of the window or a new percentage-based size.

  ### Changes for 3.0.5b (07/20/2002)

  - Fixed a bug in the interpreter that caused sporadic crashes in situations involving adding lots of new properties to an object (of class TadsObject).

  ### Changes for 3.0.5a (07/14/2002)

  - A new set of functions, collectively called the banner API, provides more direct programmatic control over the appearance of the user interface than was available in past versions of TADS. The new API allows the program to divide the display into multiple "banners," which are non-overlapping windows, each with its own independent output stream. The banner API provides functionality based on the HTML TADS <BANNER> tag, but offers more power, and is also supported on many text-only interpreters.
  - Any time a nested object is defined, the compiler now automatically defines the property `lexicalParent` in the nested object, setting the property to a reference to the lexically enclosing object.
  - The main text window's output stream is now always in HTML mode. The "\{" and "\}" sequences have likewise been removed, since these are no longer useful now that HTML mode cannot be switched on and off.
  - The "\H+" and "\H-" output control sequences have been removed. These are no longer useful now that HTML mode switching has been removed.
  - The "\(" and "\)" output control sequences have been removed. The HTML markups <B> and </B> should be used instead. The "\(" and "\)" sequences are now redundant with the HTML <B> markup, since text output streams are now always in HTML mode.
  - A new system information code, SysInfoInterpClass, retrieves information on the broad "class" of the interpreter. This returns one of the following:
    - SysInfoIClassText: a text-only character-mode interpreter, such as MS-DOS TADS or Unix TADS. This type of interpreter uses a single fixed-pitch font to show all text, cannot show any graphics, and uses the text-only HTML subset.
    - SysInfoIClassTextGUI: a text-only interpreter running on a graphical platform, such as MacTADS or WinTADS. This type of interpreter might use proportionally-spaced fonts, and might use multiple fonts. These interpreters cannot show graphics using HTML, but they might use some graphics of their own for things like window borders. This type of interpreter recognizes the text-only HTML subset. Note that this code is not indicative of the type of OS, but rather of the type of interpreter: MS-DOS TADS always returns SysInfoIClassText, even when it's running in a DOS box under Windows, because it still acts like a character-mode interpreter even when running on a Windows machine.
    - SysInfoIClassHTML: a full HTML interpreter, such as HTML TADS on Windows, or HyperTADS on Macintosh.
  - The SysInfoHtml and SysInfoHtmlMode system information codes have been eliminated. The former is superseded by SysInfoInterpClass, and the latter has been rendered obsolete by the elimination of HTML mode switching.
  - The TADS 3 character-mode interpreters now support the <TAB> tag, if the underlying OS code allows. This tag is supported on all full HTML interpreters, plus most character-mode text-only platforms. The GUI text-only interpreters do not support this currently. The full complement of <TAB> features is supported; see the HTML TADS documentation (specifically, the TADS-specific markup extensions) for details.
  - The compiler and VM support "transient" objects, which are objects that do not participate in any of the VM's built-in persistence mechanisms (save, restore, undo, restart). A transient object is not saved to a saved state file, and is not affected by restore, undo, or restart operations. This is described more fully in the Object Definitions section of the documentation.
  - The saveGame function works differently than it used to. The function no longer saves the execution context, so it no longer has the "setjmp" behavior.
  - The restoreGame function works differently as well. Because saveGame no longer saves the execution context, restoreGame no longer restores it, so the function simply returns on successful completion - it doesn't have the "longjmp" behavior any more. This new design is much more flexible, because it allows arbitrary session information to be retained across the Restore operation, via local variables on the stack as well as with transient objects, and gives the program complete control over execution flow throughout the operation.
  - The restartGame function also has a new design. The function no longer requires a function to jump to, but simply resets object state and returns. As with the restoreGame changes, this allows the program complete control over execution flow and allows any amount of session information to be retained across the Restart operation.
  - All instances of the File intrinsic class are now transient. The static creation methods of the File class always return transient objects.
  - It is now possible to open "resources" as though they were files, and read their data using the File intrinsic class. Two new static construction methods make this possible: openTextResource() and openRawResource().
  - The option flags for the String.htmlify() method have been renamed, to make the names of the flags more descriptive of their functions. The flags formerly were of the form HtmlifyKeepXxx, but now use names of the form HtmlifyTranslateXxx. The change of terms to "translate" is a better match for what the flags actually mean, since the flags specify that certain characters are to be translated into HTML markup equivalents.
  - In Workbench for Windows, when the status line is displayed, the messages from the compiler showing the build progress are not displayed to the debug log window, but rather to the status line. This makes it much easier to read the results in the log window, and especially makes it easier to see the error messages, since the error messages aren't mixed in with lots of build progress messages. When the status line is hidden, build progress messages are still shown in the log window so that the compiler's progress can be seen.
  - The internal character encoding that the T3 software was using in past versions was not in conformance with the T3 specification, which calls for the standard UTF-8 encoding. The software was using an older encoding that had been obsoleted in the spec but was never changed in the software. This has been corrected; note that this change requires recompiling any existing games.
  - Due to a bug, Workbench for Windows did not properly store directory paths (such as for the Include path list) in the project file when the paths included a colon (":") character. This has been fixed.
  - A bug in Workbench for Windows caused the Window menu to display incorrect entries for Windows 95 and NT 4 (actually, this is more due to a bug in Windows 95 and NT 4, but Workbench didn't work around the bug, so in a sense it was a Workbench bug). This has been corrected.
  - A compiler bug caused the compiler to crash (with an access violation or equivalent) when given a source file whose very first object definition started with a template containing a double-quoted string with an embedded expression. This problem is now fixed.

  ### Changes for version 3.0.4 - 06/01/2002

  - Fixed a problem in the Vector intrinsic class that caused interpreter crashes under certain circumstances. (The exact conditions were not entirely predictable, because the problem had to do with an interaction between the Vector class, the garbage collector, and the undo mechanism, and only occurred when garbage collection was triggered after certain operations in the Vector class.)
  - Added a status line to Workbench for Windows. The status line is optional; it can be displayed or hidden, as desired, using the "View" menu. When displayed, the status line shows whether or not the program being debugged is running, and shows the line and column number of the current cursor position when a source file window is active.
  - Fixed a problem in Workbench that prevented parts of the window layout from being saved in the project configuration file when the main Workbench application window was closed while the program being debugged was still running.

  ### Changes for 05/19/2002

  - The DOS text-mode interpreter now supports setting text colors. Text colors can be set through HTML, as follows:
    - The <FONT COLOR=xxx BGCOLOR=yyy> tag can be used to set the and background colors of the text. The basic set of HTML colors is recognized, although the effective set of available colors is limited to the eight ANSI colors that DOS character mode can display: white, black, red, green, blue, yellow, cyan, and magenta. Hex RGB values (for example, <FONT COLOR='#C080E0'> are accepted, but these are simply mapped to the nearest available color from the ANSI set. Note that if a FONT tag specifies both COLOR and BGCOLOR, the text will be displayed exactly as specified; if the FONT tag specifies only COLOR, then the background color will be inherited from the enclosing text, and ultimately from the <BODY> color if no enclosing text has a specific background color.
    - The <BODY> tag can be used to set the foreground and background color of the window. The TEXT attribute sets the foreground text color, and the BGCOLOR attribute sets the background color of the window. The background color affects the entire window, just as in the HTML interpreters, so the entire window will be redisplayed in its new color whenever a <BODY BGCOLOR=xxx> tag is displayed.
    - The parameterized color names (TEXT, BGCOLOR, STATUSTEXT, STATUSBG) are accepted and map to the current settings of those colors, as set by the TRCOLOR program.
  - The new system information code SysInfoTextColors can be used to determine the level of color support available on the platform. The return value is a code indicating the level of support:
    - SysInfoTxcNone - no color support
    - SysInfoTxcParam - parameterized color names only
    - SysInfoTxcAnsiFg - The eight ANSI colors are available for text, but there is no capability to set the background color
    - SysInfoTxcAnsiFgBg - the ANSI colors are available for text and background colors (this is the code the DOS interpreter returns)
    - SysInfoTxcRGB - full RGB text color support is available (this is the code the Windows HTML interpreter returns)
  - The new system information code SysInfoTextHilite can be used to determine whether or not text highlighting is available. This returns true if a distinctive appearance for <B> text is available, nil if not. The HTML interpreters return true for this; the text-only interpreters generally return true, unless running in "plain" ASCII mode or with a terminal or display device that cannot render anything special for highlighted text.

  ### Changes for 05/05/2002

  - Fixed a problem in Workbench for Windows with libraries (.tl files) found via the library search path. In some cases, the files within a library could not be opened; in addition, the library itself was not always properly scanned on opening the project, so no files within the library were visible in the Project window. Libraries found via the search path should work properly now.
  - Workbench for Windows now uses small (8x8-pixel) icons in the left margin of debugger source windows when the selected source window font is smaller than the standard (16x16-pixel) icons. (These are the icons that show the location of the current line, breakpoints, and so on during a debugging session.) This allows more lines to be displayed vertically in a source window when a small font is selected.
  - When quitting out of Workbench, if a build is still running, the Workbench displays a dialog indicating that Workbench is waiting for the build to complete. In the past, there was no way to force Workbench to exit if the build process had become stuck. Now, the "waiting for build" dialog offers an "Abort" button; clicking this button will forcibly terminate the build, allowing Workbench to terminate immediately. This button is useful when the build process becomes stuck (which ideally should never happen, but has happened at times due to compiler bugs). The build process should not normally be aborted forcibly unless the build appears stuck, because forcibly terminating a process on Windows can occasionally cause Windows to become unstable.
  - Fixed a compiler bug that made it possible for the linking step to get stuck in an infinite loop if the data associated with a particular "grammar" production became too large. This should no longer occur.
  - Fixed a debugger bug that caused sporadic crashes when running games in Workbench.
  - Added new systemInfo() codes for MNG display:
    - SysInfoMng - can the system display MNG images?
    - SysInfoMngTrans - can the system display MNG's with transparency?
    - SysInfoMngAlpha - can the system display MNG's with alpha channels (i.e., partial transparency)?

  ### Changes for 04/28/2002

  - Renamed numerous macros in the system and adv3 header files to achieve more consistency in the naming scheme. Here's a table of the changes. (Sorry this isn't a Perl script or something.)

    Old Name | New Name
    --- | ---
    BIGNUM_SIGN | BignumSign
    BIGNUM_EXP | BignumExp
    BIGNUM_EXP_SIGN | BignumExpSign
    BIGNUM_LEADING_ZERO | BignumLeadingZero
    BIGNUM_POINT | BignumPoint
    BIGNUM_COMMAS | BignumCommas
    BIGNUM_POS_SPACE | BignumPosSpace
    BIGNUM_EUROSTYLE | BignumEuroStyle
    TYPE_NIL | TypeNil
    TYPE_TRUE | TypeTrue
    TYPE_OBJECT | TypeObject
    TYPE_PROP | TypeProp
    TYPE_INT | TypeInt
    TYPE_SSTRING | TypeSString
    TYPE_DSTRING | TypeDString
    TYPE_LIST | TypeList
    TYPE_CODE | TypeCode
    TYPE_FUNCPTR | TypeFuncPtr
    TYPE_NATIVE_CODE | TypeNativeCode
    TYPE_ENUM | TypeEnum
    PROPDEF_ANY | PropDefAny
    PROPDEF_DIRECTLY | PropDefDirectly
    PROPDEF_INHERITS | PropDefInherits
    PROPDEF_GET_CLASS | PropDefGetClass
    STR_HTML_KEEP_SPACES | HtmlifyKeepSpaces
    STR_HTML_KEEP_NEWLINES | HtmlifyKeepNewlines
    STR_HTML_KEEP_TABS | HtmlifyKeepTabs
    STR_HTML_KEEP_WHITESPACE | HtmlifyKeepWhitespace
    T3DBG_CHECK | T3DebugCheck
    T3DBG_BREAK | T3DebugBreak
    OBJ_INSTANCES | ObjInstances
    OBJ_CLASSES | ObjClasses
    OBJ_ALL | ObjAll
    REPLACE_ONCE | ReplaceOnce
    REPLACE_ALL | ReplaceAll
    GETTIME_DATE_AND_TIME | GetTimeDateAndTime
    GETTIME_TICKS | GetTimeTicks
    INEVT_KEY | InEvtKey
    INEVT_TIMEOUT | InEvtTimeout
    INEVT_HREF | InEvtHref
    INEVT_NOTIMEOUT | InEvtNotimeout
    INEVT_EOF | InEvtEof
    INEVT_LINE | InEvtLine
    INEVT_END_QUIET_SCRIPT | InEvtEndQuietScript
    INDLG_OK | InDlgOk
    INDLG_OKCANCEL | InDlgOkcancel
    INDLG_YESNO | InDlgYesNo
    INDLG_YESNOCANCEL | InDlgYesNoCancel
    INDLG_ICON_NONE | InDlgIconNone
    INDLG_ICON_WARNING | InDlgIconWarning
    INDLG_ICON_INFO | InDlgIconInfo
    INDLG_ICON_QUESTION | InDlgIconQuestion
    INDLG_ICON_ERROR | InDlgIconError
    INDLG_LBL_OK | InDlgLblOk
    INDLG_LBL_CANCEL | InDlgLblCancel
    INDLG_LBL_YES | InDlgLblYes
    INDLG_LBL_NO | InDlgLblNo
    INFILE_OPEN | InFileOpen
    INFILE_SAVE | InFileSave
    INFILE_SUCCESS | InFileSuccess
    INFILE_FAILURE | InFileFailure
    INFILE_CANCEL | InFileCancel
    FILETYPE_LOG | FileTypeLog
    FILETYPE_DATA | FileTypeData
    FILETYPE_CMD | FileTypeCmd
    FILETYPE_TEXT | FileTypeText
    FILETYPE_BIN | FileTypeBin
    FILETYPE_UNKNOWN | FileTypeUnknown
    FILETYPE_T3IMAGE | FileTypeT3Image
    FILETYPE_T3SAVE | FileTypeT3Save
    SYSINFO_VERSION | SysInfoVersion
    SYSINFO_OS_NAME | SysInfoOsName
    SYSINFO_HTML | SysInfoHtml
    SYSINFO_JPEG | SysInfoJpeg
    SYSINFO_PNG | SysInfoPng
    SYSINFO_WAV | SysInfoWav
    SYSINFO_MIDI | SysInfoMidi
    SYSINFO_WAV_MIDI_OVL | SysInfoWavMidiOvl
    SYSINFO_WAV_OVL | SysInfoWavOvl
    SYSINFO_PREF_IMAGES | SysInfoPrefImages
    SYSINFO_PREF_SOUNDS | SysInfoPrefSounds
    SYSINFO_PREF_MUSIC | SysInfoPrefMusic
    SYSINFO_PREF_LINKS | SysInfoPrefLinks
    SYSINFO_MPEG | SysInfoMpeg
    SYSINFO_MPEG1 | SysInfoMpeg1
    SYSINFO_MPEG2 | SysInfoMpeg2
    SYSINFO_MPEG3 | SysInfoMpeg3
    SYSINFO_HTML_MODE | SysInfoHtmlMode
    SYSINFO_LINKS_HTTP | SysInfoLinksHttp
    SYSINFO_LINKS_FTP | SysInfoLinksFtp
    SYSINFO_LINKS_NEWS | SysInfoLinksNews
    SYSINFO_LINKS_MAILTO | SysInfoLinksMailto
    SYSINFO_LINKS_TELNET | SysInfoLinksTelnet
    SYSINFO_PNG_TRANS | SysInfoPngTrans
    SYSINFO_PNG_ALPHA | SysInfoPngAlpha
    STATMODE_NORMAL | StatModeNormal
    STATMODE_STATUS | StatModeStatus
    SCRFILE_QUIET | ScriptFileQuiet
    SCRFILE_NONSTOP | ScriptFileNonstop
    CHARSET_DISPLAY | CharsetDisplay
    CHARSET_FILE | CharsetFile
    firstPerson | FirstPerson
    secondPerson | SecondPerson
    thirdPerson | ThirdPerson
    spellIntTeenHundreds | SpellIntTeenHundreds
    spellIntAndTens | SpellIntAndTens
    spellIntCommas | SpellIntCommas
    Logical | logical
    LogicalRank | logicalRank
    LogicalRankOrd | logicalRankOrd
    Dangerous | dangerous
    NonObvious | nonObvious
    IllogicalNow | illogicalNow
    Illogical | illogical
    Inaccessible | inaccessible
    DefaultReport | defaultReport
    MainReport | mainReport
    ReportBefore | reportBefore
    ReportAfter | reportAfter
    ReportFailure | reportFailure
    IsNonDefaultReport | gIsNonDefaultReport
    SingleDobj | singleDobj
    SingleIobj | singleIobj
    DobjList | dobjList
    IobjList | iobjList
    NumberPhrase | singleNumber
    TopicPhrase | singleTopic
    LiteralPhrase | singleLiteral
    DirPhrase | singleDir

  - Added Phil Lewis's new Adv3 Reference Help to Workbench for Windows. This new Windows Help file is a reference to the classes in the adv3 library; Phil created it for his own use but has graciously offered it for inclusion in the Author's Kit distribution. Phil says the reference isn't complete, but it has a wealth of information all the same. The Adv3 Help can be reached from the "TADS 3 Library" item on the Workbench "Help" menu.
  - The compiler can now search for source files using a user-specified list of directories. This allows makefiles (.t3m files) to specify source files using only relative filename paths, eliminating any dependency in a makefile on the local system's directory structure and thus allowing the project to be easily used on other systems. The compiler searches for its files by looking in the following locations, in order:
    - The current working directory (for Workbench users, this is the directory containing the .t3m file for the project).
    - The directories specified with "-Fs" compiler options, in the order of the options.
    - The directories specified with the new "user library" mechanism.
    - The "system library" directory. This is the special directory containing the compiler's own libraries. This directory varies by system, but it is normally set up automatically when TADS is installed and requires no user action to configure.
    The "user library" list is specified using a system-dependent mechanism:
    - For the DOS/Windows command-line compiler (i.e., run from a command prompt), set the environment variable TADSLIB to a list of directories, separated by semicolons (";").
    - For Workbench for Windows, enter the list of directories in the "Libraries" page of the Workbench preferences dialog, reachable from the "Options" item on the "View" menu.
    - The mechanisms for other systems are yet to be determined, but in all likelihood Unix will use the same TADSLIB environment variable as the DOS version.
  - Workbench for Windows has a new option to automatically load the most recent project when Workbench is started. To set the start-up mode, use the "Start-Up" page of the Workbench preferences dialog, reachable from the "Options" item on the "View" menu.
  - Added the new systemInfo() code SysInfoOgg, which senses whether or not the interpreter supports Ogg Vorbis audio playback.
  - Changed `inputEvent()` so that it accepts a nil timeout argument value, for consistency with `inputLine()`. A nil value for the timeout is equivalent to omitting the timeout argument entirely: it indicates that the input should be allowed to proceed indefinitely.
  - The compiler now stores preprocessor symbol (macro) definitions with the debugger records of the compiled program, when compiling for source-level debugging (i.e., using the "-d" compiler command-line option). The debugger uses the preprocessor symbols when parsing expressions during the debugging session, so it is now possible to interactively evaluate expressions involving macros. Note that the compiler keeps debugging records for a macro only if the macro (1) is never undefined (using #undef) or redefined with a different expansion within a given module, and (2) has the exact same expansion in every module in which it is defined; these restrictions mean that only macros with consistent "global" meanings across the entire program are visible in the debugger.
  - Fixed a problem in Workbench for Windows that caused an incorrect name to be stored for the game's initial source file when creating a new project.
  - Fixed a compiler problem that caused the compiler to crash when confronted with a constant index expression where the indexed value was not a list (e.g., `1[1]`).
  - Fixed a problem in the Windows HTML interpreter that prevented interrupted command lines from continuing correctly. When a command line input was interrupted by a timeout, the command line that was under construction when the timeout occurred was not properly restored for further editing. This has been corrected.
  - Fixed a problem in the VM that caused the VM to crash under rare circumstances. The problem was particularly likely to occur when stepping through large amounts of code with the debugger.
  - Fixed a problem in the character map compiler (mkchrtab) that generated corrupted character map files when the source file had duplicated display mapping entries.
  - The distributions (including the installer kits and the source code distribution) now include a full set of character mapping files that should cover most users on most platforms. For a listing of the included codings, see charmap/README.txt. (The full set adds only about 25k to the compressed distribution files, which seems a small cost for the simplicity of having an essentially universal set of mappings available with the default install.)
  - The Windows Author's Kit installer now associates .t3m files with Workbench, so that double-clicking on a .t3m file from Windows Explorer will open the file in Workbench. (The 4/7/2002 version still set the association for .t3c files instead, despite Workbench's switch to .t3c files for storing project configuration information.)
  - Fixed a problem that caused the compiler to display the incorrect text for invalid tokens in certain error messages related to 'grammar' statement syntax.

  ### Changes for 04/07/2002

  - Workbench for Windows now uses the compiler makefile (.t3m) file format to store its project information. This means that a Workbench project file can be used directly as a compiler makefile, using the compiler's "-f" option. For the moment, Workbench is still capable of loading
  - Workbench on Windows now monitors for Ctrl+Break, and breaks into the debugger when this key combination is detected. This allows easily breaking into the debugger if the .t3 program enters an infinite loop.
  - The 'replace' and 'modify' keywords can now be used to change 'grammar' definitions. Refer to the Grammar Rules documentation for details.
  - A grammar production object can now be declared without creating any rules associated with the production. The new syntax is simply "grammar production_name;" (that is, a "grammar" statement that simply ends after the name of the production). This can be useful for libraries that want to define rules that refer to productions for which the library itself provides no rules, so that games based on the library can fill in the grammar definitions for the productions. In the past, if a production was referenced as a subproduction from one or more rules but had no rules of its own defined, the linker generated an error, because it is likely in such cases that the rules referring to the undeclared production were misspelled and meant to refer to a declared production; this new syntax gives the author a way to tell the compiler explicitly that a production name was used intentionally, even if the production has no rules.
  - Added new syntax that allows multiple part-of-speech properties (such as "noun" or "adjective") to be used as a single token matcher in a grammar rule. The new syntax uses a list of properties in angle brackets: `<noun adjective plural>`. When this syntax is used, an input token matching any of the part-of-speech properties in the list matches the rule token position.
  - Moved the "build configuration" information that was formerly stored in object (.t3o) files into the symbol (.t3s) files instead. The compiler uses the build configuration data stored in these files to determine if recompilation of a given source file is necessitated by build configuration changes since the last time the file was compiled. In the past, when the information was stored in the object files, the compiler unnecessarily regenerated symbol files repeatedly when compilations failed due to syntax errors, because compilation didn't get far enough to store the build data. Moving the information to the symbol files allows the compiler to skip symbol table generation when a previous compilation generated a valid symbol file for a given module. This saves time in the build-edit-build cycle when a program is initially compiled and contains syntax errors.
  - Added two new pseudo-variable keywords: `targetobj` and `definingobj`. These pseudo-variables are similar to `self` and `targetobj`, in that they act like read-only variables (i.e., you cannot assign values to them), and they are automatically maintained by the interpreter to keep track of the current method context. `targetobj` returns the "original target object" of the current method; this is the object that was targeted by the method call that reached the current method. The target object is set each time a method is called normally or via `delegated`, and remains the same as methods are invoked via `inherited`. `definingobj` is the object that defines the currently executing method; this is normally simply the object where the method was actually defined in the program's source code.
  - Removed the `getMethodDefiner()` intrinsic function from the "tads-gen" function set. This function has been replaced by the new pseudo-variable `definingobj`.
  - Changed the interface of the Object.propInherited() intrinsic class method. The method now takes an additional argument (positionally the second argument in the new interface) giving the original target object of the call. In cases where the caller wishes to know if the currently active method can inherit a base class method, the value for the new argument should simply be `targetobj`.
  - Changed the way `inherited` behaves after `delegated` is used. In the past, the inheritance mechanism tried to find the defining object of the method with the `inherited` operator in the inheritance tree of "self". After `delegated`, the defining object is normally not related by inheritance to "self", so the old search pattern normally failed to find any inherited instance of the method. Now, the interpreter keeps track internally of the "original target" object in addition to the "self" object; the original target is always the target of the last explicit method call or the target of the most recent `delegated` operator. The `inherited` operator uses the original target object as the starting point of the inheritance tree search, rather than "self"; this allows `inherited` to find methods inherited from base classes of the delegatee when appropriate.
  - Fixed a compiler bug that caused incorrect code to be generated for statements like this: `if (constant_expr && non_constant_expr)` - that is, an "if" whose condition expression consists of a constant expression (i.e., an expression whose value can be determined at compile-time) and a non-constant expression joined by the "&&" operator. The code that the compiler generated caused unpredictable results at run-time, and was able to crash the interpreter in some cases. This has been corrected.
  - Increased the standard VM stack size to 4096 stack slots (from 1024).
  - Expanded the compiler's maximum symbol length to 80 characters, to accomodate the longer symbols generated by the new treatment of production match object tagged names as actual compiler symbols.
  - Fixed a problem that caused a sporadic interpreter crash when using restartGame(). This crash occurred only rarely, and was related to memory management during program re-initialization. This should no longer occur.
  - Fixed a problem with restoreGame() that caused modifications to intrinsic classes to be lost in some cases. This problem occurred rarely, and should no longer occur.
  - Changed the character mapping input file format slightly. The "unicode_to_local" keyword has been renamed to "display_mappings", and has a slightly different effect: in the "display_mappings" section, each character mapping gives the Unicode expansion of a Unicode code point; that is, each mapping specifies a set of Unicode characters to substitute for the Unicode character being mapped. The expansion is then further translated automatically by the character mapper to the local character set. Each expansion must map to characters defined in the one-to-one mapping section (i.e., the set of mappings before the "display_mappings" keyword). Note in particular that an expansion cannot map to characters that are themselves further expanded. The purpose of this change is to allow the interpreter to perform expansion mappings - that is, mappings that can translate one Unicode character to several display characters - while still in the Unicode domain, and hence to perform operations such as word-wrapping on the expansions. The console output formatter uses this to properly word-wrap lines with expanded display mappings.

  ### Changes for 03/16/2002

  - Fixed script-reading mode in the interpreter. Past versions did not correctly read input scripts (using the command-line interpreter's "-i" option, for example).
  - Added the new input event code INEVT_END_QUIET_SCRIPT, which is described in the documentation for the inputLineTimeout intrinsic function.
  - Added a couple of small usabilty enhancements to Workbench for Windows:
    - Pushing the Return/Enter key when keyboard focus is in the Project window opens the selected module in a source file window, if a module is selected. This allows easier keyboard navigation of the Project file list.
    - Double-clicking on a module in the Project window now moves keyboard focus to the newly-opened source file window. In the past, focus stayed on the Project window, so context-sensitive commands (such as "Find") did not apply to the newly-opened source window until manually clicking on the window to activate it.
  - Fixed a bug in `mkchrtab` (the character map compiler) that caused incorrect mappings in some compiled mapping files having display (from_unicode_to_local) mappings that expanded to more than one byte.
  - Fixed a problem in the Windows interpreter that made it incompatible with Windows 95. The interpreter should once again be compatible with Windows 95.

  ### Changes for 03/10/2002

  - Added the new method removeElement() to the Vector intrinsic class. This new method removes an element by value, modifying the vector in-place.
  - Added the new method forEachWord() to the Dictionary intrinsic class. This new method provides a way of enumerating all of the entries in a Dictionary object.
  - Added information to the LICENSE.TXT file making it clear that derived versions of the library are permitted with few restrictions.
  - The "!" operator can now take an object reference as its operand; when applied to a non-nil object reference, "!" yields nil. This means that constructs such as "if (!obj)" are now treated as equivalent to "if (obj == nil)"; such constructs formerly generated a run-time error. In addition, property ID's, single-quoted strings, lists, and function pointers can all be used as operands of "!", and "!" applied to any of these types yields nil.
  - Fixed a compiler bug that caused the compiler to crash in some cases when confronted with an empty pair of parentheses within a grammar rule, such as `grammar myProd: ('mytoken' ())`.
  - Fixed a compiler bug that caused the compiler to crash in some cases when given a method definition with no code body and the end of the object immediately following.
  - Fixed a compiler bug that caused incorrect code generation for an 'if' with a constant controlling expression that evaluated to true and no 'else' clause. In such cases, the true branch of the 'if' was not generated; this has been corrected.
  - The project file extension for Workbench for Windows is now ".t3c" (it was formerly ".tdc", the same as it was for the TADS 2 Workbench). The extension has been changed to allow the Windows desktop to launch the appropriate version of Workbench when the user double-clicks a project file from the desktop and both TADS 2 and ADS 3 Workbench versions are installed.
  - Fixed a problem in the VM that caused repeated "terminate game" dialogs to appear in Workbench for Windows when the user attempted to compile the game after the debugger intercepted a run-time error.
  - Fixed a problem in the character map compiler (mkchrtab) that caused invalid map files to be generated if the source file had more than one symmetric (bidirectional) mapping assigned to the same Unicode code point. The character map compiler now generates a warning when these collisions occur, and generates valid map files even when collisions are present by ignoring redundant mappings.

  ### Changes for 02/17/2002

  - The compiler now shows a summary count of warnings and errors at the end of the compiler console output when either count is non-zero, to make it more obvious that messages were generated during the compilation. If many modules are included in a compilation, the status messages that the compiler generates as it works through the module list can make it easy to miss an error or warning mixed in among all the status messages. The new summary at the end of the compilation should make it easier to notice when something requires attention. No summary counts are displayed when there are no warnings or errors; this is intended to make it even easier to notice when something is wrong, since authors will not be accustomed to seeing a summary count at all when everything is well.
  - The Iterator intrinsic class has the new methods getCurVal() and getCurKey(), which return the value and key of the current element of the iteration, respectively. For indexed collections, the "key" is the index of the current element.
  - LookupTable.forEach() no longer passes the key argument to the callback. If the key is desired, use the new method forEachAssoc() instead. This allows LookupTable to be used more interchangeably with other Collection subclasses, since its forEach() method has the same interface as the corresponding method of other Collection subclasses.
  - LookupTable, List, and Vector now have the additional method forEachAssoc(func), which calls func(key,val) for each element of the collection. For List and Vector, the "key" is the index of the element; for LookupTable, it is the key for the entry.
  - The Array intrinsic class has been deleted; Vector should be used instead. The Array class was too similar to the Vector class to justify its existence as a separate type, so the functionality of Array and Vector are now combined into the single Vector class.
  - When a Vector is used as the left-hand side of a '+' or '-' operation, in the past, the VM modified the left-hand side Vector object directly. This has been changed so that a new Vector is created, and the original left-hand Vector is left unchanged. The old behavior was confusing in that it gave the '+' and '-' operators side effects, which is inconsistent with the behavior of the operators in other situations.
  - A new Vector method, appendAll(), allows appending the individual elements of a List or Vector to another Vector in-place (i.e., without creating a new Vector object, as the '+' operator does).
  - The Vector methods getUnique() and subset() now return a new Vector to store the result of the operation. In the past, these methods modified the original Vector in place.
  - In the past, when a Vector was used as the right-hand side of a '+' operator whose left-hand side was a List or Vector, the List or Vector on the right was the single new element concatenated to the left-hand collection. This was inconsistent with the handling of List values; a List value concatenates its elements individually when used as the right-hand side of a '+' operator. For consistency, Vector now concatenates its elements individually when used on the right side of a '+' operator. Similarly, Vector values now subtract their elements from the left-hand side collection when used as the right-hand side of a '-' operator, also for consistency with the List type's behavior.
  - Fixed a problem in the VM that caused the VM to lose track of intrinsic class modifiers after a RESTORE operation. Intrinsic class modifiers will now properly survive RESTORE operations.

  ### Changes for 02/09/2002

  - Changed `inputLineTimeout` so that it accepts a nil timeout argument value. A nil value for the timeout is equivalent to omitting the timeout argument entirely: it indicates that the input should be allowed to proceed indefinitely.
  - Improved `inputLineTimeout`'s interaction with the OS layer so that the portable code can handle complete non-implementation of input-with-timeout by the OS layer.
  - Changed `getTime(GETTIME_TICKS)` so that the function always chooses the zero point of the system clock as the time of the first call to the function. This reduces the likelihood that a game will encounter a roll-over of the system clock, which could lead to confusion in interpreting time differences and the ordering of events.
  - Changed the names of two methods in the LookupTable intrinsic class. The method formerly called countBuckets() is now getBucketCount(), and the method formerly called countEntries() is now getEntryCount(). These names match the names as given in the documentation, but the header file (lookup.h) had the old names.
  - Added the compiler option "-clean", which causes the compiler to skip ordinary compilation and instead simply remove all derived files that the compilation would have produced; in particular, this removes the symbol (.t3s), object (.t3o), and image (.t3) files that the compilation would have produced.
  - Added the compiler option "-Pi", which causes the compiler to skip ordinary compilation and instead write to the standard output a list of files included with `#include` directives throughout the program. The compiler runs the normal preprocessing, and shows only files included in conditional compilation sections that are selected in the compilation (in other words, the list does not include any files included from within the false branches of `#if` or other conditional compilation directives). In the generated list, the files are listed one file per line, and each line specifying a file consists of the characters "`#include`", followed by a single space, followed by the name of the included file, followed by a newline sequence. The name of the included file is not enclosed in any quote marks or other delimiters. This format is intended to simplify automatic processing of the list by clearly marking each line in the output that names an included file. Note that the list of included files might include a given file more than once, because each file is listed as it's included, and it is possible to include a given file more than once.
  - When the compiler is run with the "-P" option (which writes the preprocessed version of the source to standard output), the compiler now prefixes the generated source with the directive `#charset "utf8"` to indicate the character set of the preprocessed source.
  - Added a compiler warning message when the preprocessor finds a line that ends with a backslash followed by whitespace. While this format is legal (because it could be useful in defining a macro that is later "stringized"), it is highly unusual. Since trailing spaces are not usually visible in a text editor, the programmer might not be aware of their presence; and since the presence of the trailing spaces materially changes the meaning of the program, the compiler warns about them. Note that the warning can be suppressed by adding a comment at the end of the line; this doesn't change the meaning of the program but does make the spaces visually evident in a text editor, so the compiler recognizes that the warning is not necessary in this case.
  - Fixed a VM problem that caused the garbage collector to incorrectly delete intrinsic class objects under certain unusual circumstances. When an intrinsic class is used implicitly but never specifically declared in the compiled program, the VM creates an object to represent the intrinsic class during the initial program load. In the past, it was possible for the garbage collector to regard such an object as unreachable even though it is always reachable via the native code implementing its corresponding intrinsic class. This problem sometimes led to VM crashes. The problem should no longer occur.
  - Fixed a compiler problem that caused incorrect compilation for a grammar rule specified with an alternation (two or more sub-rules, each separated by an "|" symbol) and an empty final sub-rule. In such cases, the compiler incorrectly generated two copies of the empty sub-rule, leading to two match objects being created at run-time each time the empty sub-rule was matched. This has been corrected.
  - Changed `inherited` so that it searches for the next inherited definition of the property as though the currently active method (and any overriding definitions) had simply never been defined. This makes `inherited` work roughly the same way as the `inheritNext` method that was formerly defined in the `MixIn` class in the adventure game library (adv3).
  - Added a new `Object` method, `propInherited`, which determines if a method is inherited, using the new rules of the `inherited` operator. This provides functionality equivalent to the `canInheritNext` method formerly defined in the `MixIn` class in the adventure game library.

  ### Changes for 01/13/2002

  - The compiler can now read "library" files, which are lists of source files to be included in the compilation. Library files can be used to simplify compiler command lines and makefiles when including sets of source files that usually act as a group, such as the standard adventure library sources.
  - Workbench can now show library files in the project window. You can add a library file to the project window's source file list in the same way as you can add a source file; the library shows its contained source files as a subtree. Each source file within a library is shown with a checkbox, indicating whether or not the file is included in compilations; if you want to exclude a file within a library from compilation, click on the checkbox to remove the checkmark. The checkbox settings are stored with the project and don't affect the library itself, so you can use the same library in a different project, and include and exclude different sets of files.
  - The debugger no longer uses a RuntimeError exception to terminate the program being debugged. In the past, when the user terminated the running program using the debugger "Stop" button, or by starting a new compilation of the program while the program was still running, the debugger attempted to terminate the program by throwing a RuntimeError with system error code 2390. This approach wasn't completely reliable, because it allowed the running program to catch the exception and keep running; programs sometimes inadvertantly caught the error as part of an inclusive "catch" handler, causing strange interactions with the debugger user interface. The debugger now halts the program by telling the VM not to execute any more program instructions, which guarantees that the program stops immediately. This new approach should be much more robust and should avoid the strange effects that sometimes occurred with the old mechanism.
  - Fixed a problem in the compiler that caused the compiler to hang when given a makefile (a .t3m file) that didn't end with a newline character.
  - Fixed a compiler problem that generated an incorrect set of grammar rule patterns for grammars involving nested alternatives (i.e., parenthesized "|" expressions). In the past, the compiler incorrectly generated multiple copies of the top-level expressions in such rules, leading to run-time generation of multiple redundant matches for these expressions. This has been corrected; the compiler now generates only one copy of each top-level rule in an alternation.
  - Fixed an interpreter problem that caused the interpreter to crash when an HTML <TITLE> tag was displayed.
  - Fixed a problem in the debugger that caused memory leaks and other incorrect behavior when the user attempted to run the program, but the program had not been compiled (or had not been compiled with debugging information).
  - When Workbench needs to find a source file during program tracing in the debugger, it now scans the project list to find the file. In the past, the debugger used only the source path to find files, leading to annoying interactive requests to locate files that were in plain view in the project window.

  ### Changes for 01/05/2002

  - Added the new intrinsic functions `inputLineTimeout()`, which allows reading a line of text with an optional timeout. This function can be used to combine command-line input with real-time effects, because it allows a command line to be interrupted if the command is not completed before a real-time interval elapses.
  - Fixed a problem in the Dictionary class: the `isWordDefinedTrunc()` method used the wrong truncation length in its comparison - it required the string to be matched to be at least one character longer than the dictionary's truncation length. It now uses the correct truncation length.

  ### Changes for 12/30/2001

  - The compiler now parses a `delegated` expression so that the object expression is taken to exclude function or method calls. That is, if parentheses follow the expression giving the target object of the delegation, these are taken to give the argument list of the delegation call itself, rather than of the expression giving the target object value. This change makes `delegated` syntactically parallel to `inherited` in that the target property can be omitted from the expression, in which case the delegation target property is the same as the property being evaluated in the caller. (If a function or method call is desired in the object expression itself, this can be easily accomplished by enclosing the entire object expression in parentheses.)
  - Workbench now stores its project configuration files so that the absolute file system path to "system" files is not stored; instead, system files are flagged as system files, and their locations are stored relative to the system directory. A "system" file is simply a file that is stored in the Workbench install directory or any of its subdirectories; the system directory is the directory containing the Workbench program executable. This change makes project configurations more readily moveable from one system to another, because it eliminates any dependency in the project configuration on the particular directory in which Workbench is installed.
  - The compiler now treats the symbol and object path options as overriding all module source paths, even when the filenames are given with "absolute" (as opposed to relative) path names.

  ### Changes for 12/23/2001

  - Added a checksum to the saved game format. This allows the interpreter to validate a saved state file, to ensure the file wasn't corrupted (such as by a text-mode ftp transfer), before attempting to load the file.
  - Fixed a problem in the Vector intrinsic class that prevented two equivalent vectors from comparing equal.
  - Fixed a compiler problem that caused the compiler to crash in some cases when a symbol was redefined from function to another type.
  - Fixed a compiler problem that caused incorrect initialization of Dictionary objects in the image file in certain cases when preinitialization ran (i.e., when compiling with the -d option).

  ### Changes for 12/09/2001

  - The compiler now accepts URL-style portable path names in #include directives, and in fact prefers them. Refer to the preprocessor chapter for details.
  - Added a new method, createClone, to the TadsObject intrinsic class. This method returns a newly-created object that is an identical copy of the original object.

  ### Changes for 12/02/2001

  - Changed the tokenizer interface (in tok.t) to return a list of token elements, rather than parallel value/type lists. Each token element in the token list is a sublist, consisting of the following values:
    - [1] = token value, as set by the matched rule
    - [2] = token type enum, as set by the matched rule
    - [3] = original source text matched by the rule that matched the token
    The tok.h header defines macros that extract these elements of a token; these should be used rather than direct list elements to make your code more readable. The macros are getTokVal(tok), getTokType(tok), and getTokOrig(tok). So, if `lst` is a variable containing the result of calling Tokenizer.tokenize(), and you want to retrieve the type enum for the third token, you'd write `getTokType(lst[3])`.
  - Changed the tokenizer's rule specifications for greater power and symmetry in creating rules:
    - The "flags" entry has been eliminated. The functionality of the only flag that was defined, TOKFLAG_SKIP, has been replaced with the improved behavior of the rule processor. Since the processor method's interface is now powerful enough to subsume the functionality of the "skip" flag, the special case embodied in the flag is no longer needed.
    - The processor method (element [3] in the sublist defining a rule) has a new interface. In the past, this method took a text match and returned a token value. This interface meant that a given rule was limited to generating exactly one token. The new interface takes three arguments, and returns no value:

              self.(processorProp)(txt, typ, toks)

      txt is the text that matched the rule (this is the same as the lone argument to the old interface). typ is the token type from the rule (i.e., element [2] of the sublist defining the rule). toks is a Vector containing the token list under construction. The method must append the appropriate set of tokens to the Vector in toks. The method is not required to append any tokens; the rule in the default tokenizer rule set that matches whitespace, for example, doesn't generate any tokens, since whitespace characters have no significance other than separating tokens in the default rule set. The rule is also allowed to generate more than one token; this is useful for rules that generate certain tokens types only if they immediately follow particular text patterns. Note that the processor method is not required to use the typ value given, since each new token the method adds to the result Vector can be of whatever type is appropriate; the type information is included so that a single processor method can be re-used for similar types of processing that produce different token types.

  - Changed the intrinsic GrammarProd.parseTokens() method to accept tokens in the new format returned by the tokenizer. The method now takes only two arguments, not three: the second argument that formerly gave the token type list has been eliminated, since each element of the token list now includes the type information along with the token value information.
  - Changed the Dictionary and GrammarProd intrinsic classes to use case-sensitive matching exclusively. Case sensitivity in the past was inconsistent; all functions are now case-sensitive for consistency.
  - The template inheritance mechanism is somewhat altered from its first implementation. The 'inherited' keyword can now go anywhere a template; the inherited token lists are treated as substitutions for 'inherited' at the point at which it appears in the list. Furthermore, the compiler now treats each template involving inheritance as a macro defining all possible inherited templates; when a template is used, it is matched based on the entire expansion of the template, not on the partial superclass template. The net effect is that a template definition involving an 'inherited' token is identical to the implied set of fully expanded template definitions.
  - The -Fs option can now be used to specify a search path for source files, rather than a single path for all sources as it did in the past. Multiple -Fs options can be specified; each one adds one directory to the source search path. When a source file name is specified in "relative" form (as defined by local filename conventions), the compiler first looks for the file in the working directory, then searches the directories specified with -Fs options, in the order in which the options were specified. The compiler uses the first instance of the file it finds.
  - The compiler automatically adds the system-dependent default system library directory to the source search path. This directory is always searched after all directories specified by the user with -Fs options. In effect, the compiler adds an extra -Fs option for the default system library directory after all user-specified -Fs options. This allows library sources (such as reflect.t or gameinfo.t) to be included in a build configuration (in a .t3m file, for example) without any path information; the compiler will automatically find these system files using the implied -Fs setting.
  - The compiler's default system library and include directories are now system-dependent. On DOS and Windows systems, the default system header and library directories are the same as the compiler executable's directory (this is the main directory where the TADS 3 tools are installed). Check your platform-specific release notes for details on the locations of these directories on other platforms.
  - Fixed a problem that allowed objects to be deleted by the garbage collector when they were referenced as superclasses of other objects. This caused unpredictable behavior, including interpreter crashes.
  - Fixed a problem that affected the results of t3GetStackTrace() in the non-debug interpreter when a run-time error occurred. In such cases, the stack trace incorrectly omitted the innermost level, where the error actually occurred. This has been corrected.
  - Fixed a compiler problem that sometimes caused the compiler to crash after attempting a link that involved unresolved external symbol references.
  - Fixed a GrammarProd parsing problem that caused incorrect token index information to be returned in certain cases involving productions with no tokens.

  ### Changes for 11/17/2001

  - Extended the object template syntax to allow template inheritance. A template definition can now include the keyword "`inherited`" as its final token; this indicates that the template "inherits" the templates of its class's superclasses.
  - The compiler now detects and reports circular class definitions (that is, class definitions where the class being defined is a subclass of one or more its purported superclasses). In the past, the compiler did not detect such definitions and could get stuck in infinite loops or unbounded recursion when they were made.
  - Fixed a compiler problem that sometimes caused crashes when an actual parameter list in a macro expansion was not properly terminated (with a closing parenthesis) in the source file.
  - Fixed a problem that affected a few Vector methods by incorrectly returning an empty vector. This affected the appendUnique, getUnique, and mapAll methods.
  - Fixed a compiler problem that caused a modified intrinsic class to show a spurious extra property in its getPropList() result list. This property had an undefined type (type code 16).
  - Fixed a problem in the Vector class that caused unpredictable results, including crashes, when adding a large list to a vector.
  - Fixed a problem in the debugger that caused unpredictable results, including crashes, when interrupting the program in mid-statement in certain circumstances. The problem occurred sporadically in such cases when the garbage collector happened to run while the debugger had control, but didn't appear until after returning control to the program. This problem only manifested itself rarely, but could cause crashes when it did appear.
  - Fixed a compiler problem that caused incorrect code to be generated for calls to operator `new` where the actual parameters included one or more "..." expressions (i.e., expanded variable argument lists). This affected the calling end, not the receiving end. The problem caused the caller to send one fewer argument than it should have.
  - Fixed a problem in the output formatter that caused log files to be generated without proper line wrapping in the HTML version of the interpreter.
  - Changed the output formatter so that <BANNER> contents (everything from a <BANNER> tag to the corresponding </BANNER> close tag) are not included in the output log. The contents of a banner are not logically part of the main text stream so are not appropriate for inclusion in a log file. This ensures that HTML-based status lines and other special display effects do not interfere with the log file contents.

  ### Changes for 10/21/2001

  - Fixed a problem that made it impossible to use anonymous functions that referenced "self" or properties of "self" within property values defined as simple value expressions (as opposed to methods).
  - Changed the compiler to allow using short-form anonymous functions (i.e., using the "`{args: }`" notation, rather than the "`new function`" notation) as list elements without enclosing the functions in parentheses. In the past, the compiler considered an open brace at the start of a list element expression as an error; this was an heuristic intended to catch unterminated list expressions, but its utility as a diagnostic tool was not sufficient to justify the superfluous syntax requirement it imposed for this case.

  ### Changes for 10/07/2001

  - Added special character sequences '\{' and '\}'. These are used to group a set of output formatter setting changes: any changes to the formatter settings made after a '\{' sequence are undone at the corresponding '\}' sequence. In particular, the following state changes are affected:
    - \H+
    - \H-
    - \H
    These new sequences can be used to isolate a run of text from the enclosing text's formatter settings, so that the text within the '\{ \}' pair doesn't have to worry about the enclosing settings and has no effect on the enclosing settings. This can be useful, for example, if a run of text wants to output an HTML-significant character, but doesn't know if it will be called with HTML interpretation turned on or off. In such cases, the text can turn HTML interpretation off within the brackets without affecting its caller: "\{\H-&\}" would display an ampersand, regardless of whether HTML mode was in effect before the text was displayed, but will have no effect on subsequent text's HTML mode.
  - Fixed problems in several intrinsic classes related to saving and restoring. These bugs caused crashes in some cases when restoring saved positions.
  - Changes the restartGame() behavior slightly. The function invoked after the restart is now passed the original command line arguments to the program; the arguments are passed as a list in the second parameter to the function. This allows the function to invoke the normal main program entrypoint as though the program were being started normally.
  - If a saved position file is found to be corrupted in the course of being restored, the interpreter will now force an exit. There is no way for the program to retain control in such cases. If a saved position file is corrupted, the partially restored machine state at the point at which the corruption is detected must be considered invalid, so the VM cannot safely pass control back to the program. In such cases, the VM terminates the program to avoid the high likelihood that the program would crash the VM due to the program's partially corrupted internal state.
  - Fixed some problems in the "undo" mechanism that caused unpredictable behavior (including VM crashes) under some circumstances.
  - Fixed a problem in the debugger that caused, in some cases, the incorrect error code to be reported in the RuntimeError object representing a VM exception. This only occurred when the program was being run in the debugger, and only then when certain types of expressions were evaluated. This has been corrected.

  ### Changes for 09/30/2001

  - Changed the symbol file format to allow inclusion of intrinsic function and intrinsic class registration lists. This is an internal change only; its purpose is to make the compiler more flexible in correlating the internal linkage identifiers of intrinsics across object modules to eliminate the possibility of certain confusing linking errors. In the past, it was necessary to keep intrinsic definitions in a consistent order across separately compiled modules, which was problematic for library developers and especially for library extension developers. Adding the information to the symbol files allows the compiler to build an intrinsic identifier list globally across modules to ensure a consistent ordering, even when the individual modules have conflicting orderings. This change should not be visible to users except to the extent that it eliminates certain errors relating to intrinsic class and intrinsic function inclusion order.

  ### Changes for 09/09/2001

  - Added a new function to the "tads-io" function set: `flushOutput()`, which immediately flushes text output to the display and updates the window, if possible.
  - Fixed a compiler bug that caused incorrect code to be generated for implicit constructors for classes with multiple superclasses. This code generation error did not manifest itself frequently, but when it did show up caused problems ranging from data value corruption to interpreter crashes.
  - The debugger now includes an ampersand prefix when displaying property pointer values.

  ### Changes for 08/26/2001

  - Added new syntax that provides a short-hand notation for defining a group of properties with similar names and parameters: the new "propertyset" syntax.
  - Added a new keyword, "targetprop", a pseudo-variable that evaluates to the current target property pointer. The target property is the property that was invoked to reach the current method; this new pseudo-variable complements "self" with information on the property being evaluated in the current "self" object. The "targetprop" keyword can only be used in contexts where "self" is valid.
  - The "inherited" and "delegated" keywords can be used with new syntax that omits the target property. If the target property is omitted, then the current target property is implied. The target property can be omitted from any of the previously-allowed forms of the "inherited" and "delegated" expressions, as shown here ("delegated" syntax is parallel to "inherited", so only "inherited" is shown):
    - `inherited` is equivalent to `inherited.targetprop`
    - `inherited(arguments)` is equivalent to `inherited.targetprop(arguments)`
    - `inherited superclass_name` is equivalent to `inherited superclass_name.targetprop`
    - `inherited superclass_name(arguments)` is equivalent to `inherited superclass_name.targetprop(arguments)`
  - Added a new library module, reflect.t, that provides higher-level reflection services. This module is optional, but if it is included, the _main.t module uses reflection to show stack trace listings for unhandled runtime exceptions.
  - Added t3GetStackTrace() to the 't3vm' intrinsic function set. This function returns information on the call stack.
  - The RuntimeException object defined in _main.t now stores a stack trace (in the form returned by t3GetStackTrace()) in its stack_ property. The VM no longer stores an explicit stringized form of the stack trace when setting the exception message, since the new stack trace format is more powerful.
  - Fixed a bug in the TadsObject intrinsic class that sometimes caused a given property to appear more than once in the getPropList() method's returned list. Any given property now appears at most once in the result list.
  - The TadsObject intrinsic class now supports createInstance() as a static method on the intrinsic class. The expression TadsObject.createInstance() returns a new instance of TadsObject, which is the same as defining an object statically like so: "myobj: object;" - that is, using the "object" keyword rather than a superclass list.
  - Fixed a bug in the getPropList() method when called on any intrinsic class object (e.g., Object, TadsObject, BigNumber). In the past, this method returned a list of all of the methods that were valid on instances of the intrinsic class, not the methods that were necessarily valid on the intrinsic class object itself. This method now returns a list consisting only of the "static" methods of the intrinsic class, which is to say the methods that can be called directly on the intrinsic class object itself.
  - Fixed a bug in the Object intrinsic class's propType() method. When the property in question was undefined, the method returned TYPE_NIL, whereas it should have returned nil. The method now returns nil for these cases, as documented.
  - Fixed a bug in the compiler that caused incorrect code generation when a variable argument list parameter variable was referenced from within an anonymous function within the function or method with the variable argumetn list parameter.
  - The compiler now specifially flags code using '=' to define a method. Since this was valid TADS 2 syntax, and has been gratuitously changed in TADS 3, users are likely to use the old syntax accidentally, especially while transitioning to the new language. The compiler catches these cases so that it can generate specific and clear error messages; this should help ease the transition to the new syntax by spelling out plainly the new syntax requirement.

  ### Changes for 08/12/2001

  - Fixed a compiler problem that caused incorrect code to be generated for expressions of the form `obj.(prop)(args)`, where `prop` is a property of `self` whose value is a property pointer. An expressions of this form is equivalent to the form `obj.(self.prop)(args)`, but the compiler in the past incorrectly interpreted this as equivalent to `obj.prop(args)` - that is, rather than evaluating `(self.prop)` and then calling the property of `obj` given by the resulting property pointer value with the given argument list `args`, the compiler generated code that called the property `prop` of `obj` with arguments `args`. This has been corrected - the compiler now correctly interprets `obj.(prop)(args)` as equivalent to `obj.(self.prop)(args)`.
  - Fixed a compiler problem that caused incorrect code to be generated for `delegated` expressions involving variable argument lists.
  - Fixed a compiler problem that caused a spurious warning under certain circumstances. If a property was used only in an address expression ("&prop") in a module, and no object ever defined a value for the property, a call to the property in a separate module incorrectly generated a warning indicating a call to a possibly undefined property name. This warning was spurious because the use of the property name in an address expression is enough to definitively establish the symbol as a property.
  - Fixed an output formatter problem that caused the text-mode interpreter to hang (in an infinite loop internally) in response to certain "&" entities in HTML mode.
  - Fixed a problem in the GrammarProd intrinsic class that caused productions that matched zero tokens to indicate invalid token index values for firstTokenIndex and lastTokenIndex. These now always indicate zero in such case, to indicate that the production is associated with no tokens.

  ### Changes for 08/05/2001

  - Added file safety level checking to the File intrinsic class. The initial implementation of File did not check the safety level set in the user preferences; the File class now correctly checks to ensure each open-file operation is allowed by the user's safety level settings. On a safety level violation, the "open" functions throw the new exception FileSafetyException.
  - Text files can now be opened in FileAccessReadWriteKeep and FileAccessReadWriteTrunc modes. In the past, only "data" and "raw" files could be opened in read/write modes, which made it impossible to append to an existing text file.

  ### Changes for 07/22/2001

  - Fixed a problem with using 'modify' with intrinsic classes. In the past, if more than one 'modify' statement was applied to an intrinsic class, only the last of the 'modify' statements was actually taken into account at run-time. This has been corrected.
  - Fixed a compiler bug: the compiler did not report an error if a 'replace' statement replaced an object but did not specify a superclass list for the new object. The compiler misinterpreted such a statement as a new anonymous object definition. This has been corrected; the compiler now flags the missing superclass list as an error.

  ### Changes for 07/16/2001

  - Fixed a problem in the List class that could cause an object to be improperly deleted by the garbage collector under certain obscure circumstances. (In particular, if an object was being assigned to a list element, and the garbage collector ran in the course of the creation of the new list for the result of the assignment, the object on the right-hand side of the assignment was lost if not otherwise referenced.)
  - Fixed a problem that occurred with `propDefined(prop, PROPDEF_GET_CLASS)` when the property of interest was an intrinsic method (i.e., a TYPE_NATIVE_CODE value). In these cases, the return value of the method was an invalid value, which caused problems if used, including interpreter crashes. In such cases, `propDefined()` now properly returns the intrinsic class object where the intrinsic method is defined.
  - Extended the object template mechanism to allow class-specific templates to be defined.
  - Extended the firstObj() and nextObj() intrinsic functions to take a new flags argument, which allows the caller to specify whether to enumerate instances only, classes only, or both.
  - Changed the TadsObject class to allow use of the `new` operator with no arguments. In the past, at least one argument (giving the immediate superclass of the new object) was required; now a `new TadsObject` with no arguments is understood to create a base TadsObject.
  - Added the File intrinsic class, which provides a new interface to external file input/output. This replaces the file-related functions in the "tads-io" intrinsic function set, which have been removed. Specifically, the following functions have been removed:
    - `fileClose`
    - `fileGetPos`
    - `fileOpen`
    - `fileRead`
    - `fileSeek`
    - `fileSeekEnd`
    - `fileWrite`
    Important note: This change is not upwardly compatible. All existing code must be recompiled for this change, and any code using the fileXxx functions must be modified to use the new File intrinsic class. The necessary code changes are relatively straightforward, since the names of the new File methods are similar to those of the old functions.
  - The compiler now generates an implicit constructor for each object or class that inherits from multiple base classes and does not provide an explicit constructor. The implicit constructor simply invokes each base class's constructor, in the same order in which the base classes are listed in the superclass list.
  - Added grouped sub-alternatives to rules in the `grammar` statement. This allows portions of an alternative in a rule definition to be grouped for alternation; for example, a rule can be defined as "`('take' | 'get' | 'pick' 'up') nounList->lst_`", which is more concise than flattening out the grouped alternation manually.
  - Added the `#ifempty` and `#ifnempty` variable-arguments expansion operators, which allow conditional expansion in a varargs macro depending on whether or not the varargs part is empty.
  - Added the -P option to t3make: this preprocesses the source file, writing the expanded results on standard output. When -P is specified, no compilation or linking is performed, so no object or image files are created.
  - Added new String intrinsic class methods: `startsWith()`, `endsWith()`, and `mapToByteArray`.
  - Added a feature to the `substr()` method of the String intrinsic class: if the starting index (the first argument) is negative, it indicates an offset from the end of the string: -1 is the last character of the string, -2 the second-to-last, and so on.
  - Added a new function to the "tads-io" function set: `getLocalCharSet`, which returns the name of one of the active local character sets on the current system.
  - Added new functionality to the "tads-io" function set for files. Files can now be opened in "raw" mode, which allows reading and writing byte arrays. Bytes written to and read from a file in raw mode are not translated or modified in any way; this mode offers direct access to external files, for purposes such as manipulating files in formats defined by other applications. The `fileRead()` and `fileWrite()` functions in this mode take ByteArray arguments.
  - Added new functionality to the "tads-io" function set: the `fileOpen()` routine can now take an object of intrinsic class CharacterSet instead of a character set name. If you've already instantiated a CharacterSet object for other reasons, it is more efficient to re-use the same object by reference in this manner than to pass the name of the character set to `fileOpen()`, since `fileOpen()` has to create another mapping object when given only a character set name.
  - Added the new CharacterSet intrinsic class.
  - Added the new ByteArray intrinsic class.
  - In the Object intrinsic class, method formerly known as `isClass()` has been renamed to `ofKind()`. x.ofKind(y) returns true if x is an instance or subclass or y. In addition, this method has been changed so that x.ofKind(x) returns true for any x.
  - Added a built-in character set mapping for ISO 8859-1 (Latin-1). This character set is in widespread use because of its status as the default HTTP character set, and has an especially simple mapping to Unicode, so it seemed worthwhile to add as a built-in set not requiring an external mapping file. The assigned name of the set is "iso-8859-1".
  - Changed the compiler's former `-r` option to `-a`, and the former `-rl` to `-al`. (The `-a` option forces recompilation of all involved modules even when not out of date with respect to the source files, and `-al` forces relinking even when the image file isn't out of date with respect to the object files; these options effectively override the compiler's normal dependency analysis for cases when the automatic analysis is incorrect for some reason.) This change is gratuitous and cosmetic, but makes the compiler's option names more closely resemble that of traditional "make" programs.
  - Fixed a compiler bug: the compiler reported a spurious "symbol already defined" warning when a particular grammar production had rules defined in multiple modules. This has been corrected.
  - Fixed a preprocessor bug: if the argument of a #message was missing its closing right parenthesis, the preprocessor got stuck in an infinite loop. This has been corrected.
  - Fixed a bug in the Vector intrinsic class (and, by inheritance, in the Array intrinsic class): if the `insertAt` method was called on an empty vector, a crash occurred. This has been corrected.
  - Fixed a compiler bug that caused the compiler to crash if confronted with a `foreach` statement in the absence of the definition of the Collection and Iterator classes. This has been corrected; the compiler now generates the appropriate error message and recovers gracefully.
  - Fixed a problem with the grammar production object that caused new match tree objects to bypass constructors on creation. The match tree constructors are now invoked as for any other object instantiation.
  - Fixed a problem in the debugger that prevented the debugger from taking control on a run-time exception being thrown when another run-time exception had previously occurred at the same place twice in a row with no intervening debugger activity.
  - Fixed a problem that caused the debugger to crash under some unusual conditions when an entry in the local-variables window was selected and later automatically removed due to an execution context change.
  - Improved the robustness of the debugger when the program being debugged caused a stack-overflow exception.
  - Updated the calc.t example to the new GrammarProd.parseTokens() interface.
  - Fixed a bug that caused comparisons of any two function pointers to yield unequal, even for equivalent function pointers. This bug had numerous subtle manifestations; for example, a function pointer key in a LookupTable could never be found, since a test for equality to the key would never succeed.
  - Fixed a compiler bug that caused the incorrect error message to be reported when a replace/modify of an extern object was out of order in a link (the message reported that a function rather than object was involved).
  - Removed a spurious warning that was generated when a dictionary was imported from multiple symbol files.
  - Fixed a bug in the GrammarProd intrinsic class that caused "*" tokens in subproductions to be misinterpreted. In the past, the "*" token only worked properly in top-level productions (i.e., a production on which parseTokens() was called); this has been corrected so that "*" works properly at any level.

  ### Changes for 05/05/2001

  - Incompatible intrinsic class API change: The return value of the `parseTokens()` method in the GrammarProd intrinsic class has been changed. In the past, this method returned a list, each of whose elements was a sublist of two elements. Each sublist described one successful match tree; the first element of each sublist was the number of tokens matched, and the second was the root object of the match tree. The 4/29/2001 version added the firstTokenIndex and lastTokenIndex properties to the match objects; since the number of tokens matched in a tree can be inferred from the firstTokenIndex and lastTokenIndex values, the token counts in the return sublists were redundant. Therefore, to simplify the API, the sublists have been eliminated, and `parseTokens()` now returns simply a list of match tree root objects. To obtain the token count for a match, simply calculate `(match.lastTokenIndex - match.firstTokenIndex - 1)`, where `match` is the root object in the match tree. Since the root object in a tree encompasses the entire match, its token range necessarily encompasses the range of tokens for the entire match.
  - Added variable-argument macros.
  - Fixed a problem in the GrammarProd intrinsic class that prevented a rule from being matched when it ended with the special '*' token and was used as a subproduction in another rule. This now works correctly.
  - Fixed a problem in the compiler that caused a spurious warning message indicating that a dictionary symbol had been imported multiple times. This warning was generated whenever the dictionary was declared in more than one source file but not in all source files; each file that did not declare the dictionary displayed the warning. This has been corrected.
  - Added the `delegated` keyword, which allows delegating a method call to an unrelated object.
  - Added the `getMethodDefiner()` intrinsic function, which returns the object that defines the currently executing method.
  - Changed the default name of the ASCII character set mapping to "us-ascii" for better readability. The old name ("asc7dflt") is still accepted, but is now obsolescent and should not be used in new code. All of the #charset directives in the system headers provided with the compiler have been updated to use the new "us-ascii" name.

  ### Changes for 04/29/2001

  - Fixed a problem in the GrammarProd intrinsic class that caused incorrect results to be returned with productions that matched exactly zero tokens.
  - Extended the `grammar` syntax to allow the "`->`" notation to be used with literal tokens. In the past, the arrow was only allowed with symbol-match tokens (subproductions and token classes), but it is often desirable to be able to retrieve the matching token even for a literal match. There are two cases in particular where a literal's matching token is needed to reconstruct the original input: when the literal is matched with truncation; and when a production has several alternatives with different literals.
  - Modified the GrammarProd intrinsic class so that each match object now includes more direct information on the tokens involved in the match. The parser now sets the firstTokenIndex and lastTokenIndex properties of each match object to indicate the index of the first token and of the last token, respectively, that are involved in matching the rule corresponding to the match object. This is a simple range, so all of the tokens from the first to the last, inclusive, constitute the match's original text. In addition, the parser sets the tokenList property of each match tree item to the original token list passed into parseTokens() (this doesn't take up nearly as much memory as it might at first appear, since all of the match objects reference a single shared copy of the token list). The exported properties firstTokenIndex, lastTokenIndex, and tokenList are defined in gramprod.h.
  - The compiler now creates a dictionary entry in the default dictionary, if one is defined, for each literal string that appears in a "grammar" statement's rule list. If no default dictionary is defined when a "grammar" statement is encountered, the statement's literals are not entered into any dictionary. Each literal string is associated with the production object and the property "miscVocab". Since these strings are now stored in the dictionary, it is simple to determine if a word is defined in any context; without the grammar literal dictionary entries, it was not possible to determine if a given string, when entered by a user at run-time, was known in the context of a grammar literal.
  - The "grammar" syntax has been extended to allow a "tag" to be associated with each "grammar" statement. To specify a tag, specify any symbol or number in parentheses after the production name. For example:

            grammar nounPhrase(1): adjective->adj_ : object ;

    The tag's only purpose is to provide an identifying name for the new "grammarInfo" method, described below.

  - The compiler now automatically creates a method for each grammar match object that makes it possible to traverse match trees without knowing their internal structure in advance. The new method is called "grammarInfo," and it returns a list. The list's first element is a string giving the name of the production, with the optional tag (see above) enclosed in parentheses after the production's symbolic name. Each subsequent element is the value of a property appearing after an arrow ("->") in the production's rule list.
  - Modified the grammar production matching algorithm so that [badness] matches are examined as a group rather than individually. In particular, when a number of [badness] alternatives arise simultaneously, the parser had in the past examined only one such alternative at a time once determining that no better matches were available. Now, all [badness] alternatives with the lowest badness value are examined in parallel. This is important in some cases for the same reasons that parallel consideration of regular alternatives is necessary.
  - Fixed a compiler problem that caused spurious "variable assigned but not used" warnings in certain situations. In particular, if a local variable was defined in a nested scope within a method, and the variable was used only within the lexical confines of an anonymous function within the nested scope, the compiler did not correctly mark the variable as having been used and thus incorrectly reported the warning. This problem did not affect code generation; its only effect was the unnecessary warning.
  - Enhanced the Dictionary intrinsic class's findWord() and findWordTrunc() methods so that the property argument in each can be omitted or specified as nil, in which case all objects with vocabulary matching given text, for any part-of-speech property, will be returned.
  - Fixed a debugger problem that caused a crash in some obscure cases involving opening a file during a debugger session when the debugger had never taken control since the beginning of program execution, and a similar problem that occurred when the VM threw a run-time error exception under similar circumstances.

  ### Changes for 04/15/2001

  - A new mechanism allows capturing calls to undefined methods and properties. When a call is made to an undefined method, the VM now calls a new property, `propNotDefined()`, on the target object. The new method receives as arguments the the undefined property ID and the arguments to the original method call. If `propNotDefined` is itself not defined, the VM simply returns nil for the undefined method call, as it did in the past.
  - Added some new regular expression features:
    - Character classes can now be combined with '|', as in <upper|digit> (matches any upper-case letter or any digit).
    - Character classes can now be complemented with '^', as in <^upper> (matches anything except upper-case letters).
    - Added some named character expressions, which look similar to character-class expressions, and which can be combined with character-class expressions via '|': <upper|star> matches any upper-case letter or an asterisk.
  - Renamed the t23run.exe executable to simply tr32.exe, so the combined TADS 2+3 interpreter is now the default interpreter. The separate interpreters are now called t2r32.exe (for TADS 2) and t3run.exe (for TADS 3). For the most part, users will not need to run the version-specific interpreters at all; the only time these should be needed is when bundling a game into an executable, in which case it is desirable for the sake of minimizing file sizes to include only the version of the interpreter actually needed.

  ### Changes for 3/28/2001

  - The object definition syntax has been extended to allow an object's property list to be enclosed in braces. Refer to the Object Definitions documentation for details.
  - The object definition syntax now provides "nested" objects. A nested object is an anonymous object defined in-line within another object, with a property of the enclosing object initialized with a reference to the nested object; this syntax is convenient for defining certain types of small helper objects.
  - The language now has a static property initialization syntax, which allows a property to be initialized with a non-constant value computed at compile-time.
  - Changed the behavior of the '+' property. The new behavior is much simpler than the previous behavior: if an object is defined with N plus signs, its '+' property is initialized to the most recent object defined with N-1 plus signs. Explicitly setting the '+' property in an object list is now irrelevant. Refer to the documentation for details.
  - Changed the default filename suffix for image files to ".t3" (it was formerly ".t3x") to make image filenames somewhat more friendly looking.
  - Added the new executable "t23run" - this is a 32-bit console-mode combined TADS 2 and TADS 3 interpreter. You can use this single application to run games compiled for TADS 2 or TADS 3. This version of the interpreter is not designed for bundling single-file games for distribution, since this would unnecessarily increase the size of bundled games; use the appropriate single-version interpreter executable for bundling.
  - Added the new executable "html23" - this is a combined TADS 2 and TADS 3 version of the HTML interpreter.
  - For anyone interested in porting the combined command-line interpreter on another platform, the code that implements this should be easily portable to other command-line operating systems. See the target 't23run.exe' in win32/makefile.vc5; you can find the source code for the main program entrypoint in vmcl23.cpp. For systems that don't use Unix-style command lines, the command line code itself won't be portable, but portable code for sensing the engine version needed to run a given game file can be found in vmmain.cpp.
  - Fixed a bug that caused problems with certain "reflection" methods when the program used `modify` to extend the `TadsObject` intrinsic class. If the program modified `TadsObject`, then traversed the object tree (using the `getSuperclassList()` method), or used the `propDefined()` method, the behavior was incorrect, and could lead to VM crashes. This has been corrected.
  - Added documentation on the `#charset` directive and using source files encoded in Unicode UCS-2.
  - Added a `#charset "asc7dflt"` directive to each system source and header file included with the compiler distribution. This directive ensures that the compiler interprets the contents of the system files correctly, in case the user wants to specify a default character set for the compilation with the `-cs` compiler option.
  - The compiler now accepts Unicode character 0x2028 ("line separator") as equivalent to a newline in source files that use of the Unicode encodings the compiler accepts (UCS-2 big-endian, UCS-2 little-endian, or UTF-8).
  - In text mode, the `fileRead()` function now properly translates input characters according to the character set selected when the file was opened. (In the past, the character set was ignored, and the characters from the file were not properly translated to Unicode.) In addition, the `fileRead()` function accepts Unicode character 0x2028 (the Unicode line separator character) as equivalent to a newline (but note that, as always, the text returned from `readLine()` represents each end-of-line with a single '\n' character, regardless of the type of line termination in the underlying file).

  ### Changes for February 24, 2001

  - Added the `t3AllocProp()` intrinsic function, which allocates a new property ID.
  - Added the `Object.getPropList()` method, which returns a list of properties directly defined by an object.
  - Added the `Object.getPropParams(prop)` method, which returns information on the parameters taken by a property or method.
  - Added the `getFuncParams(funcptr)` intrinsic function, which returns information ont he parameters taken by a function.

  ### Changes for February 10, 2001

  - The new `property` statement allows a program to explicitly declare property symbols. This is optional, but can be useful in certain cases in library code.
  - Added the LookupTable intrinsic class, which implements a general-purpose associative array type. A LookupTable is similar to a Vector, but whereas a Vector can use only integers as indices, a Hashtable can use any value as an index.
  - Added the new `t3GetGlobalSymbols()` intrinsic function, which provides programmatic access to the compile-time names of objects, properties, functions, intrinsic classes, and enumerators.
  - The preprocessor now treats square brackets ("[ ]") and braces ("{ }") as grouping symbols when parsing macro arguments. In the past, only parentheses were counted. This allows list constants and anonymous functions to be used more easily as macro arguments.
  - In `_main.t`, added a new function, `initAfterLoad()`. The main program entrypoint in `_main.t` (function `_main()`) calls this new routine to perform initialization. This routine sets up the default display function, performs pre-initialization if necessary, then performs regular load-time initialization. All of these operations were previously carried out in `_main()`; the reason they've been separated into a new function is to allow the same operations to be called after a `restartGame` operation. Since a `restartGame` effectively re-loads the image file and starts the game over from scratch, the same initialization that `_main()` performs at initial load must be performed immediately after a restart; this function makes this common code easy to re-use.
  - Added a new method to the TadsObject intrinsic class: createInstance(), which creates an instance of the object. This method passes its arguments to the new object's constructor, if any, and returns a reference to the new object.
  - Added `execAfterMe` to `ModuleExecObject` in `_main.t`. User code can initialize this property in a given `ModuleExecObject` instance to contain a list of other `ModuleExecObject` instances that are to be initialized after the given instance; this is analogous to the `execBeforeMe` list, but allows an object to specify things that are to come after it. It is sometimes desirable to be able to specify initialization order dependencies by specifying what must follow rather than what must precede initialization of a given object, and this new property provides the flexibility to specify order dependencies either way.
  - A makefile for DJGPP (the definitive port of Gnu C/C++ for MS-DOS) is now included in the source distribution. This makefile can be used to create a 32-bit version of the interpreter that will run on MS-DOS on PC's with 386 or later processors.
  - Fixed a VM problem that caused modification of the root intrinsic object (i.e., `modify Object`) to fail. In the past, the VM simply failed to execute code added to the root intrinsic object with `modify`. This has been corrected; code added to `Object` is now properly inherited from the other intrinsic classes.
  - The String and List intrinsic classes can now be extended with the `modify` mechanism. In the past, the VM did not correctly handle code extensions to the String and List intrinsic classes.
  - Fixed a compiler bug that caused incorrect code generation when adding a constant zero value to a local variable which, at run-time, ends up containing a vector, list, or other non-integer value.
  - The Vector intrinsic class can now be used with the `foreach` keyword to loop over the elements in a vector. (In previous versions, the Vector class incorrectly omitted support for `foreach`.)
  - The "Frames" version of the documentation should now work correctly with Netscape and other browsers that had trouble with past versions. (The frames page had some ill-formed HTML, which some browsers rejected, but this page has now been corrected.)
  - Changed the text of the VM error message that results from applying an index to a type that cannot be indexed (nil[3], for example). In the past, the message read "invalid type for indexing - value cannot be index," which incorrectly signified that there was something wrong with the index value, when in fact the value being indexed was the problem. The message has been changed to read "invalid index operation - this type of value cannot be indexed."
  - Fixed a problem in the Vector intrinsic class that caused a vector's data to be corrupted by certain operations that should have, but did not, increase the internal storage space allocated for the Vector object.
  - Fixed a compiler problem with object templates. The compiler did not properly parse object templates that included list tokens; this has been corrected.
  - Fixed a bug in the `rand()` intrinsic function. In the past, this function crashed the interpreter if the argument was a list with no elements. This has been corrected; the function now returns `nil` when the argument is a list with no elements.
  - Fixed a problem with the `Vector` intrinsic class that caused pre-initialized data to be loaded incorrectly.
  - Corrected the documentation (the expressions chapter) to reflect the correct precedence of the "`[]`" and "`.`" operators, which should be above the unary operators.
  - Added four new methods to the List intrinsic class: `prepend(val)`, which inserts a new value at the start of a list; `insertAt(index, val1, val2, ...)`, which inserts one or more values into a list at a given position; `removeElementAt(index)`, which deletes the element at the given index; and `removeRange(startIndex, endIndex)`, which removes the elements in the given range of indices.
  - Added a new method to the Vector intrinsic class: `prepend(val)`, which inserts a new value at the start of a vector.
  - It is no longer legal to apply the unary "`&`" operator to an object symbol. In the past, "`&objectName`" was the same as simply "`objectName`"; this is no longer legal. "`&objectName`" was never a meaningful construct, since an object symbol yields a reference to the object to begin with, but past versions of the compiler accepted it without complaint and treated it as equivalent to the unadorned object symbol; the compiler now rejects this construct.
  - It is no longer legal to apply the unary "`&`" operator to a function name symbol. In the past, "`&functionName`" yielded a reference to the function. This has been changed so that the function name used by itself yields a reference to the function, just as an object name does.
  - Because the "`&`" operator can no longer be used with any symbol types other than properties, there is no longer a warning when using the operator with an otherwise undefined symbol name. "`&symbol`" now unambiguously defines the symbol as a property name.
  - Fixed a compiler bug that caused a spurious warning message when compiling certain types of expressions involving property pointers. The warning did not affect code generation, but it was incorrect and has been removed.

  ### Changes for version 3.0.2 (September 27, 2000)

  - Fixed a compiler problem that caused the compiler to go into an infinite loop (and therefore freeze up) when confronted with a 'switch' statement containing code before the first 'case' or 'default' label. This has been corrected; the compiler now reports an error (such code is unreachable) and continues with the compilation.
  - Fixed a minor compiler problem that generated a spurious warning message in a certain situation. Specifically, if none of a 'switch' statement's 'case' labels led to code paths that could reach the next statement after the 'switch' (for example, if every code path reachable from a 'case' label led to a 'return' statement), but the 'switch' had no 'default' label, the compiler generated the warning message "unreachable statement" at the next executable statement after the 'switch'. This warning was incorrect because, in most cases, it is not safe to assume that every possible value of a switch's controlling expression is included in the list of explicit cases, hence the next statement following a 'switch' with no 'default' is reachable any time the controlling expression's value is not in the list of explicit 'case' labels. Note that this problem merely caused the spurious warning and did not affect code generation.

  ### Changes for June 24, 2000

  - Fixed a compiler problem with try/catch statements. The compiler did not correctly generate handlers for any catch block past the first for a given try statement; this has been corrected.

  ### Changes for version 3.0.1 (June 17, 2000)

  - The meaning of the syntax `x.y` and `&y` have changed slightly, in a way that will be transparent to most code. In the past, if `y` was a local variable, then `x.y` evaluated the local, then called the method on `x` specified by the property pointer value in the local; `&y` simply generated a compilation error because a local's address cannot be evaluated. This behavior has changed. Now, `x.y` and `&y` both ignore the local definition of `y` and interpreter `y` as a property name. This change is important because it allows code to refer to a property explicitly, even when a local of the same name has been defined in the code block. For example:

           myObject: object
             obj = nil
             setObj(obj) { self.obj = obj; }
           ;

    In the past, the code above would have had to use a different name for the formal parameter variable `obj`, because it would not have been able to refer to the property of the same name. With the new interpretation, the code can distinguish between the local and the property by referring to the property explicitly using `self.obj`.

    Note that it is still simple to obtain the old behavior of evaluating the local variable and calling a method via the resulting property pointer. To do this, simply enclose the local in parentheses: `x.(y)`.

  ### Changes for 5/21/2000

  - Add a new Vector intrinsic class, a subclass of Array that combines the reference semantics of an Array with the dynamic sizing capabilities of a List. Vector is substantially more efficient than List when constructing a collection iteratively.
  - Added some new List methods: sort, append, appendUnique.
  - Added new Array methods: sort, appendUnique.
  - Added an error message translation mechanism, which allows non-English versions of the interpreter's and compiler's error messages to be substituted at run-time. Messages can be loaded from an external file, so there is no need to recompile the system to switch languages. (At the moment, of course, only an English set of messages actually comes with the system, but it is hoped that a few translated versions will be contributed so that more languages will be supported "out of the box" in the future.)
  - Fixed a bug that reversed the order of arguments in calls to anonymous functions while running in the debugger.

  ### Changes for 5/11/2000

  - Changed the name of the `say` function in the "tads-io" intrinsic function set to `tadsSay`. This allows the library to define its own higher-level function called `say`; since user code should almost always call the library's function rather than the low-level direct console output function, it is desirable to give the library version the shorter, more convenient name.
  - Added the `appendUnique()` method to the List and Array intrinsic classes.

  ### Changes for 4/24/2000

  - Fixed a bug in the compiler that caused lost properties on objects under certain very complicated circumstances (the problem occurred when dictionaries and other objects were defined in a particular order).

  ### Changes for 4/22/2000

  - Added the `foreach` statement.
  - Added the Collection and Iterator classes. List and Array are now subclasses of Collection, so these classes can create Iterator objects to visit their elements.
  - The Windows HTML interpreter now supports PNG transparency (this is a generic change to the Windows HTML renderer that will also be in HTML TADS 2.5.4). Note that only simple transparency is supported; full alpha blending is still not supported. PNG transparency now has its own systemInfo() capability code, SYSINFO_PNG_TRANS.

  ### Changes for 4/16/2000

  - Fixed a bug that caused a compiler crash when a source file was completely empty (or contained only comments).
  - Fixed a bug that caused a compiler crash in certain situations involving multiple initializers in a single 'local' statement.

  ### Changes since 3.0.0

  - Added the htmlify() method to the String class. This method converts any HTML markup-significant characters in the string to their HTML equivalents; in particular, it converts an ampersand ("&") to "&amp;" and a less-than sign ("<") to "&lt;", and can also optionally quote spaces, tabs, and newlines to ensure display fidelity for these whitespace characters as well.
  - Added a shortest-match modifier to the regular expression closure operators ("*", "+", and "?"). This feature provides precise control over how matches are allocated in expressions involving multiple closures.
  - Added the non-capturing modifier to the regular expression group syntax; this allows a parenthesized group to be omitted from the counted groups.
  - Added look-ahead assertions to the regular expression syntax.
  - Added the regular expression interval operator, which provides a compact notation for specifying a specific number of repetitions of a sub-expression.
  - Renamed a few list methods and array methods, and expanded both sets for greater consistency and more complete functionality:
    - indexOf
    - indexWhich
    - valWhich
    - lastIndexOf
    - lastIndexWhich
    - lastValWhich
    - countOf
    - countWhich
    - mapAll
    - applyAll (arrays only)
    - forEach
    - getUnique
  - When the default start-up module (_main.t) is automatically included in a build, _main.t is linked in first. It was formerly linked in last, which didn't allow 'modify' or 'replace' to be used with objects defined in the module.
  - When running under the debugger, RuntimeError exceptions now include stack trace information (with source line information) in the exceptionMessage string associated with the exception object. This makes it easier to track down where a run-time error occurred. Note that this information is available only when running under the debugger, because this is the only time the system has access to the necessary source line information.
  - Added a "character map library" mechanism to the stand-alone interpreter. This new feature allows a set of character map (.tcm) files to be bundled with a stand-alone game, eliminating the need to distribute separate .tcm files with a stand-alone game. (Having to distribute .tcm files seemed to defeat the purpose of building a stand-alone executable. The new bundling feature still allows users with localizations that aren't included in the standard character map set to add their own .tcm files, but it makes character mappings entirely invisible for most users.)
  - Added CP1250.TCM (a character set mapping for the Windows Eastern/Central European code page), CP850.TCM (DOS OEM Latin 1), and CP852.TCM (DOS OEM Latin 2) to the default character map set for Windows.

  ### Changes since 03/30/2000

  - Slightly changed the `InitObject` mechanism. The class formerly known as `InitObject` is now called `PreinitObject`, and a new class `InitObject` has been added. The new `InitObject` does the same thing that `PreinitObject` does, but does it at regular program start-up rather than pre-initialization. This change makes the pre-initialization and regular initialization mechanisms work the same way. In addition, to make this mechanism more generic, both `InitObject` and `PreinitObject` now descend from a base class called `ModuleExecObject`; this class should be usable as the base class for other types of modular execution objects, such as perhaps a post-restore initializer sequence, a command parsing initializer sequence, and so on. Refer to the library pre-initialization documentation for details.
  - Added the `-r` option to the interpreter, allowing games to be restored directly from the command. The saved state files now include information on the image file that created them, so if you're restoring a game, you don't have to specify the image file; this particular feature also allows double-clicking on a saved state from the desktop to start the interpreter, load the image file, and restore the saved state.
  - The GrammarProd intrinsic class's parseTokens() method now includes truncated matches to dictionary words (according to the dictionary's truncation length setting) in its structural analysis. The method also includes truncated matches (again, using the dictionary setting) for literal tokens in the grammar. If you don't want to allow truncated matches, simply change the dictionary's truncation length setting to zero.

  ### Changes since 03/26/2000

  - Added a new library pre-initialization mechanism based on "initialization objects" rather than a simple preinit() method. This new mechanism should be especially useful for library developers, since new initialization objects can be plugged in without touching any library or user code
  - It is now possible to extend intrinsic classes with user-defined methods.

  ### Changes since 03/21/2000

  - The method-based API to certain functions that were formerly implemented as intrinsics is now official. The trailing underscores on the interim method names have been removed, and the corresponding functions have been removed from the intrinsic function sets.
    - getSuperclassList() is now Object.getSuperclassList()
    - isClass() is now Object.isClass()
    - propDefined() is now Object.propDefined()
    - propType() is now Object.propType()
    - length() is now List.length() and String.length()
    - sublist() is now List.sublist()
    - intersect() is now List.intersect()
    - car() and cdr() are now List.car() and List.cdr()
    - substr() is now String.substr()
    - toUpper() is now String.toUpper()
    - toLower() is now String.toLower()
    - find() is now List.find() and String.find()
    - toUnicode() is now String.toUnicode()
    This change will, of course, necessitate recompiling all code, and will require changing code that calls any of the functions that have been migrated to methods. The sample code included in the distribution has been updated to reflect the changes, and the documentation has also been updated.
  - Renamed the `getSize()` method in the Array class to `length()`, for consistency with List and String.
  - Added the 'is in' and 'not in' operators. See the "is in" and "not in" expressions section.
  - The debugger now has "program arguments" settings. You can access these settings via a dialog, which you can open using the "Program Arguments" item on the "Debug" menu. You can use the program arguments to control script file reading, output logging, and the argument string that is passed to your program's "_main()" entrypoint procedure.
  - Added several new regular expression features: <Case> and <NoCase>, <Alpha>, <Upper>, <Lower>, <Digit>, <AlphaNum>, <Space>, <Punct>. Refer to the new regular expressions section of the documentation for details.
  - Enhanced the regular expression parser to detect and remove cycles in compiled patterns. It is possible (pretty easy, actually) to introduce "infinite loops" into a pattern; the easiest way to do this is to put a zero-or-more closure inside another closure, as in "(.*)+" (this has an infinite loop because the expression in parentheses can match zero characters, and that match can be repeated any number of times), but much more complex and subtle types of cycles are possible and can be inadvertantly constructed. Eliminating the infinitely repeating zero-length matches obviously doesn't change the meaning of the expression, since one repetition of a zero-length match is as good as a million, so the regular expression matcher simply detects and removes these loops and then carries on as normal.
  - Updated StartI3.t and StartA3.t (the starter games in the Workbench kit) to work with _main.t, so you don't have to compile them with -nodef. (This also has the benefit of making the files a whole lot simpler.) Also updated them to use method calls rather than intrinsic function calls where appropriate.
  - Updated the sample files to use the standard _main.t startup and new property functions.

  ### Changes since 03/12/2000

  - Added default display methods, which allow string display to be routed through a method of the active "self" object in effect each time a string is displayed and each time an expression embedded in a string via the << >> syntax is displayed. This powerful new feature allows for per-object output filtering, and allows for "stateful" filtering (in that the filtering function is a method of the object that initiated the filtering, and can therefore look at properties of "self" to perform its work).
  - Added the "short form" anonymous function syntax, which is much more compact than the long form, but can only be used to define functions that consist solely of a single expression.
  - Added the `subset()` and `applyAll()` methods to the array and list intrinsic classes.
  - Added documentation for the List intrinsic class.
  - Added the `-cs` interpreter option, which allows the user to specify a character set to use for the display and keyboard. Refer to the new interpreter section in the documentation.
  - As mentioned above, there is a new section on the interpreter in the documentation.
  - The TADS 3 HTML interpreter and debugger for Windows now use a separate registry key for storing their preference settings. In addition, the TADS 3 debugger's global preferences file is now called HTMLTDB3.TDC. These changes should allow TADS 2 and TADS 3 installations to co-exist independently on a single system, without affecting one another's stored configuration settings.
  - Anonymous function objects are now represented by their own intrinsic class. This is a mostly internal change, but does have the benefit of enabling the debugger to display the type of an anonymous function object (before, the debugger only knew that they were objects).
  - Made some internal changes to the way anonymous function context objects are implemented to make them more efficient. (In particular, context objects are now arrays, not TADS objects; array index lookup is faster than TADS object property lookup.)
  - Moved the code to Visual C++ 6 (which involved no changes, not surprisingly, although the new C++ compiler caught a few dubious constructs and generated helpful warnings, all of which have been cleaned up).