Managing, or really just delegating, the generation of ANSI C code from a tree of Inter.


§1. Target.

code_generation_target *c_target = NULL;
void CTarget::create_target(void) {
    c_target = CodeGen::Targets::new(I"c");

    METHOD_ADD(c_target, BEGIN_GENERATION_MTID, CTarget::begin_generation);
    METHOD_ADD(c_target, END_GENERATION_MTID, CTarget::end_generation);

    CProgramControl::initialise(c_target);
    CNamespace::initialise(c_target);
    CMemoryModel::initialise(c_target);
    CFunctionModel::initialise(c_target);
    CObjectModel::initialise(c_target);
    CLiteralsModel::initialise(c_target);
    CGlobals::initialise(c_target);
    CAssembly::initialise(c_target);
    CInputOutputModel::initialise(c_target);

    METHOD_ADD(c_target, GENERAL_SEGMENT_MTID, CTarget::general_segment);
    METHOD_ADD(c_target, TL_SEGMENT_MTID, CTarget::tl_segment);
    METHOD_ADD(c_target, DEFAULT_SEGMENT_MTID, CTarget::default_segment);
    METHOD_ADD(c_target, BASIC_CONSTANT_SEGMENT_MTID, CTarget::basic_constant_segment);
    METHOD_ADD(c_target, CONSTANT_SEGMENT_MTID, CTarget::constant_segment);
    METHOD_ADD(c_target, NEW_ACTION_MTID, CTarget::new_action);
}

§2. Static supporting code. The C code generated here would not compile as a stand-alone file. It needs to use variables and functions from a small unchanging library called inform7_clib.h. (The .h there is questionable, since this is not purely a header file: it contains actual content and not only predeclarations. On the other hand, it serves the same basic purpose.)

The code we generate here can only make sense if read alongside inform7_clib.h, and vice versa, so the file is presented here in installments. This is the first of those:

