+ + +

Pattern-matches on individual nouns in an action are called clauses.

+ +

§1.

+ +
enum ACTOR_AP_CLAUSE from 1
+enum NOUN_AP_CLAUSE
+enum SECOND_AP_CLAUSE
+enum IN_AP_CLAUSE
+enum IN_THE_PRESENCE_OF_AP_CLAUSE
+enum WHEN_AP_CLAUSE
+enum GOING_FROM_AP_CLAUSE
+enum GOING_TO_AP_CLAUSE
+enum GOING_BY_AP_CLAUSE
+enum GOING_THROUGH_AP_CLAUSE
+enum PUSHING_AP_CLAUSE
+enum STV_AP_CLAUSE
+
+
+typedef struct ap_clause {
+    int clause_ID;
+    struct stacked_variable *stv_to_match;
+    struct parse_node *clause_spec;
+    int clause_options;
+    struct ap_clause *next;
+    CLASS_DEFINITION
+} ap_clause;
+
+ +

§2. The clause options are a bitmap. Some are meaningful only for one or two +clauses. +

+ +
define ALLOW_REGION_AS_ROOM_APCOPT 1
+define DO_NOT_VALIDATE_APCOPT 2
+
+

§3.

+ +
+int APClauses::opt(ap_clause *apoc, int opt) {
+    return (((apoc) && (apoc->clause_options)) & opt)?TRUE:FALSE;
+}
+
+void APClauses::set_opt(ap_clause *apoc, int opt) {
+    if (apoc == NULL) internal_error("no such apoc");
+    apoc->clause_options |= opt;
+}
+
+void APClauses::clear_opt(ap_clause *apoc, int opt) {
+    if (apoc == NULL) internal_error("no such apoc");
+    if (apoc->clause_options & opt) apoc->clause_options -= opt;
+}
+
+parse_node *APClauses::get_actor(action_pattern *ap) {
+    return APClauses::get_val(ap, ACTOR_AP_CLAUSE);
+}
+
+void APClauses::set_actor(action_pattern *ap, parse_node *val) {
+    APClauses::set_val(ap, ACTOR_AP_CLAUSE, val);
+}
+
+parse_node *APClauses::get_noun(action_pattern *ap) {
+    return APClauses::get_val(ap, NOUN_AP_CLAUSE);
+}
+
+void APClauses::set_noun(action_pattern *ap, parse_node *val) {
+    APClauses::set_val(ap, NOUN_AP_CLAUSE, val);
+}
+
+parse_node *APClauses::get_second(action_pattern *ap) {
+    return APClauses::get_val(ap, SECOND_AP_CLAUSE);
+}
+
+void APClauses::set_second(action_pattern *ap, parse_node *val) {
+    APClauses::set_val(ap, SECOND_AP_CLAUSE, val);
+}
+
+parse_node *APClauses::get_presence(action_pattern *ap) {
+    return APClauses::get_val(ap, IN_THE_PRESENCE_OF_AP_CLAUSE);
+}
+
+void APClauses::set_presence(action_pattern *ap, parse_node *val) {
+    APClauses::set_val(ap, IN_THE_PRESENCE_OF_AP_CLAUSE, val);
+}
+
+parse_node *APClauses::get_room(action_pattern *ap) {
+    return APClauses::get_val(ap, IN_AP_CLAUSE);
+}
+
+void APClauses::set_room(action_pattern *ap, parse_node *val) {
+    APClauses::set_val(ap, IN_AP_CLAUSE, val);
+}
+
+parse_node *APClauses::get_val(action_pattern *ap, int C) {
+    ap_clause *apoc = APClauses::clause(ap, C);
+    return (apoc)?(apoc->clause_spec):NULL;
+}
+
+void APClauses::set_val(action_pattern *ap, int C, parse_node *val) {
+    if (val == NULL) {
+        ap_clause *apoc = APClauses::clause(ap, C);
+        if (apoc) apoc->clause_spec = val;
+    } else {
+        ap_clause *apoc = APClauses::ensure_clause(ap, C);
+        apoc->clause_spec = val;
+    }
+}
+
+void APClauses::nullify_nonspecific(action_pattern *ap, int C) {
+    ap_clause *apoc = APClauses::clause(ap, C);
+    if (apoc) apoc->clause_spec = ActionPatterns::nullify_nonspecific_references(apoc->clause_spec);
+}
+
+ap_clause *APClauses::clause(action_pattern *ap, int C) {
+    return APClauses::find_clause(ap, C, FALSE);
+}
+
+ap_clause *APClauses::ensure_clause(action_pattern *ap, int C) {
+    return APClauses::find_clause(ap, C, TRUE);
+}
+
+ap_clause *APClauses::find_clause(action_pattern *ap, int clause, int make) {
+    if (ap) {
+        ap_clause *last = NULL;
+        for (ap_clause *apoc = ap->ap_clauses; apoc; apoc = apoc->next) {
+            if (apoc->clause_ID == clause)
+                return apoc;
+            last = apoc;
+        }
+        if (make) {
+            ap_clause *new_apoc = APClauses::apoc_new(clause, NULL, NULL);
+            if (last == NULL) ap->ap_clauses = new_apoc;
+            else last->next = new_apoc;
+            return new_apoc;
+        }
+    } else {
+        if (make) internal_error("cannot make clause in null AP");
+    }
+    return NULL;
+}
+
+ap_clause *APClauses::find_stv(action_pattern *ap, stacked_variable *stv) {
+    if (ap)
+        for (ap_clause *apoc = ap->ap_clauses; apoc; apoc = apoc->next)
+            if (apoc->stv_to_match == stv)
+                return apoc;
+    return NULL;
+}
+
+ap_clause *APClauses::apoc_new(int clause, stacked_variable *stv, parse_node *spec) {
+    ap_clause *apoc = CREATE(ap_clause);
+    apoc->clause_ID = clause;
+    apoc->stv_to_match = stv;
+    apoc->clause_spec = spec;
+    apoc->next = NULL;
+    apoc->clause_options = FALSE;
+    return apoc;
+}
+
+void APClauses::ap_add_optional_clause(action_pattern *ap, stacked_variable *stv,
+    wording W) {
+    if (stv == NULL) internal_error("no stacked variable for apoc");
+    ap_clause *apoc = APClauses::apoc_new(STV_AP_CLAUSE, stv,
+        ParseActionPatterns::verified_action_parameter(W));
+    int oid = StackedVariables::get_owner_id(apoc->stv_to_match);
+    int off = StackedVariables::get_offset(apoc->stv_to_match);
+    if (ap->ap_clauses == NULL) {
+        ap->ap_clauses = apoc;
+        apoc->next = NULL;
+    } else {
+        ap_clause *oapoc = ap->ap_clauses, *papoc = NULL;
+        while (oapoc) {
+            if (oapoc->stv_to_match) {
+                int ooff = StackedVariables::get_offset(oapoc->stv_to_match);
+                if (off < ooff) {
+                    if (oapoc == ap->ap_clauses) {
+                        apoc->next = ap->ap_clauses;
+                        ap->ap_clauses = apoc;
+                        papoc = NULL;
+                    } else {
+                        apoc->next = papoc->next;
+                        papoc->next = apoc;
+                        papoc = NULL;
+                    }
+                    break;
+                }
+            }
+            papoc = oapoc;
+            oapoc = oapoc->next;
+        }
+        if (papoc) {
+            apoc->next = NULL;
+            papoc->next = apoc;
+        }
+    }
+
+    if (oid == 20007 /* i.e., going */ ) {
+        switch (off) {
+            case 0: ap->from_spec = apoc->clause_spec;
+                APClauses::set_opt(apoc, ALLOW_REGION_AS_ROOM_APCOPT); break;
+            case 1: ap->to_spec = apoc->clause_spec;
+                APClauses::set_opt(apoc, ALLOW_REGION_AS_ROOM_APCOPT); break;
+            case 2: ap->through_spec = apoc->clause_spec; break;
+            case 3: ap->by_spec = apoc->clause_spec; break;
+            case 4: ap->pushing_spec = apoc->clause_spec; break;
+        }
+    }
+    ap->chief_action_owner_id = oid;
+}
+
+int APClauses::ap_count_optional_clauses(action_pattern *ap) {
+    int n = 0;
+    if (ap)
+        for (ap_clause *apoc = ap->ap_clauses; apoc; apoc = apoc->next)
+            if (apoc->stv_to_match)
+                if ((ap->chief_action_owner_id != 20007) ||
+                    (StackedVariables::get_offset(apoc->stv_to_match) >= 5))
+                    n++;
+    return n;
+}
+
+int APClauses::has_stv_clauses(action_pattern *ap) {
+    if ((ap) && (APClauses::nudge_to_stv_apoc(ap->ap_clauses))) return TRUE;
+    return FALSE;
+}
+
+int APClauses::compare_specificity_of_apoc_list(action_pattern *ap1, action_pattern *ap2) {
+    int rct1 = APClauses::ap_count_optional_clauses(ap1);
+    int rct2 = APClauses::ap_count_optional_clauses(ap2);
+
+    if (rct1 > rct2) return 1;
+    if (rct1 < rct2) return -1;
+    if (rct1 == 0) return 0;
+    if (ap1->chief_action_owner_id != ap2->chief_action_owner_id) return 0;
+
+    ap_clause *apoc1 = APClauses::nudge_to_stv_apoc(ap1->ap_clauses),
+        *apoc2 = APClauses::nudge_to_stv_apoc(ap2->ap_clauses);
+    while ((apoc1) && (apoc2)) {
+        int off1 = StackedVariables::get_offset(apoc1->stv_to_match);
+        int off2 = StackedVariables::get_offset(apoc2->stv_to_match);
+        if (off1 == off2) {
+            int rv = Specifications::compare_specificity(apoc1->clause_spec, apoc2->clause_spec, NULL);
+            if (rv != 0) return rv;
+            apoc1 = APClauses::nudge_to_stv_apoc(apoc1->next);
+            apoc2 = APClauses::nudge_to_stv_apoc(apoc2->next);
+        }
+        if (off1 < off2) apoc1 = APClauses::nudge_to_stv_apoc(apoc1->next);
+        if (off1 > off2) apoc2 = APClauses::nudge_to_stv_apoc(apoc2->next);
+    }
+    return 0;
+}
+
+ap_clause *APClauses::nudge_to_stv_apoc(ap_clause *apoc) {
+    while ((apoc) && (apoc->stv_to_match == NULL)) apoc = apoc->next;
+    return apoc;
+}
+
+int APClauses::validate(ap_clause *apoc, kind *K) {
+    if ((apoc) &&
+        (APClauses::opt(apoc, DO_NOT_VALIDATE_APCOPT) == FALSE) &&
+        (Dash::validate_parameter(apoc->clause_spec, K) == FALSE))
+        return FALSE;
+    return TRUE;
+}
+
+ + +