To abstract non-standard, perhaps non-SVO, meanings of a verb.


§1. Special meaning functions. Regular meanings of verbs are represented by VERB_MEANING_LINGUISTICS_TYPE pointers — see Verb Meanings. In Inform, those are binary predicates. They always take two terms.

However, Inform sometimes wants sentences which are written in non-standard ways, with anything from one to three terms, and which don't correspond to any of the relations. (For example, "Include Locksmith by Emily Short".)

These are represented by functions to perform the necessary business; the type special_meaning_fn gives the type of such a function.

typedef int (*special_meaning_fn)(int, parse_node *, wording *);

§2. This is a convenient generic special-meaning function; it simply accumulates non-empty SPs and OPs as unparsed noun phrases and accepts them.

The first parameter is the task to be performed on the verb node pointed to by the second. The task number must belong to the *_SMFT enumeration, and the only task used by the Linguistics module is ACCEPT_SMFT. This should look at the array of wordings and either accept this as a valid usage, build a subtree from the verb node, and return TRUE, or else return FALSE to say that the usage is invalid: see Verb Phrases for more.

The user is then free to define further SMF tasks, and Inform does so.

enum ACCEPT_SMFT from 0
int SpecialMeanings::generic_smf(int task, parse_node *V, wording *NPs) {
    switch (task) {
        case ACCEPT_SMFT: {
            parse_node *A = V;
            for (int i=0; i<3; i++) {
                wording W = (NPs)?(NPs[i]):EMPTY_WORDING;
                if (Wordings::nonempty(W)) {
                    <np-unparsed>(W);
                    parse_node *p = <<rp>>;
                    A->next = p; A = p;
                }
            }
            return TRUE;
        }
    }
    return FALSE;
}

§3. Special meaning holders. Although a SM is basically encapsulated by a function, it's convenient to have some metadata with it too:

§4.

typedef struct special_meaning_holder {
    int (*sm_func)(int, parse_node *, wording *);  (compiler doesn't like typedef here)
    struct text_stream *sm_name;
    int metadata_N;
    CLASS_DEFINITION
} special_meaning_holder;

§5.

special_meaning_holder *SpecialMeanings::declare(special_meaning_fn func,
    text_stream *name, int p) {
    special_meaning_holder *smh = CREATE(special_meaning_holder);
    if (func == NULL) func = SpecialMeanings::generic_smf;
    smh->sm_func = func;
    smh->sm_name = Str::duplicate(name);
    smh->metadata_N = p;
    return smh;
}

§6. SMHs can be found by name:

special_meaning_holder *SpecialMeanings::find_from_wording(wording W) {
    TEMPORARY_TEXT(name)
    WRITE_TO(name, "%W", W);
    special_meaning_holder *smh;
    LOOP_OVER(smh, special_meaning_holder)
        if (Str::eq_insensitive(smh->sm_name, name))
            break;
    DISCARD_TEXT(name)
    return smh;
}

§7. Metadata access:

int SpecialMeanings::get_metadata_N(special_meaning_holder *smh) {
    if (smh == NULL) return 0;
    return smh->metadata_N;
}

text_stream *SpecialMeanings::get_name(special_meaning_holder *smh) {
    if (smh == NULL) return NULL;
    return smh->sm_name;
}

int SpecialMeanings::is(special_meaning_holder *smh, special_meaning_fn func) {
    if (smh == NULL) return FALSE;
    if (smh->sm_func == func) return TRUE;
    return FALSE;
}

§8. Calling:

int SpecialMeanings::call(special_meaning_holder *smh, int task, parse_node *V,
    wording *NPs) {
    if ((smh == NULL) || (smh->sm_func == NULL)) return FALSE;
    return (*(smh->sm_func))(task, V, NPs);
}