1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-08 18:14:21 +03:00
inform7/services/linguistics-module/Chapter 2/Adjectives.w

154 lines
4.7 KiB
OpenEdge ABL
Raw Normal View History

2019-02-05 02:44:07 +02:00
[Adjectives::] Adjectives.
To record the names of all adjectives.
@h Adjectives are not their meanings.
Adjectives are simpler than verbs, since they define unary rather than
binary predicates. The word "open" applies to only one term -- logically, we
regard it as |open(x)|, whereas a verb like "suspects" would appear
in formulae as |suspects(x, y)|.
But they are nevertheless complicated enough to have multiple meanings. For
instance, two of the senses of "empty" in the Standard Rules are:
>> Definition: a text is empty rather than non-empty if it is "".
>> Definition: a table name is empty rather than non-empty if the number of filled rows in it is 0.
(Which also defines two of the senses of "non-empty", another adjective.)
The clause |empty(x)| can be fully understood only when we know what
kind of value x has; for a text, the first sense applies, and for a table
name, the second.
Adjectives may also need to inflect, though not in English. (Let's not argue
about the word "blond"/"blonde", which is the only counterexample anybody
ever brings up.)
@h Adjectival phrases.
Because of this we need a structure to represent an adjective as
distinct from its meaning, and this is it.
@default ADJECTIVE_MEANING_LINGUISTICS_TYPE void
2019-02-05 02:44:07 +02:00
=
typedef struct adjectival_phrase {
struct name_cluster *adjective_names;
#ifdef CORE_MODULE
struct inter_name *aph_iname;
struct package_request *aph_package;
#endif
ADJECTIVE_MEANING_LINGUISTICS_TYPE *meanings;
2020-05-09 15:07:39 +03:00
CLASS_DEFINITION
2019-02-05 02:44:07 +02:00
} adjectival_phrase;
@ The following declares a new adjective, creating it only if necessary:
=
2020-05-13 01:33:17 +03:00
adjectival_phrase *Adjectives::declare(wording W, NATURAL_LANGUAGE_WORDS_TYPE *nl) {
2019-02-05 02:44:07 +02:00
adjectival_phrase *aph;
LOOP_OVER(aph, adjectival_phrase) {
wording C = Clusters::get_name_in_play(aph->adjective_names, FALSE, nl);
if (Wordings::match(C, W)) return aph;
}
return Adjectives::from_word_range(W, nl);
}
@ Whereas this simply creates it:
=
2020-05-13 01:33:17 +03:00
adjectival_phrase *Adjectives::from_word_range(wording W, NATURAL_LANGUAGE_WORDS_TYPE *nl) {
2019-02-05 02:44:07 +02:00
adjectival_phrase *aph = NULL;
if (Wordings::nonempty(W)) aph = Adjectives::parse(W);
if (aph) return aph;
aph = CREATE(adjectival_phrase);
aph->adjective_names = Clusters::new();
Clusters::add_with_agreements(aph->adjective_names, W, nl);
aph->meanings = NULL;
#ifdef EMPTY_ADJECTIVE_MEANING_LINGUISTICS_CALLBACK
aph->meanings = EMPTY_ADJECTIVE_MEANING_LINGUISTICS_CALLBACK();
2019-02-05 02:44:07 +02:00
#endif
#ifdef CORE_MODULE
2019-04-13 16:41:56 +03:00
aph->aph_package = Hierarchy::package(Modules::current(), ADJECTIVES_HAP);
aph->aph_iname = Hierarchy::make_iname_in(ADJECTIVE_HL, aph->aph_package);
2019-02-05 02:44:07 +02:00
#endif
if ((nl == NULL) && (Wordings::nonempty(W))) {
#ifdef ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK
if (ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK(W)) {
2019-02-05 02:44:07 +02:00
#endif
2020-05-30 16:33:19 +03:00
Lexicon::register(ADJECTIVE_MC,
2019-02-05 02:44:07 +02:00
W, STORE_POINTER_adjectival_phrase(aph));
LOOP_THROUGH_WORDING(n, W)
2020-05-19 13:46:13 +03:00
NTI::mark_word(n, <adjective-name>);
#ifdef ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK
2019-02-05 02:44:07 +02:00
}
#endif
}
return aph;
}
@ =
wording Adjectives::get_text(adjectival_phrase *aph, int plural) {
return Clusters::get_name(aph->adjective_names, plural);
}
@h Parsing adjectives.
This does what its name suggests: matches the name of any adjective known to
Inform.
=
<adjective-name> internal {
2020-05-30 16:33:19 +03:00
parse_node *p = Lexicon::retrieve(ADJECTIVE_MC, W);
2019-02-05 02:44:07 +02:00
if (p) {
*XP = RETRIEVE_POINTER_adjectival_phrase(
2020-05-30 16:33:19 +03:00
Lexicon::get_data(Node::get_meaning(p)));
2019-02-05 02:44:07 +02:00
return TRUE;
}
return FALSE;
}
@ These are registered as excerpt meanings with the |ADJECTIVE_MC| meaning
code, so parsing a word range to match an adjective is easy. By construction
there is only one |adjectival_phrase| for any given excerpt of text, so
the following is unambiguous:
=
adjectival_phrase *Adjectives::parse(wording W) {
if (<adjective-name>(W)) return <<rp>>;
return NULL;
}
@h Testing agreement.
=
void Adjectives::test_adjective(OUTPUT_STREAM, wording W) {
adjectival_phrase *aph = Adjectives::declare(W, NULL);
if (aph == NULL) { WRITE("Failed test\n"); return; }
int g, n;
for (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 (n = 1; n <= 2; n++) {
if (n == 1) WRITE("singular: "); else WRITE(" / plural: ");
wording C = Clusters::get_name_general(aph->adjective_names,
NULL, n, g);
WRITE("%W", C);
}
WRITE("^");
}
}
@h Logging.
To identify an adjective in the debugging log:
=
void Adjectives::log(adjectival_phrase *aph) {
if (aph == NULL) { LOG("<null adjectival phrase>"); return; }
wording W = Adjectives::get_text(aph, FALSE);
if (Streams::I6_escapes_enabled(DL)) LOG("'%W'", W);
else LOG("A%d'%W'", aph->allocation_id, W);
}