To permit variables to have scopes intermediate between local and global: for example, to be shared by all rules in a given rulebook.


§1. Definitions.

    typedef struct stacked_variable {
        struct wording name;     text of the name
        struct parse_node *assigned_at;     sentence assigning it
        struct nonlocal_variable *underlying_var;     the variable in question
        int owner_id;     who owns this
        int offset_in_owning_frame;     word offset of storage (counts from 0)
        struct wording match_wording_text;     matching text (relevant for action variables only)
        MEMORY_MANAGEMENT
    } stacked_variable;

    typedef struct stacked_variable_list {
        struct stacked_variable *the_stv;     the STV
        struct stacked_variable_list *next;     in linked list
        MEMORY_MANAGEMENT
    } stacked_variable_list;

    typedef struct stacked_variable_owner {
        int no_stvs;
        int recognition_id;
        struct stacked_variable_list *list_of_stvs;
        struct inter_name *stvo_iname;
        MEMORY_MANAGEMENT
    } stacked_variable_owner;

    typedef struct stacked_variable_owner_list {
        struct stacked_variable_owner *stvo;     the STO
        struct stacked_variable_owner_list *next;     in linked list
        MEMORY_MANAGEMENT
    } stacked_variable_owner_list;

The structure stacked_variable is accessed in 2/sq, 2/si, 5/ins, 5/nv, 8/ef, 9/ma, 9/pk, 11/sm, 14/lv, 14/ds2, 15/pr, 15/ep, 15/vp, 15/spr, 16/in, 16/cmw, 17/rs, 19/tc, 19/tb, 19/tod, 20/eq, 21/rl, 21/rl2, 21/fao, 21/rps, 21/ac, 22/pu, 22/dptd, 22/po, 22/pav, 25/cii, 26/uo, 26/ts and here.

The structure stacked_variable_list is accessed in 3/pd, 5/lp, 5/ut, 5/un, 5/ins, 6/rlt, 6/nv, 7/ns, 7/oaf, 7/rs, 9/tfa, 9/tbath, 9/rpt, 9/tc, 9/ma, 9/rk, 9/ass, 9/imp, 9/pd, 10/teav, 10/cap, 11/ap, 11/pr, 11/bas, 11/tc, 11/sm, 12/dtd, 12/cdp, 14/rv, 14/lv, 14/cn, 14/ds, 14/ds2, 15/cp, 16/is, 16/in, 19/tb, 19/rsft, 19/tod, 20/eq, 21/rl, 21/rl2, 21/fao, 21/rps, 21/ac, 22/ph, 22/tp, 22/tp2, 23/ad, 24/lv, 24/sf, 25/in, 25/pi, 25/cii, 25/cp, 26/uo, 26/tti, 26/pc, 26/ts, 27/cm and here.

The structure stacked_variable_owner is private to this section.

The structure stacked_variable_owner_list is accessed in 3/pd, 5/lp, 5/ut, 5/un, 5/ins, 6/rlt, 6/nv, 7/ns, 7/oaf, 7/rs, 9/tfa, 9/tbath, 9/rpt, 9/tc, 9/ma, 9/rk, 9/ass, 9/imp, 9/pd, 10/teav, 10/cap, 11/ap, 11/pr, 11/bas, 11/tc, 11/sm, 12/dtd, 12/cdp, 14/rv, 14/lv, 14/cn, 14/ds, 14/ds2, 15/cp, 16/is, 16/in, 19/tb, 19/rsft, 19/tod, 20/eq, 21/rl, 21/rl2, 21/fao, 21/rps, 21/ac, 22/ph, 22/tp, 22/tp2, 23/ad, 24/lv, 24/sf, 25/in, 25/pi, 25/cii, 25/cp, 26/uo, 26/tti, 26/pc, 26/ts, 27/cm and here.

§2.

    int max_frame_size_needed = 0;

