How the program starts up, in a Basic Inform project.


§1. Summary. These rules perform the essential tasks required for setting up the virtual machine. This includes checking that we are running in a compatible interpreter, and setting up various built in Glk objects (when running in a Glk interpreter).

These rules here are the ones which get the basic machinery working to the point where it is safe to run arbitrary I7 source text. They necessarily do very low-level things, and it is not guaranteed that I7 phrases will behave to specification if executed before these early rules have finished. So it is hazardous to obstruct or alter them.

Arrangements are a little different here on the Z-machine, because some data is retained in the case of a restart.

(Many thanks are due to Eliuk Blau, who found several tricky timing errors here and elsewhere in the Glulx-specific code. Frankly, I feel like hanging a sign on the following routines which reads "Congratulations on bringing light to the Dark Room.")

§2. The startup sequence. As of IE-0022 we have a simplified startup sequence. Main calls the Startup function, which does two things: run an Architecture16Kit/Architecture32Kit function VM_Check_Functionality which checks the VM meets the minimum requirements for Inform (in Glulx it would test a few Glulx/Glk gestalts; in Z-Code it would probably do nothing.) Then it runs the Startup Rules. And that's it - everything else in the startup sequence is now in Inform-accessible rules.

Because the functions below are replaced by WorldModelKit alternatives if that kit is present, the following applies only to Basic Inform programs where WorldModelKit is not involved.

[ Main;
    self = COL_HSIZE; To ensure this definition is not optimised out
    Startup();
    Submain();
];

[ Startup;
    VM_Check_Functionality();
    say__pc = say__pc | PARA_NORULEBOOKBREAKS;
    FollowRulebook(STARTUP_RB);
    if (say__pc & PARA_NORULEBOOKBREAKS) say__pc = say__pc - PARA_NORULEBOOKBREAKS;
    rfalse;
];

§3. Initialise Memory Rule. This rule amalgamates some minimal initialisations which all need to happen before we can risk using some of the more exotic I7 kinds:

[ INITIALISE_MEMORY_R;
    LanguageInitialise();

    HeapInitialise(); Create a completely unused memory allocation heap
    StackFramingInitialise(); Create an empty stack
    CreateDynamicRelations(); Create relation structures on the heap

    #Ifdef TARGET_GLULX;
        Empty the parse buffer (see bug 0001451)
        buffer3-->0 = 0;
    #Ifnot;
        standard_interpreter = HDR_TERPSTANDARD-->0;

        dict_start = HDR_DICTIONARY-->0;
        dict_entry_size = dict_start->(dict_start->0 + 1);
        dict_start = dict_start + dict_start->0 + 4;
        dict_end = dict_start + ((dict_start - 2)-->0) * dict_entry_size;

        buffer->0  = INPUT_BUFFER_LEN;
        buffer2->0 = INPUT_BUFFER_LEN;
        buffer3->0 = INPUT_BUFFER_LEN;
        parse->0   = 15;
        parse2->0  = 15;
    #Endif;

    rfalse;
];

§4. Seed Random Number Generator Rule. Unless a seed is provided by Inform, and it won't be for released story files, the VM's interpreter is supposed to start up with a good seed in its random number generator: something usually derived from, say, the milliseconds part of the current time of day, which is unlikely to repeat or show any pattern in real-world use. However, early Z-machine interpreters often did this quite badly, starting with poor seed values which meant that the first few random numbers always had something in common (being fairly small in their range, for instance). To obviate this we extract and throw away 100 random numbers to get the generator going, shaking out more obvious early patterns, but that cannot really help much if the VM interpreter's RNG is badly written. "Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin" (von Neumann).

[ SEED_RANDOM_NUMBER_GENERATOR_R i;
    if (BasicInformKit`FIX_RNG_CFGF) {
        #Ifdef TARGET_GLULX;
            @random 10000 i;
            i = -i-2000;
            @setrandom i;
        #Ifnot;
            @random 10000 -> i;
            i = -i-2000;
            @random i -> i;
        #Endif;
    }
    if (RNG_SEED_AT_START_OF_PLAY) VM_Seed_RNG(RNG_SEED_AT_START_OF_PLAY);
    for (i=1: i<=100: i++) random(i);
    rfalse;
];