### Start-up Code

In previous versions of TADS, when the program started running, TADS called an initialization function (called `init`) to carry out any special start-up processing that the program wanted to perform. This function performed any needed initialization, then returned. The system then entered a command loop, in which the system prompted the user, read a command line, parsed the command, and called program functions and methods to execute the operations of the command.

TADS 3 does not have a built-in parser, and it doesn't even have a built-in command loop. Instead, the program is responsible for all of this. At start-up, the VM calls an "entrypoint" function (called `_main`). This function is called the entrypoint because it's the point at which control enters the program. The `_main` function does not return until the program has finished executing. Once `_main` returns, TADS 3 terminates the program.

In this respect, TADS 3 is more like a traditional programming language (such as Java or C++) than it is like previous versions of TADS. This approach requires some extra coding in the game program, but it provides much greater flexibility, since the program is no longer forced to work with a pre-defined command loop. Besides, any extra code needed for start-up will eventually be available from libraries, so most game authors won't have to code this part of the program anyway.

The `_main` function receives one argument, which is a list giving the strings making up the command line. The first entry in this list is the name of the program image file; the subsequent entries in the list are the strings that follow the image file name on the command line that started the program. The rules for parsing command lines vary from system to system, but on most systems, arguments are delimited by spaces unless the arguments are enclosed in quotation marks. For example, this command line:

       t3run mygame "first argument" second third

Would yield a list with four elements on most systems:

       'mygame.t3'

       'first argument'

       'second'

       'third'

The `_main` routine normally also sets up the default display function, so that double-quoted strings and embedded text can be displayed. See Default Display Function for details.

Note that most libraries will probably include their own VM-level (`_main`) entrypoint implementation. This is the primary reason for the odd name: most libraries will probably provide standard implementations of `_main()`, which will set up and then call another function, to be provided by the user code. Library-provided `_main()` functions will probably want to set up a top-level error handler (via the `try` statement), check the pre-initialization mode, possibly process the command-line arguments or other environmental data, and call a secondary entrypoint function provided by user code. This is akin to the way most C compilers work: the compiler's standard run-time library provides a low-level start-up routine, which serves as the entrypoint from the operating system; this function normally does some initial processing, then calls the `main()` function defined by the program.

### Default Start-Up Code

TADS comes with source code for a default start-up module. This code is in a file called _main.t, in the same directory as the compiler. By default, t3make will automatically include this module in your program, which makes it unnecessary for you to add the module to your build explicitly.

The code in _main.t implements several functions and objects that most TADS 3 programs will need. Most programs will have no reason to modify the default versions provided in _main.t, which is why t3make includes the file in all builds by default; however, if you do need to replace this module, you can use the –nodef compiler option to tell the compiler not to include this default module.

The functions and objects implemented in _main.t are:

- _main(args). This function is the main entry-point that the VM calls when the program is loaded. The _main.t implementation performs the following steps:

- Establishes a default display function (_default_display_fn(), also implemented in _main.t).
- Runs pre-initialization if necessary by invoking each PreinitObject's execute() method. During the special post-compilation pre-initialization step, the default start-up code stops here. If this is a normal execution, though, the library checks to see if pre-initialization has already been completed by checking the mainGlobal.preinited_ flag, and skips this step if this flag is set to true, which indicates that pre-initialization has already been performed.
- Runs initialization if by invoking each InitObject's execute() method.
- Calls the function main(args), which you must provide.

All of this is done within a try/catch block; if any exceptions are caught at this level, the catch block displays the exception's error message and terminates the program.

- forEachInstance(cls, func). This function is a simple object "iterator" function; it iterates (in arbitrary order) over all instances of the class given by the "cls" argument, and for each instance invokes the function given by "func", passing the current instance as the function's single argument. This function is provided for convenience; you can use it as an alternative to writing a loop involving the firstObj/nextObj functions.
- class Exception: object. This class is defined to serve as the base class for all exceptions, including run-time errors and program-defined exceptions. The class defines a method, displayException(), that should be overridden in all subclasses to display an appropriate message describing the exception.
- class RuntimeError: Exception. This class is the base class for all run-time exceptions that the VM itself throws.
- class ModuleExecObject: object. This is the base class for PreinitObject and InitObject.
- PreinitObject: ModuleExecObject.
- InitObject: ModuleExecObject.
- _default_display_fn(val). This function simply calls the function tadsSay(val) from the "tads-gen" intrinsic function set.
- mainGlobal: object. This object simply serves as a set of global variables for the _main.t module. In particular, this object's property preinited_ stores the pre-initialization status; this property is set to true after pre-initialization has been completed.

When you use the default start-up code, you must define the main(args) function. This function is your program's main entrypoint; the default start-up code calls main(args) after performing its initialization steps, as described above. "args" is a list of strings giving the arguments to the program.

### Pre-initialization

With TADS 2, if your game program defined a function called preinit(), the compiler called this function after completing compilation and before writing the binary .GAM file. TADS 3 has a similar mechanism but implements it differently.

Note that, if you're using the default start-up code, you should perform pre-initialization by defining one or more PreinitObject instances. Refer to library pre-initialization for details.

In TADS 3, after linking is complete, when not compiling for debugging, `t3make` calls the main entrypoint function (_main), just as it would for normal execution. However, the system sets a special internal flag that indicates that it's performing pre-initialization rather than a normal run of the program. You can access this flag via the `t3GetVMPreinitMode()` function in the "t3vm" function set; this function returns true if pre-initialization is taking place, nil during normal execution.

When you compile for debugging (with the "-d" flag to t3make, for example), the compiler does not perform pre-initialization. Instead, this step is deferred until you run the program with the interpreter. This difference is important because it allows you to step through the pre-initialization code with the debugger when you compile for debugging; if pre-initialization were to run as part of compilation for a debug build, you wouldn't have a chance to trace through that code.

Note that the difference between the debug and non-debug build modes does not mean that you have to write your code differently for the two modes. Pre-initialization runs in both types of builds, and runs in the same sequence in both types of builds; as far as your program is concerned, there's no difference at all. The only difference is where the pre-initialization step is carried out. Here's a summary of the sequence of events in the two cases:

Normal (non-debug) builds:

    ·           Compiler:

    o          Compiles program

    o          Runs pre-initialization

    ·           Interpreter:

    o          Executes the main program

    Debug builds:

- Compiler:

o Compiles program

- Interpreter:

o Runs pre-initialization

o Executes the main program

In both cases, the sequence of events that your program sees is the same: compile, pre-initialize, run.