§3.

    nonlocal_variable_emission StackedVariables::how_to_lvalue(stacked_variable *stv) {
        if ((stv->owner_id == ACTION_PROCESSING_RB) && (stv->offset_in_owning_frame == 0))
            return NonlocalVariables::nve_from_iname(Hierarchy::find(ACTOR_HL));
        else
            return NonlocalVariables::nve_from_mstack(stv->owner_id, stv->offset_in_owning_frame, FALSE);
    }

    nonlocal_variable_emission StackedVariables::how_to_rvalue(stacked_variable *stv) {
        if ((stv->owner_id == ACTION_PROCESSING_RB) && (stv->offset_in_owning_frame == 0))
            return NonlocalVariables::nve_from_iname(Hierarchy::find(ACTOR_HL));
        else
            return NonlocalVariables::nve_from_mstack(stv->owner_id, stv->offset_in_owning_frame, TRUE);
    }

    int StackedVariables::get_owner_id(stacked_variable *stv) {
        return stv->owner_id;
    }

    int StackedVariables::get_offset(stacked_variable *stv) {
        return stv->offset_in_owning_frame;
    }

    kind *StackedVariables::get_kind(stacked_variable *stv) {
        nonlocal_variable *nlv = StackedVariables::get_variable(stv);
        return NonlocalVariables::kind(nlv);
    }

    nonlocal_variable *StackedVariables::get_variable(stacked_variable *stv) {
        if (stv == NULL) return NULL;
        return stv->underlying_var;
    }

    void StackedVariables::set_matching_text(stacked_variable *stv, wording W) {
        stv->match_wording_text = W;
    }

    wording StackedVariables::get_matching_text(stacked_variable *stv) {
        return stv->match_wording_text;
    }

    stacked_variable *StackedVariables::parse_match_clause(stacked_variable_owner *stvo,
        wording W) {
        for (stacked_variable_list *stvl = stvo->list_of_stvs; stvl; stvl = stvl->next)
            if (Wordings::starts_with(W, stvl->the_stv->match_wording_text))
                return stvl->the_stv;
        return NULL;
    }

    stacked_variable_owner *StackedVariables::new_owner(int id) {
        stacked_variable_owner *stvo = CREATE(stacked_variable_owner);
        stvo->recognition_id = id;
        stvo->no_stvs = 0;
        stvo->list_of_stvs = NULL;
        stvo->stvo_iname = NULL;
        return stvo;
    }

    int StackedVariables::owner_empty(stacked_variable_owner *stvo) {
        if (stvo->no_stvs == 0) return TRUE;
        return FALSE;
    }

    stacked_variable *StackedVariables::add_empty(stacked_variable_owner *stvo,
        wording W, kind *K) {
        stacked_variable *stv = CREATE(stacked_variable);
        nonlocal_variable *q;
        W = Articles::remove_the(W);
        stv->name = W;
        stv->owner_id = stvo->recognition_id;
        stv->offset_in_owning_frame = stvo->no_stvs++;
        stv->assigned_at = current_sentence;
        stv->match_wording_text = EMPTY_WORDING;
        stvo->list_of_stvs = StackedVariables::add_to_list(stvo->list_of_stvs, stv);
        if (stvo->no_stvs > max_frame_size_needed)
            max_frame_size_needed = stvo->no_stvs;
        q = NonlocalVariables::new_stacked(W, K, stv);
        stv->underlying_var = q;
        NonlocalVariables::set_I6_identifier(q, FALSE, StackedVariables::how_to_rvalue(stv));
        NonlocalVariables::set_I6_identifier(q, TRUE, StackedVariables::how_to_lvalue(stv));
        return stv;
    }

    stacked_variable_owner_list *StackedVariables::add_owner_to_list(stacked_variable_owner_list *stvol,
        stacked_variable_owner *stvo) {
        stacked_variable_owner_list *ostvol = stvol;

        while (stvol) {
            if (stvol->stvo == stvo) return ostvol;
            stacked_variable_owner_list *nxt = stvol->next;
            if (nxt == NULL) break;
            stvol = nxt;
        }

        stacked_variable_owner_list *nstvol = CREATE(stacked_variable_owner_list);
        nstvol->next = NULL;
        nstvol->stvo = stvo;
        if (stvol == NULL) return nstvol;
        stvol->next = nstvol;
        return ostvol;
    }

    stacked_variable_owner_list *StackedVariables::append_owner_list(stacked_variable_owner_list *stvol,
        stacked_variable_owner_list *extras) {
        LOGIF(RULEBOOK_COMPILATION,
            "Appending list %08x to list %08x\n", (int) extras, (int) stvol);
        stacked_variable_owner_list *new_head = stvol;
        for (; extras; extras = extras->next)
            new_head = StackedVariables::add_owner_to_list(new_head, extras->stvo);
        return new_head;
    }

    int StackedVariables::list_length(stacked_variable_list *stvl) {
        int l = 0;
        while (stvl) {
            l++;
            stvl = stvl->next;
        }
        return l;
    }

    void StackedVariables::index_owner(OUTPUT_STREAM, stacked_variable_owner *stvo) {
        stacked_variable_list *stvl;
        for (stvl=stvo->list_of_stvs; stvl; stvl = stvl->next)
            if ((stvl->the_stv) && (stvl->the_stv->underlying_var)) {
                HTMLFiles::open_para(OUT, 2, "tight");
                NonlocalVariables::index_single(OUT, stvl->the_stv->underlying_var);
                HTML_CLOSE("p");
            }
    }

    stacked_variable *StackedVariables::parse_from_owner_list(stacked_variable_owner_list *stvol, wording W) {
        if (Wordings::empty(W)) return NULL;
        W = Articles::remove_the(W);
        while (stvol) {
            stacked_variable *stv = NULL;
            if (stvol->stvo) stv = StackedVariables::parse_from_list(stvol->stvo->list_of_stvs, W);
            if (stv) return stv;
            stvol = stvol->next;
        }
        return NULL;
    }

    stacked_variable *StackedVariables::parse_from_list(stacked_variable_list *stvl, wording W) {
        while (stvl) {
            if (Wordings::match(stvl->the_stv->name, W))
                return stvl->the_stv;
            stvl = stvl->next;
        }
        return NULL;
    }

    stacked_variable_list *StackedVariables::add_to_list(stacked_variable_list *stvl,
        stacked_variable *stv) {
        stacked_variable_list *nstvl = CREATE(stacked_variable_list), *ostvl = stvl;
        nstvl->the_stv = stv;
        nstvl->next = NULL;
        if (stvl == NULL) return nstvl;
        while (stvl->next) stvl = stvl->next;
        stvl->next = nstvl;
        return ostvl;
    }

    int StackedVariables::compile_frame_creator(stacked_variable_owner *stvo, inter_name *iname) {
        if (stvo == NULL) return 0;

        packaging_state save = Routines::begin(iname);
        inter_symbol *pos_s = LocalVariables::add_named_call_as_symbol(I"pos");
        inter_symbol *state_s = LocalVariables::add_named_call_as_symbol(I"state");

        Produce::inv_primitive(Emit::tree(), IFELSE_BIP);
        Produce::down(Emit::tree());
            Produce::inv_primitive(Emit::tree(), EQ_BIP);
            Produce::down(Emit::tree());
                Produce::val_symbol(Emit::tree(), K_value, state_s);
                Produce::val(Emit::tree(), K_number, LITERAL_IVAL, 1);
            Produce::up(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                <Compile frame creator if state is set 3.1>;
            Produce::up(Emit::tree());
            Produce::code(Emit::tree());
            Produce::down(Emit::tree());
                <Compile frame creator if state is clear 3.2>;
            Produce::up(Emit::tree());
        Produce::up(Emit::tree());

        int count = 0;
        for (stacked_variable_list *stvl = stvo->list_of_stvs; stvl; stvl = stvl->next) count++;

        Produce::inv_primitive(Emit::tree(), RETURN_BIP);
        Produce::down(Emit::tree());
            Produce::val(Emit::tree(), K_number, LITERAL_IVAL, (inter_t) count);
        Produce::up(Emit::tree());

        Routines::end(save);
        stvo->stvo_iname = iname;
        return count;
    }

The function StackedVariables::how_to_lvalue appears nowhere else.

The function StackedVariables::how_to_rvalue appears nowhere else.

The function StackedVariables::get_owner_id appears nowhere else.

The function StackedVariables::get_offset appears nowhere else.

The function StackedVariables::get_kind appears nowhere else.

The function StackedVariables::get_variable is used in §3.1, §3.2, 10/teav (§16).

The function StackedVariables::set_matching_text appears nowhere else.

The function StackedVariables::get_matching_text appears nowhere else.

The function StackedVariables::parse_match_clause appears nowhere else.

The function StackedVariables::new_owner is used in 21/rl2 (§10), 21/ac (§6).

The function StackedVariables::owner_empty is used in 21/rl2 (§14, §14.1), 21/ac (§8).

The function StackedVariables::add_empty is used in 21/rl2 (§14), 21/ac (§8).

The function StackedVariables::add_owner_to_list is used in 21/rl2 (§10, §14).

The function StackedVariables::append_owner_list is used in 21/rl (§16).

The function StackedVariables::list_length appears nowhere else.

The function StackedVariables::index_owner appears nowhere else.

The function StackedVariables::parse_from_owner_list is used in 10/teav (§16).

The function StackedVariables::parse_from_list appears nowhere else.

The function StackedVariables::add_to_list appears nowhere else.

The function StackedVariables::compile_frame_creator is used in 21/rl2 (§14), 21/ac (§8).

§3.1. <Compile frame creator if state is set 3.1> =

        for (stacked_variable_list *stvl = stvo->list_of_stvs; stvl; stvl = stvl->next) {
            nonlocal_variable *q = StackedVariables::get_variable(stvl->the_stv);
            kind *K = NonlocalVariables::kind(q);
            Produce::inv_primitive(Emit::tree(), STORE_BIP);
            Produce::down(Emit::tree());
                Produce::inv_primitive(Emit::tree(), LOOKUPREF_BIP);
                Produce::down(Emit::tree());
                    Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(MSTACK_HL));
                    Produce::val_symbol(Emit::tree(), K_value, pos_s);
                Produce::up(Emit::tree());
                if (Kinds::Behaviour::uses_pointer_values(K))
                    Kinds::RunTime::emit_heap_allocation(Kinds::RunTime::make_heap_allocation(K, 1, -1));
                else
                    NonlocalVariables::emit_initial_value_as_val(q);
            Produce::up(Emit::tree());

            Produce::inv_primitive(Emit::tree(), POSTINCREMENT_BIP);
            Produce::down(Emit::tree());
                Produce::ref_symbol(Emit::tree(), K_value, pos_s);
            Produce::up(Emit::tree());
        }

