1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-29 05:24:57 +03:00
inform7/services/linguistics-module/Chapter 2/Adjectives.w
2021-06-12 13:08:47 +01:00

162 lines
5.1 KiB
OpenEdge ABL

[Adjectives::] Adjectives.
To create adjective objects, each of which represents a single adjective
which may have multiple inflected forms and meanings.
@h An adjective is only a lexical cluster.
We represent adjectives like "empty" with //adjective// objects. The only
linguistic data in these objects is the lexical cluster for its wordings,
possibly in multiple languages. These allow adjectives to have inflected
forms, though this never really arises in English. (Let's not argue about
the word "blond"/"blonde", the only counterexample anybody ever brings up.)
Beyond that, an //adjective// object simply contains two convenient hooks
for the user of this module to attach semantics to an adjective. For how
Inform does this, see //assertions: Adjective Meanings//.
=
typedef struct adjective {
struct lexical_cluster *adjective_names;
struct linguistic_stock_item *in_stock;
#ifdef ADJECTIVE_COMPILATION_LINGUISTICS_CALLBACK
struct adjective_compilation_data adjective_compilation;
#endif
#ifdef ADJECTIVE_MEANING_LINGUISTICS_CALLBACK
struct adjective_meaning_data adjective_meanings;
#endif
CLASS_DEFINITION
} adjective;
@ Adjectives are a grammatical category:
=
grammatical_category *adjectives_category = NULL;
void Adjectives::create_category(void) {
adjectives_category = Stock::new_category(I"adjective");
METHOD_ADD(adjectives_category, LOG_GRAMMATICAL_CATEGORY_MTID, Adjectives::log_item);
}
void Adjectives::log_item(grammatical_category *cat, general_pointer data) {
adjective *adj = RETRIEVE_POINTER_adjective(data);
Adjectives::log(adj);
}
adjective *Adjectives::from_lcon(lcon_ti lcon) {
linguistic_stock_item *item = Stock::from_lcon(lcon);
if (item == NULL) return NULL;
return RETRIEVE_POINTER_adjective(item->data);
}
@h Creation.
The following declares a new adjective, creating it only if it does not
already exist.
=
adjective *Adjectives::declare(wording W, NATURAL_LANGUAGE_WORDS_TYPE *nl) {
adjective *adj;
LOOP_OVER(adj, adjective) {
wording C = Clusters::get_form_in_language(adj->adjective_names, FALSE, nl);
if (Wordings::match(C, W)) return adj;
}
adj = NULL;
if (Wordings::nonempty(W)) adj = Adjectives::parse(W);
if (adj) return adj;
adj = CREATE(adjective);
adj->adjective_names = Clusters::new();
Clusters::add_with_agreements(adj->adjective_names, W, nl);
#ifdef ADJECTIVE_MEANING_LINGUISTICS_CALLBACK
ADJECTIVE_MEANING_LINGUISTICS_CALLBACK(adj);
#endif
#ifdef ADJECTIVE_COMPILATION_LINGUISTICS_CALLBACK
ADJECTIVE_COMPILATION_LINGUISTICS_CALLBACK(adj, W);
#endif
@<Register the new adjective with the lexicon module@>;
adj->in_stock = Stock::new(adjectives_category, STORE_POINTER_adjective(adj));
return adj;
}
@ It's very important for performance that parsing adjective names can be
done quickly, so we use the lexicon's optimisation code to mark all words
occurring in any known adjective. Whereas nouns are registered with the
lexicon under any number of different meaning codes, adjectives are always
registered under |ADJECTIVE_MC|.
@<Register the new adjective with the lexicon module@> =
if ((nl == NULL) && (Wordings::nonempty(W))) {
#ifdef ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK
if (ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK(W)) {
#endif
Lexicon::register(ADJECTIVE_MC, W, STORE_POINTER_adjective(adj));
LOOP_THROUGH_WORDING(n, W) NTI::mark_word(n, <adjective-name>);
#ifdef ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK
}
#endif
}
@ =
wording Adjectives::get_nominative_singular(adjective *adj) {
return Clusters::get_form(adj->adjective_names, FALSE);
}
@h Parsing adjectives.
This does what its name suggests: matches the name of any adjective known to
Inform. By construction there is only one |adjective| for any given excerpt of
text, so the following is unambiguous:
=
<adjective-name> internal {
parse_node *p = Lexicon::retrieve(ADJECTIVE_MC, W);
if (p) {
adjective *adj = RETRIEVE_POINTER_adjective(Lexicon::get_data(Node::get_meaning(p)));
==> {-, adj};
return TRUE;
}
==> { fail nonterminal };
}
@ Wrapping which:
=
adjective *Adjectives::parse(wording W) {
if (<adjective-name>(W)) return <<rp>>;
return NULL;
}
@h Testing agreement.
This is used in unit testing.
=
void Adjectives::test_adjective(OUTPUT_STREAM, wording W) {
adjective *adj = Adjectives::declare(W, NULL);
if (adj == NULL) { WRITE("Failed test\n"); return; }
for (int g = NEUTER_GENDER; g <= FEMININE_GENDER; g++) {
switch (g) {
case NEUTER_GENDER: WRITE("neuter "); break;
case MASCULINE_GENDER: WRITE("masculine "); break;
case FEMININE_GENDER: WRITE("feminine "); break;
}
for (int n = 1; n <= 2; n++) {
if (n == 1) WRITE("singular: "); else WRITE(" / plural: ");
wording C = Clusters::get_form_general(adj->adjective_names,
NULL, n, g);
WRITE("%W", C);
}
WRITE("^");
}
}
@h Logging.
To identify an adjective in the debugging log:
=
void Adjectives::log(adjective *adj) {
Adjectives::write(DL, adj);
}
void Adjectives::write(OUTPUT_STREAM, adjective *adj) {
if (adj == NULL) { WRITE("<null adjectival phrase>"); return; }
wording W = Adjectives::get_nominative_singular(adj);
WRITE("'%W'", W);
}