/* This is a library of C code to support Inform or other Inter programs compiled
   tp ANSI C. It was generated mechanically from the Inter source code, so to
   change it, edit that and not this. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <ctype.h>

§3. Segmentation.

enum c_fundamental_types_I7CGS
enum c_ids_and_maxima_I7CGS
enum c_header_matter_I7CGS
enum c_predeclarations_I7CGS
enum c_very_early_matter_I7CGS
enum c_constants_1_I7CGS
enum c_constants_2_I7CGS
enum c_constants_3_I7CGS
enum c_constants_4_I7CGS
enum c_constants_5_I7CGS
enum c_constants_6_I7CGS
enum c_constants_7_I7CGS
enum c_constants_8_I7CGS
enum c_constants_9_I7CGS
enum c_constants_10_I7CGS
enum c_early_matter_I7CGS
enum c_text_literals_code_I7CGS
enum c_summations_at_eof_I7CGS
enum c_arrays_at_eof_I7CGS
enum c_globals_array_I7CGS
enum c_main_matter_I7CGS
enum c_functions_at_eof_I7CGS
enum c_code_at_eof_I7CGS
enum c_verbs_at_eof_I7CGS
enum c_stubs_at_eof_I7CGS
enum c_property_offset_creator_I7CGS
enum c_mem_I7CGS
enum c_initialiser_I7CGS
int C_target_segments[] = {
    c_fundamental_types_I7CGS,
    c_ids_and_maxima_I7CGS,
    c_header_matter_I7CGS,
    c_predeclarations_I7CGS,
    c_very_early_matter_I7CGS,
    c_constants_1_I7CGS,
    c_constants_2_I7CGS,
    c_constants_3_I7CGS,
    c_constants_4_I7CGS,
    c_constants_5_I7CGS,
    c_constants_6_I7CGS,
    c_constants_7_I7CGS,
    c_constants_8_I7CGS,
    c_constants_9_I7CGS,
    c_constants_10_I7CGS,
    c_early_matter_I7CGS,
    c_text_literals_code_I7CGS,
    c_summations_at_eof_I7CGS,
    c_arrays_at_eof_I7CGS,
    c_globals_array_I7CGS,
    c_main_matter_I7CGS,
    c_functions_at_eof_I7CGS,
    c_code_at_eof_I7CGS,
    c_verbs_at_eof_I7CGS,
    c_stubs_at_eof_I7CGS,
    c_property_offset_creator_I7CGS,
    c_mem_I7CGS,
    c_initialiser_I7CGS,
    -1
};

§4. State data.

define C_GEN_DATA(x) ((C_generation_data *) (gen->target_specific_data))->x
typedef struct C_generation_data {
    int C_action_count;
    struct C_generation_memory_model_data memdata;
    struct C_generation_function_model_data fndata;
    struct C_generation_object_model_data objdata;
    struct C_generation_literals_model_data litdata;
    CLASS_DEFINITION
} C_generation_data;

void CTarget::initialise_data(code_generation *gen) {
    CMemoryModel::initialise_data(gen);
    CFunctionModel::initialise_data(gen);
    CObjectModel::initialise_data(gen);
    CLiteralsModel::initialise_data(gen);
    CGlobals::initialise_data(gen);
    CAssembly::initialise_data(gen);
    CInputOutputModel::initialise_data(gen);
    C_GEN_DATA(C_action_count) = 0;
}

§5. Begin and end.

int CTarget::begin_generation(code_generation_target *cgt, code_generation *gen) {
    CodeGen::create_segments(gen, CREATE(C_generation_data), C_target_segments);
    CTarget::initialise_data(gen);

    CNamespace::fix_locals(gen);

    generated_segment *saved = CodeGen::select(gen, c_fundamental_types_I7CGS);
    text_stream *OUT = CodeGen::current(gen);
    WRITE("#include <stdint.h>\n");
    WRITE("typedef int32_t i7val;\n");
    WRITE("typedef uint32_t i7uval;\n");
    WRITE("typedef unsigned char i7byte;\n");
    CodeGen::deselect(gen, saved);

    saved = CodeGen::select(gen, c_header_matter_I7CGS);
    OUT = CodeGen::current(gen);
    WRITE("#include \"inform7_clib.h\"\n");
    CodeGen::deselect(gen, saved);

    CMemoryModel::begin(gen);
    CFunctionModel::begin(gen);
    CObjectModel::begin(gen);
    CLiteralsModel::begin(gen);
    CGlobals::begin(gen);
    CAssembly::begin(gen);
    CInputOutputModel::begin(gen);

    return FALSE;
}

int CTarget::end_generation(code_generation_target *cgt, code_generation *gen) {
    CMemoryModel::end(gen);
    CFunctionModel::end(gen);
    CObjectModel::end(gen);
    CLiteralsModel::end(gen);
    CGlobals::end(gen);
    CAssembly::end(gen);
    CInputOutputModel::end(gen);

    return FALSE;
}

int CTarget::general_segment(code_generation_target *cgt, code_generation *gen, inter_tree_node *P) {
    switch (P->W.data[ID_IFLD]) {
        case CONSTANT_IST: {
            inter_symbol *con_name =
                InterSymbolsTables::symbol_from_frame_data(P, DEFN_CONST_IFLD);
            int choice = c_early_matter_I7CGS;
            if (Str::eq(con_name->symbol_name, I"DynamicMemoryAllocation")) choice = c_very_early_matter_I7CGS;
            if (Inter::Symbols::read_annotation(con_name, LATE_IANN) == 1) choice = c_code_at_eof_I7CGS;
            if (Inter::Symbols::read_annotation(con_name, BUFFERARRAY_IANN) == 1) choice = c_arrays_at_eof_I7CGS;
            if (Inter::Symbols::read_annotation(con_name, BYTEARRAY_IANN) == 1) choice = c_arrays_at_eof_I7CGS;
            if (Inter::Symbols::read_annotation(con_name, TABLEARRAY_IANN) == 1) choice = c_arrays_at_eof_I7CGS;
            if (P->W.data[FORMAT_CONST_IFLD] == CONSTANT_INDIRECT_LIST) choice = c_arrays_at_eof_I7CGS;
            if (Inter::Symbols::read_annotation(con_name, VERBARRAY_IANN) == 1) choice = c_verbs_at_eof_I7CGS;
            if (Inter::Constant::is_routine(con_name)) choice = c_functions_at_eof_I7CGS;
            return choice;
        }
    }
    return CTarget::default_segment(cgt);
}

int CTarget::default_segment(code_generation_target *cgt) {
    return c_main_matter_I7CGS;
}
int CTarget::constant_segment(code_generation_target *cgt, code_generation *gen) {
    return c_early_matter_I7CGS;
}
int CTarget::basic_constant_segment(code_generation_target *cgt, code_generation *gen, int depth) {
    if (depth >= 10) depth = 10;
    return c_constants_1_I7CGS + depth - 1;
}
int CTarget::tl_segment(code_generation_target *cgt) {
    return c_text_literals_code_I7CGS;
}

§6.

void CTarget::new_action(code_generation_target *cgt, code_generation *gen, text_stream *name, int true_action) {
    generated_segment *saved = CodeGen::select(gen, c_predeclarations_I7CGS);
    text_stream *OUT = CodeGen::current(gen);
    WRITE("#define i7_ss_%S %d\n", name, C_GEN_DATA(C_action_count)++);
    CodeGen::deselect(gen, saved);
}

§7.

void i7_fatal_exit(void) {
    printf("*** Fatal error: halted ***\n");
    int x = 0; printf("%d", 1/x);
    exit(1);
}

#define i7_mgl_Grammar__Version 2
i7val i7_mgl_debug_flag = 0;
i7val i7_ss_classes_table = 0;
i7val i7_mgl_NUM_ATTR_BYTES = 0;
i7val i7_ss_cpv__start = 0;
i7val i7_ss_identifiers_table = 0;
i7val i7_ss_globals_array = 0;
i7val i7_ss_gself = 0;
i7val i7_ss_dict_par1 = 0;
i7val i7_ss_dict_par2 = 0;
i7val i7_ss_dictionary_table = 0;
i7val i7_ss_grammar_table = 0;

#define i7_mgl_FLOAT_NAN 0

i7val i7_tmp = 0;

i7val fn_i7_mgl_Z__Region(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_Z__Region.\n");
    return 0;
}

i7val fn_i7_mgl_CP__Tab(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_CP__Tab.\n");
    return 0;
}

i7val fn_i7_mgl_RA__Pr(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_RA__Pr.\n");
    return 0;
}

i7val fn_i7_mgl_RL__Pr(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_RL__Pr.\n");
    return 0;
}

i7val fn_i7_mgl_OC__Cl(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_OC__Cl.\n");
    return 0;
}

i7val fn_i7_mgl_RV__Pr(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_RV__Pr.\n");
    return 0;
}

i7val fn_i7_mgl_OP__Pr(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_OP__Pr.\n");
    return 0;
}

i7val fn_i7_mgl_CA__Pr(int argc, i7val x) {
    printf("Unimplemented: fn_i7_mgl_CA__Pr.\n");
    return 0;
}