This code is used in §3.

§3.2. <Compile frame creator if state is clear 3.2> =

        for (stacked_variable_list *stvl = stvo->list_of_stvs; stvl; stvl = stvl->next) {
            nonlocal_variable *q = StackedVariables::get_variable(stvl->the_stv);
            kind *K = NonlocalVariables::kind(q);
            if (Kinds::Behaviour::uses_pointer_values(K)) {
                Produce::inv_call_iname(Emit::tree(), Hierarchy::find(BLKVALUEFREE_HL));
                Produce::down(Emit::tree());
                    Produce::inv_primitive(Emit::tree(), LOOKUP_BIP);
                    Produce::down(Emit::tree());
                        Produce::val_iname(Emit::tree(), K_value, Hierarchy::find(MSTACK_HL));
                        Produce::val_symbol(Emit::tree(), K_value, pos_s);
                    Produce::up(Emit::tree());
                Produce::up(Emit::tree());
            }
            Produce::inv_primitive(Emit::tree(), POSTINCREMENT_BIP);
            Produce::down(Emit::tree());
                Produce::ref_symbol(Emit::tree(), K_value, pos_s);
            Produce::up(Emit::tree());
        }

This code is used in §3.

§4.

    inter_name *StackedVariables::frame_creator(stacked_variable_owner *stvo) {
        return stvo->stvo_iname;
    }

The function StackedVariables::frame_creator is used in 21/rl2 (§14), 21/ac (§8).