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.
|
|
|
|
|
2020-05-26 01:46:01 +03:00
|
|
|
@default ADJECTIVE_MEANING_LINGUISTICS_TYPE void
|
2020-03-28 21:42:53 +02:00
|
|
|
|
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
|
2020-05-26 01:46:01 +03:00
|
|
|
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;
|
2020-05-26 01:46:01 +03:00
|
|
|
#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);
|
2019-04-14 13:46:13 +03:00
|
|
|
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))) {
|
2020-05-26 01:46:01 +03:00
|
|
|
#ifdef ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK
|
|
|
|
if (ADJECTIVE_NAME_VETTING_LINGUISTICS_CALLBACK(W)) {
|
2019-02-05 02:44:07 +02:00
|
|
|
#endif
|
|
|
|
ExcerptMeanings::register(ADJECTIVE_MC,
|
|
|
|
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>);
|
2020-05-26 01:46:01 +03:00
|
|
|
#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 {
|
|
|
|
parse_node *p = ExParser::parse_excerpt(ADJECTIVE_MC, W);
|
|
|
|
if (p) {
|
|
|
|
*XP = RETRIEVE_POINTER_adjectival_phrase(
|
2020-05-11 17:21:29 +03:00
|
|
|
ExcerptMeanings::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);
|
|
|
|
}
|
|
|
|
|