From e42234e48903a0d067d12d72ba834f33b81a07f1 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 10:01:23 +0200 Subject: [PATCH 01/16] Reverse the debug printout of connector lists ... so the printed order matches their expression order. --- link-grammar/disjunct-utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/link-grammar/disjunct-utils.c b/link-grammar/disjunct-utils.c index 3bbd132e48..cd5a47a974 100644 --- a/link-grammar/disjunct-utils.c +++ b/link-grammar/disjunct-utils.c @@ -466,11 +466,11 @@ void print_one_connector(Connector *e, int dir, int shallow, uint32_t flags) void dyn_print_connector_list(dyn_str *s, Connector *e, uint32_t flags) { - for (;e != NULL; e = e->next) - { - dyn_print_one_connector(s, e, /*dir*/-1, /*shallow*/-1, flags); - if (e->next != NULL) dyn_strcat(s, " "); - } + + if (e == NULL) return; + dyn_print_connector_list(s, e->next, flags); + if (e->next != NULL) dyn_strcat(s, " "); + dyn_print_one_connector(s, e, /*dir*/-1, /*shallow*/-1, flags); } void print_connector_list(Connector *e, uint32_t flags) From 2f09f7cd6a5488b1ce4e297a5feeee95805e5245 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 10:22:28 +0200 Subject: [PATCH 02/16] Disjunct printout: Add connector sign --- link-grammar/disjunct-utils.c | 14 +++++++------- link-grammar/disjunct-utils.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/link-grammar/disjunct-utils.c b/link-grammar/disjunct-utils.c index cd5a47a974..0b34f6f50e 100644 --- a/link-grammar/disjunct-utils.c +++ b/link-grammar/disjunct-utils.c @@ -442,7 +442,7 @@ void dyn_print_one_connector(dyn_str *s, Connector *e, int dir, int shallow, if (e->multi) dyn_strcat(s, "@"); dyn_strcat(s, connector_string(e)); - if (-1 != dir) dyn_strcat(s, &"-+"[dir]); + if (-1 != dir) dyn_strcat(s, (dir == 0) ? "-" : "+"); if (is_flag(flags, 't') && e->tracon_id) append_string(s, "<%d>", e->tracon_id); if (is_flag(flags, 'r') && e->refcount) @@ -464,20 +464,20 @@ void print_one_connector(Connector *e, int dir, int shallow, uint32_t flags) free(t); } -void dyn_print_connector_list(dyn_str *s, Connector *e, uint32_t flags) +void dyn_print_connector_list(dyn_str *s, Connector *e, int dir, uint32_t flags) { if (e == NULL) return; - dyn_print_connector_list(s, e->next, flags); + dyn_print_connector_list(s, e->next, dir, flags); if (e->next != NULL) dyn_strcat(s, " "); - dyn_print_one_connector(s, e, /*dir*/-1, /*shallow*/-1, flags); + dyn_print_one_connector(s, e, dir, /*shallow*/-1, flags); } void print_connector_list(Connector *e, uint32_t flags) { dyn_str *s = dyn_str_new(); - dyn_print_connector_list(s, e, flags); + dyn_print_connector_list(s, e, /*dir*/-1, flags); char *t = dyn_str_take(s); puts(t); @@ -501,9 +501,9 @@ void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags) append_string(s, "[%d]%s= ", i++, cost_stringify(dj->cost)); - dyn_print_connector_list(s, dj->left, flags); + dyn_print_connector_list(s, dj->left, /*dir*/0, flags); dyn_strcat(s, " <--> "); - dyn_print_connector_list(s, dj->right, flags); + dyn_print_connector_list(s, dj->right, /*dir*/1, flags); dyn_strcat(s, "\n"); } } diff --git a/link-grammar/disjunct-utils.h b/link-grammar/disjunct-utils.h index 463785a3c2..482dda2f05 100644 --- a/link-grammar/disjunct-utils.h +++ b/link-grammar/disjunct-utils.h @@ -75,7 +75,7 @@ void count_disjuncts_and_connectors(Sentence, unsigned int *, unsigned int *); void print_one_connector(Connector *, int, int, uint32_t); void dyn_print_one_connector(dyn_str *s, Connector *, int, int, uint32_t); void print_connector_list(Connector *, uint32_t); -void dyn_print_connector_list(dyn_str *s, Connector *, uint32_t); +void dyn_print_connector_list(dyn_str *s, Connector *, int, uint32_t); void print_disjunct_list(Disjunct *, uint32_t); void dyn_print_disjunct_list(dyn_str *s, Disjunct *, uint32_t); void print_all_disjuncts(Sentence); From 77cda61aa0f3f8274d87d8860f8f53ddf0b0db58 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 11:03:55 +0200 Subject: [PATCH 03/16] command-help-en.txt: Update the help text for "!" --- data/command-help-en.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/data/command-help-en.txt b/data/command-help-en.txt index 2338123643..2b714cb0cb 100644 --- a/data/command-help-en.txt +++ b/data/command-help-en.txt @@ -308,7 +308,7 @@ Examples: [!] This command is for debugging the dictionary or the library. -It gets as an argument a word, and optionally a regex and flags. +It gets as an argument a word, and optionally a regex and/or flags. It splits the given word to tokens according to the current language, and for each token it prints its matching dictionary words along with its expression or disjunct list. The word may include a wildcard * to find @@ -332,7 +332,13 @@ Show the disjuncts (without duplicates): !!test.n// Show selected disjuncts according to the supplied regex: - !!test.n/ Wd .*<-->.*@M\b/ + !!test.n/ Wd-.*<-->.*@M\+/ + !!test.n/ J[sk]- D[\w*]+c\-/ + + +Show selected disjuncts according to the supplied string (supposing the regex +engine is PCRE, which supports "\Q"): + !!test.n/\Q Ds**x+/ Display all the words that start with "test": !!test* @@ -348,15 +354,15 @@ A sample output of a disjunct-list display: test.n 4273/4501 disjuncts ... - test.n: [4070]1.500= Wd @hCO Ds**c <--> Ss*s @M NM + test.n: [3493]2.600= @AN- @A- Ds**x- <--> NM+ R+ Bs+ Bsm+ ... In the this sample output: 8509 Number of disjuncts in the dictionary expression. 4501 Number of disjuncts after applying cost-max. 4273 Number of disjuncts w/o duplicates. - 4070 Disjunct ordinal number. - 1.500 Disjunct cost. + 3493 Disjunct ordinal number. + 2.600 Disjunct cost. = A separator to enable regex anchoring. <--> A separator of the "-" (LHS) and "+" (RHS) connector lists. From c7bb042b331601b1f9afac078bf81be4dbe7bc4e Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 11:56:18 +0200 Subject: [PATCH 04/16] !!word/: Validate flags --- link-grammar/dict-common/print-dict.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index 8464a65c62..2cf63d30cd 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -388,6 +388,18 @@ GNUC_UNUSED static void prt_exp_mem(Exp *e) const char do_display_expr; /* a sentinel to request an expression display */ +static size_t unknown_flag(const char *display_type, const char *flags) +{ + const char *known_flags; + + if (&do_display_expr == display_type) + known_flags = "lm"; + else + known_flags = ""; + + return strspn(flags, known_flags); +} + /** * Display the information about the given word. * If the word can split, display the information about each part. @@ -439,7 +451,20 @@ static char *display_word_split(Dictionary dict, Regex_node *rn = NULL; if (arg != NULL) { + if (NULL != arg[1]) + { + size_t unknown_flag_pos = unknown_flag(arg[0], arg[1]); + if (arg[1][unknown_flag_pos] != '\0') + { + prt_error("Error: Token display: Unknown flag \"%c\".\n", + arg[1][unknown_flag_pos]); + dyn_strcat(s, " "); /* avoid a no-match error */ + goto display_word_split_error; + } + } + carg[1] = arg[1]; /* flags */ + if (arg[0] == &do_display_expr) { carg[0] = &do_display_expr; From 244a39b01c7e95eb23e006e3d3554376de7db2c6 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 12:12:58 +0200 Subject: [PATCH 05/16] Connector_struct: Use int8_t instead of int --- link-grammar/connectors.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/link-grammar/connectors.h b/link-grammar/connectors.h index 67055ca171..b03ecdaabb 100644 --- a/link-grammar/connectors.h +++ b/link-grammar/connectors.h @@ -120,7 +120,7 @@ struct Connector_struct the power pruning. */ uint8_t prune_pass; /* Prune pass number (one bit could be enough) */ bool multi; /* TRUE if this is a multi-connector */ - int tracon_id; /* Tracon identifier (see disjunct-utils.c) */ + int32_t tracon_id; /* Tracon identifier (see disjunct-utils.c) */ const condesc_t *desc; Connector *next; union @@ -129,7 +129,7 @@ struct Connector_struct /* For pruning use only */ struct { - int refcount; /* Memory-sharing reference count */ + int32_t refcount;/* Memory-sharing reference count - for pruning. */ bool shallow; /* TRUE if this is a shallow connector. * A connectors is shallow if it is the first in * its list on its disjunct. (It is deep if it is From 3864d84c1137c9fefbe618e39be90a974bb1de8d Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 12:57:44 +0200 Subject: [PATCH 06/16] Add expression connector position to disjunct connectors The immediate use of that is for expression debugging. However, it can be used for some other uses. --- link-grammar/connectors.h | 3 ++- link-grammar/prepare/build-disjuncts.c | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/link-grammar/connectors.h b/link-grammar/connectors.h index b03ecdaabb..a1b6c7b1b2 100644 --- a/link-grammar/connectors.h +++ b/link-grammar/connectors.h @@ -126,10 +126,11 @@ struct Connector_struct union { const gword_set *originating_gword; /* Used while and after parsing */ - /* For pruning use only */ struct { int32_t refcount;/* Memory-sharing reference count - for pruning. */ + uint16_t exp_pos; /* The position in the originating expression, + currently used only for debugging dict macros. */ bool shallow; /* TRUE if this is a shallow connector. * A connectors is shallow if it is the first in * its list on its disjunct. (It is deep if it is diff --git a/link-grammar/prepare/build-disjuncts.c b/link-grammar/prepare/build-disjuncts.c index f75fa813dc..c467ee714e 100644 --- a/link-grammar/prepare/build-disjuncts.c +++ b/link-grammar/prepare/build-disjuncts.c @@ -26,6 +26,7 @@ struct Tconnector_struct { Tconnector * next; const Exp *e; /* a CONNECTOR_type element from which to get the connector */ + int exp_pos; /* the position in the originating expression */ }; typedef struct clause_struct Clause; @@ -42,6 +43,7 @@ typedef struct double cost_cutoff; Pool_desc *Tconnector_pool; Pool_desc *Clause_pool; + int exp_pos; } clause_context; #ifdef DEBUG @@ -141,11 +143,12 @@ static Tconnector * catenate(Tconnector * e1, Tconnector * e2, Pool_desc *tp) /** * build the connector for the terminal node n */ -static Tconnector * build_terminal(Exp *e, Pool_desc *tp) +static Tconnector * build_terminal(Exp *e, clause_context *ct) { - Tconnector *c = pool_alloc(tp); + Tconnector *c = pool_alloc(ct->Tconnector_pool); c->e = e; c->next = NULL; + ct->exp_pos++; return c; } @@ -219,7 +222,7 @@ static Clause * build_clause(Exp *e, clause_context *ct) else if (e->type == CONNECTOR_type) { c = pool_alloc(ct->Clause_pool); - c->c = build_terminal(e, ct->Tconnector_pool); + c->c = build_terminal(e, ct); c->cost = 0.0; c->maxcost = 0.0; c->next = NULL; @@ -281,6 +284,7 @@ build_disjunct(Sentence sent, Clause * cl, const char * string, Connector *n = connector_new(connector_pool, t->e->condesc, opts); Connector **loc = ('-' == t->e->dir) ? &ndis->left : &ndis->right; + n->exp_pos = t->exp_pos; n->multi = t->e->multi; n->next = *loc; /* prepend the connector to the current list */ *loc = n; /* update the connector list */ From 3f12eb1bab222d4b57a1b30f5860809c132cf0a2 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 13:27:40 +0200 Subject: [PATCH 07/16] display_disjunct(): Move to print-dict.c --- link-grammar/dict-common/print-dict.c | 104 +++++++++++++++++++++++++ link-grammar/disjunct-utils.c | 107 +------------------------- link-grammar/disjunct-utils.h | 5 +- 3 files changed, 110 insertions(+), 106 deletions(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index 2cf63d30cd..2051eca76b 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -20,6 +20,7 @@ #include "dict-file/read-dict.h" #include "dict-utils.h" // copy_Exp #include "disjunct-utils.h" +#include "prepare/build-disjuncts.h" // build_disjuncts_for_exp #include "print/print.h" #include "print/print-util.h" #include "regex-morph.h" @@ -385,6 +386,109 @@ GNUC_UNUSED static void prt_exp_mem(Exp *e) } /* ================ Display word expressions / disjuncts ================= */ +/** + * Display the disjuncts of expressions in \p dn. + */ +static char *display_disjuncts(Dictionary dict, const Dict_node *dn, + const void **arg) +{ + const void *rn = arg[0]; + const char *flags = arg[1]; + const Parse_Options opts = (Parse_Options)arg[2]; + double max_cost = opts->disjunct_cost; + + uint32_t int_flags = 0; + if (flags != NULL) + { + for (const char *f = flags; *f != '\0'; f++) + int_flags |= make_flag(*f); + } + + /* build_disjuncts_for_exp() needs memory pools for efficiency. */ + Sentence dummy_sent = sentence_create("", dict); /* For memory pools. */ + dummy_sent->Disjunct_pool = pool_new(__func__, "Disjunct", + /*num_elements*/8192, sizeof(Disjunct), + /*zero_out*/false, /*align*/false, false); + dummy_sent->Connector_pool = pool_new(__func__, "Connector", + /*num_elements*/65536, sizeof(Connector), + /*zero_out*/true, /*align*/false, false); + + /* copy_Exp() needs an Exp memory pool. */ + Pool_desc *Exp_pool = pool_new(__func__, "Exp", /*num_elements*/256, + sizeof(Exp), /*zero_out*/false, + /*align*/false, /*exact*/false); + + dyn_str *s = dyn_str_new(); + dyn_strcat(s, "disjuncts:\n"); + for (; dn != NULL; dn = dn->right) + { + /* Use copy_Exp() to assign dialect cost. */ + Exp *e = copy_Exp(dn->exp, Exp_pool, opts); + Disjunct *d = build_disjuncts_for_exp(dummy_sent, e, dn->string, NULL, + max_cost, NULL); + unsigned int dnum0 = count_disjuncts(d); + d = eliminate_duplicate_disjuncts(d); + unsigned int dnum1 = count_disjuncts(d); + + dyn_str *dyn_pdl = dyn_str_new(); + dyn_print_disjunct_list(dyn_pdl, d, int_flags); + char *dliststr = dyn_str_take(dyn_pdl); + + pool_reuse(Exp_pool); + pool_reuse(dummy_sent->Disjunct_pool); + pool_reuse(dummy_sent->Connector_pool); + + /* Count number of disjuncts with tunnel connectors. */ + unsigned int tnum = 0; + for (const char *p = dliststr; *p != '\0'; p++) + if ((p[0] == ' ') && (p[1] == 'x')) tnum++; + + unsigned int dnum_selected = 0; + dyn_str *selected = NULL; + char *dstr = dliststr; + char *end; + if (rn != NULL) + { + selected = dyn_str_new(); + + do + { + end = strchr(dstr, '\n'); + *end = '\0'; + if (match_regex(rn , dstr) != NULL) + { + dyn_strcat(selected, dstr); + dyn_strcat(selected, "\n"); + dnum_selected++; + } + + dstr = end + 1; + } while (*dstr != '\0'); + + free(dliststr); + dliststr = dyn_str_take(selected); + } + + append_string(s, " %s %u/%u disjuncts", dn->string, dnum1, dnum0); + if (tnum != 0) append_string(s, " (%u tunnels)", tnum); + dyn_strcat(s, "\n"); + dyn_strcat(s, dliststr); + dyn_strcat(s, "\n"); + free(dliststr); + + if (rn != NULL) + { + if (dnum_selected == dnum1) + dyn_strcat(s, "(all the disjuncts matched)\n\n"); + else + append_string(s, "(%u disjuncts matched)\n\n", dnum_selected); + } + } + pool_delete(Exp_pool); + sentence_delete(dummy_sent); + + return dyn_str_take(s); +} const char do_display_expr; /* a sentinel to request an expression display */ diff --git a/link-grammar/disjunct-utils.c b/link-grammar/disjunct-utils.c index 0b34f6f50e..d5d3fea7cc 100644 --- a/link-grammar/disjunct-utils.c +++ b/link-grammar/disjunct-utils.c @@ -417,12 +417,12 @@ void count_disjuncts_and_connectors(Sentence sent, unsigned int *dca, } /* ================ Print disjuncts and connectors ============== */ -static bool is_flag(uint32_t flags, char flag) +bool is_flag(uint32_t flags, char flag) { return (flags>>(flag-'a')) & 1; } -static uint32_t make_flag(char flag) +uint32_t make_flag(char flag) { return 1<<(flag-'a'); } @@ -525,109 +525,6 @@ void print_all_disjuncts(Sentence sent) free(t); } -/** - * Display the disjuncts of expressions in \p dn. - */ -char *display_disjuncts(Dictionary dict, const Dict_node *dn, const void **arg) -{ - const void *rn = arg[0]; - const char *flags = arg[1]; - const Parse_Options opts = (Parse_Options)arg[2]; - double max_cost = opts->disjunct_cost; - - uint32_t int_flags = 0; - if (flags != NULL) - { - for (const char *f = flags; *f != '\0'; f++) - int_flags |= make_flag(*f); - } - - /* build_disjuncts_for_exp() needs memory pools for efficiency. */ - Sentence dummy_sent = sentence_create("", dict); /* For memory pools. */ - dummy_sent->Disjunct_pool = pool_new(__func__, "Disjunct", - /*num_elements*/8192, sizeof(Disjunct), - /*zero_out*/false, /*align*/false, false); - dummy_sent->Connector_pool = pool_new(__func__, "Connector", - /*num_elements*/65536, sizeof(Connector), - /*zero_out*/true, /*align*/false, false); - - /* copy_Exp() needs an Exp memory pool. */ - Pool_desc *Exp_pool = pool_new(__func__, "Exp", /*num_elements*/256, - sizeof(Exp), /*zero_out*/false, - /*align*/false, /*exact*/false); - - dyn_str *s = dyn_str_new(); - dyn_strcat(s, "disjuncts:\n"); - for (; dn != NULL; dn = dn->right) - { - /* Use copy_Exp() to assign dialect cost. */ - Exp *e = copy_Exp(dn->exp, Exp_pool, opts); - Disjunct *d = build_disjuncts_for_exp(dummy_sent, e, dn->string, NULL, - max_cost, NULL); - unsigned int dnum0 = count_disjuncts(d); - d = eliminate_duplicate_disjuncts(d); - unsigned int dnum1 = count_disjuncts(d); - - dyn_str *dyn_pdl = dyn_str_new(); - dyn_print_disjunct_list(dyn_pdl, d, int_flags); - char *dliststr = dyn_str_take(dyn_pdl); - - pool_reuse(Exp_pool); - pool_reuse(dummy_sent->Disjunct_pool); - pool_reuse(dummy_sent->Connector_pool); - - /* Count number of disjuncts with tunnel connectors. */ - unsigned int tnum = 0; - for (const char *p = dliststr; *p != '\0'; p++) - if ((p[0] == ' ') && (p[1] == 'x')) tnum++; - - unsigned int dnum_selected = 0; - dyn_str *selected = NULL; - char *dstr = dliststr; - char *end; - if (rn != NULL) - { - selected = dyn_str_new(); - - do - { - end = strchr(dstr, '\n'); - *end = '\0'; - if (match_regex(rn , dstr) != NULL) - { - dyn_strcat(selected, dstr); - dyn_strcat(selected, "\n"); - dnum_selected++; - } - - dstr = end + 1; - } while (*dstr != '\0'); - - free(dliststr); - dliststr = dyn_str_take(selected); - } - - append_string(s, " %s %u/%u disjuncts", dn->string, dnum1, dnum0); - if (tnum != 0) append_string(s, " (%u tunnels)", tnum); - dyn_strcat(s, "\n"); - dyn_strcat(s, dliststr); - dyn_strcat(s, "\n"); - free(dliststr); - - if (rn != NULL) - { - if (dnum_selected == dnum1) - dyn_strcat(s, "(all the disjuncts matched)\n\n"); - else - append_string(s, "(%u disjuncts matched)\n\n", dnum_selected); - } - } - pool_delete(Exp_pool); - sentence_delete(dummy_sent); - - return dyn_str_take(s); -} - /* ============= Connector encoding, sharing and packing ============= */ /* diff --git a/link-grammar/disjunct-utils.h b/link-grammar/disjunct-utils.h index 482dda2f05..3e7f10a7c8 100644 --- a/link-grammar/disjunct-utils.h +++ b/link-grammar/disjunct-utils.h @@ -79,7 +79,10 @@ void dyn_print_connector_list(dyn_str *s, Connector *, int, uint32_t); void print_disjunct_list(Disjunct *, uint32_t); void dyn_print_disjunct_list(dyn_str *s, Disjunct *, uint32_t); void print_all_disjuncts(Sentence); -char *display_disjuncts(Dictionary, const Dict_node *, const void **); + +/* FIXME: Move to general utilities file. */ +bool is_flag(uint32_t, char); +uint32_t make_flag(char); /* Save and restore sentence disjuncts */ typedef struct From a83b9a9efd5093484fa54ba2e74def39d11361ed Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 15:21:03 +0200 Subject: [PATCH 08/16] Move disjunct and connector printing to print-dict.c --- link-grammar/dict-common/print-dict.c | 114 +++++++++++++++++++++++++- link-grammar/disjunct-utils.c | 109 ------------------------ link-grammar/disjunct-utils.h | 8 -- 3 files changed, 112 insertions(+), 119 deletions(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index 2051eca76b..cd97475b47 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -20,13 +20,13 @@ #include "dict-file/read-dict.h" #include "dict-utils.h" // copy_Exp #include "disjunct-utils.h" -#include "prepare/build-disjuncts.h" // build_disjuncts_for_exp +#include "prepare/build-disjuncts.h" // build_disjuncts_for_exp #include "print/print.h" #include "print/print-util.h" #include "regex-morph.h" #include "tokenize/tokenize.h" // word_add +#include "tokenize/word-structures.h" // Word_struct #include "utilities.h" // GNU_UNUSED - /* ======================================================================== */ bool cost_eq(double cost1, double cost2) @@ -385,6 +385,116 @@ GNUC_UNUSED static void prt_exp_mem(Exp *e) free(e_str); } +/* ================ Print disjuncts and connectors ============== */ +static bool is_flag(uint32_t flags, char flag) +{ + return (flags>>(flag-'a')) & 1; +} + +static uint32_t make_flag(char flag) +{ + return 1<<(flag-'a'); +} + +/* Print one connector with all the details. + * mCnameD{refcount}(nearest_word, length_limit)x + * Optional m: "@" for multi (else nothing). + * Cname: Connector name. + * Optional D: "-" / "+" (if dir != -1). + * Optional : (flag 't'). + * Optional [nearest_word, length_limit or farthest_word]: (flag 'l'). + * x: Shallow/deep indication as "s" / "d" (if shallow != -1) + */ +static void dyn_print_one_connector(dyn_str *s, Connector *e, int dir, + int shallow, uint32_t flags) +{ + if (e->multi) + dyn_strcat(s, "@"); + dyn_strcat(s, connector_string(e)); + if (-1 != dir) dyn_strcat(s, (dir == 0) ? "-" : "+"); + if (is_flag(flags, 't') && e->tracon_id) + append_string(s, "<%d>", e->tracon_id); + if (is_flag(flags, 'r') && e->refcount) + append_string(s, "{%d}",e->refcount); + if (is_flag(flags, 'l')) + append_string(s, "(%d,%d)", e->nearest_word, e->length_limit); + if (-1 != shallow) + dyn_strcat(s, (0 == shallow) ? "d" : "s"); +} + +GNUC_UNUSED static void print_one_connector(Connector *e, int dir, int shallow, + uint32_t flags) +{ + dyn_str *s = dyn_str_new(); + + dyn_print_one_connector(s, e, dir, shallow, flags); + + char *t = dyn_str_take(s); + puts(t); + free(t); +} + +static void dyn_print_connector_list(dyn_str *s, Connector *e, int dir, uint32_t flags) +{ + + if (e == NULL) return; + dyn_print_connector_list(s, e->next, dir, flags); + if (e->next != NULL) dyn_strcat(s, " "); + dyn_print_one_connector(s, e, dir, /*shallow*/-1, flags); +} + +void print_connector_list(Connector *e, uint32_t flags) +{ + dyn_str *s = dyn_str_new(); + + dyn_print_connector_list(s, e, /*dir*/-1, flags); + + char *t = dyn_str_take(s); + puts(t); + free(t); +} + +static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags) +{ + int i = 0; + char word[MAX_WORD + 32]; + bool print_disjunct_address = test_enabled("disjunct-address"); + + for (;dj != NULL; dj=dj->next) + { + lg_strlcpy(word, dj->word_string, sizeof(word)); + patch_subscript_mark(word); + + append_string(s, "%16s", word); + if (print_disjunct_address) append_string(s, "(%p)", dj); + dyn_strcat(s, ": "); + + append_string(s, "[%d]%s= ", i++, cost_stringify(dj->cost)); + + dyn_print_connector_list(s, dj->left, /*dir*/0, flags); + dyn_strcat(s, " <--> "); + dyn_print_connector_list(s, dj->right, /*dir*/1, flags); + dyn_strcat(s, "\n"); + } +} + +void print_all_disjuncts(Sentence sent) +{ + dyn_str *s = dyn_str_new(); + uint32_t flags = make_flag('l') | make_flag('t'); + + for (WordIdx w = 0; w < sent->length; w++) + { + append_string(s, "Word %zu:\n", w); + dyn_print_disjunct_list(s, sent->word[w].d, flags); + + } + + char *t = dyn_str_take(s); + puts(t); + free(t); +} + /* ================ Display word expressions / disjuncts ================= */ /** * Display the disjuncts of expressions in \p dn. diff --git a/link-grammar/disjunct-utils.c b/link-grammar/disjunct-utils.c index d5d3fea7cc..5c1be6c852 100644 --- a/link-grammar/disjunct-utils.c +++ b/link-grammar/disjunct-utils.c @@ -416,115 +416,6 @@ void count_disjuncts_and_connectors(Sentence sent, unsigned int *dca, *dca = dcnt; } -/* ================ Print disjuncts and connectors ============== */ -bool is_flag(uint32_t flags, char flag) -{ - return (flags>>(flag-'a')) & 1; -} - -uint32_t make_flag(char flag) -{ - return 1<<(flag-'a'); -} - -/* Print one connector with all the details. - * mCnameD{refcount}(nearest_word, length_limit)x - * Optional m: "@" for multi (else nothing). - * Cname: Connector name. - * Optional D: "-" / "+" (if dir != -1). - * Optional : (flag 't'). - * Optional [nearest_word, length_limit or farthest_word]: (flag 'l'). - * x: Shallow/deep indication as "s" / "d" (if shallow != -1) - */ -void dyn_print_one_connector(dyn_str *s, Connector *e, int dir, int shallow, - uint32_t flags) -{ - if (e->multi) - dyn_strcat(s, "@"); - dyn_strcat(s, connector_string(e)); - if (-1 != dir) dyn_strcat(s, (dir == 0) ? "-" : "+"); - if (is_flag(flags, 't') && e->tracon_id) - append_string(s, "<%d>", e->tracon_id); - if (is_flag(flags, 'r') && e->refcount) - append_string(s, "{%d}",e->refcount); - if (is_flag(flags, 'l')) - append_string(s, "(%d,%d)", e->nearest_word, e->length_limit); - if (-1 != shallow) - dyn_strcat(s, (0 == shallow) ? "d" : "s"); -} - -void print_one_connector(Connector *e, int dir, int shallow, uint32_t flags) -{ - dyn_str *s = dyn_str_new(); - - dyn_print_one_connector(s, e, dir, shallow, flags); - - char *t = dyn_str_take(s); - puts(t); - free(t); -} - -void dyn_print_connector_list(dyn_str *s, Connector *e, int dir, uint32_t flags) -{ - - if (e == NULL) return; - dyn_print_connector_list(s, e->next, dir, flags); - if (e->next != NULL) dyn_strcat(s, " "); - dyn_print_one_connector(s, e, dir, /*shallow*/-1, flags); -} - -void print_connector_list(Connector *e, uint32_t flags) -{ - dyn_str *s = dyn_str_new(); - - dyn_print_connector_list(s, e, /*dir*/-1, flags); - - char *t = dyn_str_take(s); - puts(t); - free(t); -} - -void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags) -{ - int i = 0; - char word[MAX_WORD + 32]; - bool print_disjunct_address = test_enabled("disjunct-address"); - - for (;dj != NULL; dj=dj->next) - { - lg_strlcpy(word, dj->word_string, sizeof(word)); - patch_subscript_mark(word); - - append_string(s, "%16s", word); - if (print_disjunct_address) append_string(s, "(%p)", dj); - dyn_strcat(s, ": "); - - append_string(s, "[%d]%s= ", i++, cost_stringify(dj->cost)); - - dyn_print_connector_list(s, dj->left, /*dir*/0, flags); - dyn_strcat(s, " <--> "); - dyn_print_connector_list(s, dj->right, /*dir*/1, flags); - dyn_strcat(s, "\n"); - } -} - -void print_all_disjuncts(Sentence sent) -{ - dyn_str *s = dyn_str_new(); - uint32_t flags = make_flag('l') | make_flag('t'); - - for (WordIdx w = 0; w < sent->length; w++) - { - append_string(s, "Word %zu:\n", w); - dyn_print_disjunct_list(s, sent->word[w].d, flags); - - } - - char *t = dyn_str_take(s); - puts(t); - free(t); -} - /* ============= Connector encoding, sharing and packing ============= */ /* diff --git a/link-grammar/disjunct-utils.h b/link-grammar/disjunct-utils.h index 3e7f10a7c8..91003b2800 100644 --- a/link-grammar/disjunct-utils.h +++ b/link-grammar/disjunct-utils.h @@ -72,18 +72,10 @@ Tracon_sharing *pack_sentence_for_parsing(Sentence); void free_tracon_sharing(Tracon_sharing *); void count_disjuncts_and_connectors(Sentence, unsigned int *, unsigned int *); -void print_one_connector(Connector *, int, int, uint32_t); -void dyn_print_one_connector(dyn_str *s, Connector *, int, int, uint32_t); void print_connector_list(Connector *, uint32_t); -void dyn_print_connector_list(dyn_str *s, Connector *, int, uint32_t); void print_disjunct_list(Disjunct *, uint32_t); -void dyn_print_disjunct_list(dyn_str *s, Disjunct *, uint32_t); void print_all_disjuncts(Sentence); -/* FIXME: Move to general utilities file. */ -bool is_flag(uint32_t, char); -uint32_t make_flag(char); - /* Save and restore sentence disjuncts */ typedef struct { From e29fc119891eb7106715bb13698f695127c4bb01 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 16:59:21 +0200 Subject: [PATCH 09/16] !!word/number/: A hack to select a disjunct by number --- link-grammar/dict-common/print-dict.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index cd97475b47..d84162aed6 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -690,11 +690,22 @@ static char *display_word_split(Dictionary dict, { rn = malloc(sizeof(Regex_node)); rn->name = strdup("Disjunct regex"); - rn->pattern = strdup(arg[0]); rn->re = NULL; rn->neg = false; rn->next = NULL; + if (arg[0][strspn(arg[0], "0123456789")] != '\0') + { + rn->pattern = strdup(arg[0]); + } + else + { + rn->pattern = malloc(strlen(arg[0]) + 4); /* \ [ ] \0 */ + strcpy(rn->pattern, "\\["); + strcat(rn->pattern, arg[0]); + strcat(rn->pattern, "]"); + } + if (compile_regexs(rn, NULL) != 0) { prt_error("Error: Failed to compile regex \"%s\".\n", arg[0]); From f8cf76371943fa2dd4bb6e8aa55ea7b9f9f17096 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 17:04:38 +0200 Subject: [PATCH 10/16] Improve disjunct list title spacing --- link-grammar/dict-common/print-dict.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index d84162aed6..ada3850f14 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -496,6 +496,8 @@ void print_all_disjuncts(Sentence sent) } /* ================ Display word expressions / disjuncts ================= */ +#define DJ_COL_WIDTH sizeof(" ") + /** * Display the disjuncts of expressions in \p dn. */ @@ -582,6 +584,10 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, append_string(s, " %s %u/%u disjuncts", dn->string, dnum1, dnum0); if (tnum != 0) append_string(s, " (%u tunnels)", tnum); dyn_strcat(s, "\n"); + append_string(s, " %-*s %8u/%u disjuncts", + display_width(DJ_COL_WIDTH, dn->string), dn->string, + dnum1, dnum0); + dyn_strcat(s, "\n\n"); dyn_strcat(s, dliststr); dyn_strcat(s, "\n"); free(dliststr); @@ -776,8 +782,6 @@ static unsigned int count_disjunct_for_dict_node(Dict_node *dn) return (NULL == dn) ? 0 : count_clause(dn->exp); } -#define DJ_COL_WIDTH sizeof(" ") - /** * Display the number of disjuncts associated with this dict node */ From be05096b0835362a2f9ee13fe9ef1a25f642c002 Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 17:04:38 +0200 Subject: [PATCH 11/16] !!word//: Disjunct list header: disjunct / disjuncts --- link-grammar/dict-common/print-dict.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index ada3850f14..491e06fe4b 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -597,7 +597,9 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, if (dnum_selected == dnum1) dyn_strcat(s, "(all the disjuncts matched)\n\n"); else - append_string(s, "(%u disjuncts matched)\n\n", dnum_selected); + append_string(s, "(%u disjunct%s matched)\n\n", dnum_selected, + dnum_selected == 1 ? "" : "s"); + } } pool_delete(Exp_pool); From 153992cefd0533e01dd1fb1d76883e0370cedbcf Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 17:30:19 +0200 Subject: [PATCH 12/16] lword//: Select the disjunct earlier --- link-grammar/dict-common/print-dict.c | 103 ++++++++++++++------------ 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index 491e06fe4b..bcb6ecaf0a 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -454,7 +454,16 @@ void print_connector_list(Connector *e, uint32_t flags) free(t); } -static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags) +typedef struct +{ + const void *regex; + unsigned int num_selected; + unsigned int num_tunnels; +} select_data; + +static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags, + bool (* select)(const char *dj_str, select_data *criterion), + select_data *criterion) { int i = 0; char word[MAX_WORD + 32]; @@ -464,17 +473,24 @@ static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags) { lg_strlcpy(word, dj->word_string, sizeof(word)); patch_subscript_mark(word); + dyn_str *l = dyn_str_new(); - append_string(s, "%16s", word); + append_string(l, "%16s", word); if (print_disjunct_address) append_string(s, "(%p)", dj); - dyn_strcat(s, ": "); + dyn_strcat(l, ": "); - append_string(s, "[%d]%s= ", i++, cost_stringify(dj->cost)); + append_string(l, "[%d]%s= ", i++, cost_stringify(dj->cost)); + dyn_print_connector_list(l, dj->left, /*dir*/0, flags); + dyn_strcat(l, " <--> "); + dyn_print_connector_list(l, dj->right, /*dir*/1, flags); - dyn_print_connector_list(s, dj->left, /*dir*/0, flags); - dyn_strcat(s, " <--> "); - dyn_print_connector_list(s, dj->right, /*dir*/1, flags); - dyn_strcat(s, "\n"); + char *ls = dyn_str_take(l); + if ((NULL == select) || select(ls, criterion)) + { + dyn_strcat(s, ls); + dyn_strcat(s, "\n"); + } + free(ls); } } @@ -486,7 +502,7 @@ void print_all_disjuncts(Sentence sent) for (WordIdx w = 0; w < sent->length; w++) { append_string(s, "Word %zu:\n", w); - dyn_print_disjunct_list(s, sent->word[w].d, flags); + dyn_print_disjunct_list(s, sent->word[w].d, flags, NULL, NULL); } @@ -498,6 +514,24 @@ void print_all_disjuncts(Sentence sent) /* ================ Display word expressions / disjuncts ================= */ #define DJ_COL_WIDTH sizeof(" ") +static bool select_disjunct(const char *dj_str, select_data *criterion) +{ + /* Count number of disjuncts with tunnel connectors. */ + for (const char *p = dj_str; *p != '\0'; p++) + { + if ((p[0] == ' ') && (p[1] == 'x')) + { + criterion->num_tunnels++; + break; + } + } + + /* Select desired disjuncts. */ + if (match_regex(criterion->regex , dj_str) == NULL) return false; + criterion->num_selected++; + return true; +} + /** * Display the disjuncts of expressions in \p dn. */ @@ -530,6 +564,9 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, sizeof(Exp), /*zero_out*/false, /*align*/false, /*exact*/false); + select_data criterion = { .regex = rn }; + void *select = (rn == NULL) ? NULL : select_disjunct; + dyn_str *s = dyn_str_new(); dyn_strcat(s, "disjuncts:\n"); for (; dn != NULL; dn = dn->right) @@ -538,55 +575,25 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, Exp *e = copy_Exp(dn->exp, Exp_pool, opts); Disjunct *d = build_disjuncts_for_exp(dummy_sent, e, dn->string, NULL, max_cost, NULL); + unsigned int dnum0 = count_disjuncts(d); d = eliminate_duplicate_disjuncts(d); unsigned int dnum1 = count_disjuncts(d); + criterion.num_selected = 0; dyn_str *dyn_pdl = dyn_str_new(); - dyn_print_disjunct_list(dyn_pdl, d, int_flags); + dyn_print_disjunct_list(dyn_pdl, d, int_flags, select, &criterion); char *dliststr = dyn_str_take(dyn_pdl); pool_reuse(Exp_pool); pool_reuse(dummy_sent->Disjunct_pool); pool_reuse(dummy_sent->Connector_pool); - /* Count number of disjuncts with tunnel connectors. */ - unsigned int tnum = 0; - for (const char *p = dliststr; *p != '\0'; p++) - if ((p[0] == ' ') && (p[1] == 'x')) tnum++; - - unsigned int dnum_selected = 0; - dyn_str *selected = NULL; - char *dstr = dliststr; - char *end; - if (rn != NULL) - { - selected = dyn_str_new(); - - do - { - end = strchr(dstr, '\n'); - *end = '\0'; - if (match_regex(rn , dstr) != NULL) - { - dyn_strcat(selected, dstr); - dyn_strcat(selected, "\n"); - dnum_selected++; - } - - dstr = end + 1; - } while (*dstr != '\0'); - - free(dliststr); - dliststr = dyn_str_take(selected); - } - - append_string(s, " %s %u/%u disjuncts", dn->string, dnum1, dnum0); - if (tnum != 0) append_string(s, " (%u tunnels)", tnum); - dyn_strcat(s, "\n"); append_string(s, " %-*s %8u/%u disjuncts", display_width(DJ_COL_WIDTH, dn->string), dn->string, dnum1, dnum0); + if (criterion.num_tunnels != 0) + append_string(s, " (%u tunnels)", criterion.num_tunnels); dyn_strcat(s, "\n\n"); dyn_strcat(s, dliststr); dyn_strcat(s, "\n"); @@ -594,12 +601,12 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, if (rn != NULL) { - if (dnum_selected == dnum1) + if (criterion.num_selected == dnum1) dyn_strcat(s, "(all the disjuncts matched)\n\n"); else - append_string(s, "(%u disjunct%s matched)\n\n", dnum_selected, - dnum_selected == 1 ? "" : "s"); - + append_string(s, "(%u disjunct%s matched)\n\n", + criterion.num_selected, + criterion.num_selected == 1 ? "" : "s"); } } pool_delete(Exp_pool); From e72875308279949759e4ee6c9a497b1255c9f3bf Mon Sep 17 00:00:00 2001 From: ampli Date: Wed, 22 Jan 2020 19:04:38 +0200 Subject: [PATCH 13/16] Print connector expression source macros for disjuncts --- link-grammar/dict-common/print-dict.c | 148 ++++++++++++++++++++++++- link-grammar/prepare/build-disjuncts.c | 2 +- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index bcb6ecaf0a..bfc98f4c7a 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -212,6 +212,100 @@ static void print_expression_parens(Dictionary dict, dyn_str *e, const Exp *n, } +/** + * Find if the given connector is in the given expression. + * @param e Expression. + * @param find_pos Connector position to search in \p e. + * @param pos Temporary connector position while the search advances. + * Return \c true iff the connector is found. + */ +static bool exp_contains_connector(const Exp *e, int *pos, int find_pos) +{ + if (NULL == e) return false; + + if (CONNECTOR_type == e->type) + { +#if 0 + printf("exp_contains_connector: pos=%d C=%s%s%c %s\n", + *pos,e->multi?"@":"",e->condesc->string,e->dir, + (find_pos == *pos) ? "FOUND" : ""); +#endif + return (find_pos == (*pos)++); + } + + for(Exp *opd = e->operand_first; opd != NULL; opd = opd->operand_next) + { + if (exp_contains_connector(opd, pos, find_pos)) + return true; + } + + return false; +} + +typedef struct +{ + Dictionary dict; + dyn_str *e; + int indent; + int pos; /* current connector position in expression */ + int *find_pos; /* disjunct expression connectors positions */ + bool is_after_connector; /* an indicators for printing '&' */ +} cmacro_context; + +/** + * Print nested macros for each desired connector. + * The desired connector positions are in find_pos[] (ascending sorted, + * -1 terminated). Its first element holds the next position of the next + * connector to print, and is chopped after the connector is printed. + */ +static void print_connector_macros(cmacro_context *cmc, const Exp *n) +{ + if ((cmc->find_pos)[0] == -1) + return; /* fast termination when nothing more to do */ + + bool macro_started = false; + int current_pos = cmc->pos; + if ((Exptag_macro == n->tag_type) && + exp_contains_connector(n, ¤t_pos, (cmc->find_pos)[0])) + { + if (cmc->is_after_connector) + { + dyn_strcat(cmc->e, " & "); + cmc->is_after_connector = false; + } + print_expression_tag_start(cmc->dict, cmc->e, n, &cmc->indent); + macro_started = true; + } + + Exp *opd = n->operand_first; + + if (n->type == CONNECTOR_type) + { + if ((cmc->find_pos)[0] == cmc->pos) + { + if (cmc->is_after_connector) dyn_strcat(cmc->e, " & "); + cmc->is_after_connector = true; + if (n->multi) dyn_strcat(cmc->e, "@"); + dyn_strcat(cmc->e, + n->condesc ? n->condesc->string : "error-null-connector"); + dyn_strcat(cmc->e, (const char []){ n->dir, '\0' }); + cmc->find_pos++; /* each expression position is used only once */ + } + cmc->pos++; + } + else + { + for (Exp *l = opd; l != NULL; l = l->operand_next) + { + print_connector_macros(cmc, l); + } + } + + /* The -1 check is to suppress unneeded newlines at the end. */ + if (macro_started && ((cmc->find_pos)[0] != -1)) + print_expression_tag_end(cmc->dict, cmc->e, n, &cmc->indent); +} + static const char *lg_exp_stringify_with_tags(Dictionary dict, const Exp *n, bool show_macros) { @@ -418,6 +512,9 @@ static void dyn_print_one_connector(dyn_str *s, Connector *e, int dir, append_string(s, "{%d}",e->refcount); if (is_flag(flags, 'l')) append_string(s, "(%d,%d)", e->nearest_word, e->length_limit); +#if 0 + append_string(s, "<<%d>>", e->exp_pos); +#endif if (-1 != shallow) dyn_strcat(s, (0 == shallow) ? "d" : "s"); } @@ -454,9 +551,22 @@ void print_connector_list(Connector *e, uint32_t flags) free(t); } +/* Ascending sort of connector positions. */ +static int ascending_int(const void *a, const void *b) +{ + const int a1 = *(const int *)a; + const int b1 = *(const int *)b; + + if (a1 < b1) return -1; + if (a1 == b1) return 0; + return 1; +} + typedef struct { const void *regex; + Exp *exp; + Dictionary dict; unsigned int num_selected; unsigned int num_tunnels; } select_data; @@ -465,7 +575,7 @@ static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags, bool (* select)(const char *dj_str, select_data *criterion), select_data *criterion) { - int i = 0; + int djn = 0; char word[MAX_WORD + 32]; bool print_disjunct_address = test_enabled("disjunct-address"); @@ -479,7 +589,7 @@ static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags, if (print_disjunct_address) append_string(s, "(%p)", dj); dyn_strcat(l, ": "); - append_string(l, "[%d]%s= ", i++, cost_stringify(dj->cost)); + append_string(l, "[%d]%s= ", djn++, cost_stringify(dj->cost)); dyn_print_connector_list(l, dj->left, /*dir*/0, flags); dyn_strcat(l, " <--> "); dyn_print_connector_list(l, dj->right, /*dir*/1, flags); @@ -489,6 +599,33 @@ static void dyn_print_disjunct_list(dyn_str *s, Disjunct *dj, uint32_t flags, { dyn_strcat(s, ls); dyn_strcat(s, "\n"); + + if (criterion->exp != NULL) + { + int ccnt = 1; + for (Connector *c = dj->left; c != NULL; c = c->next) + ccnt++; + for (Connector *c = dj->right; c != NULL; c = c->next) + ccnt++; + + int *exp_pos = alloca(ccnt * sizeof(int)); + int *i = exp_pos; + for (Connector *c = dj->left; c != NULL; c = c->next) + *i++ = c->exp_pos; + for (Connector *c = dj->right; c != NULL; c = c->next) + *i++ = c->exp_pos; + *i = -1; + + qsort(exp_pos, ccnt-1, sizeof(int), ascending_int); + + cmacro_context cmc = { + .dict = criterion->dict, + .e = s, + .find_pos = exp_pos, + }; + print_connector_macros(&cmc, criterion->exp); + dyn_strcat(s, "\n\n"); + } } free(ls); } @@ -580,6 +717,11 @@ static char *display_disjuncts(Dictionary dict, const Dict_node *dn, d = eliminate_duplicate_disjuncts(d); unsigned int dnum1 = count_disjuncts(d); + if ((flags != NULL) && (strchr(flags, 'm') != NULL)) + { + criterion.exp = e; + criterion.dict = dict; + } criterion.num_selected = 0; dyn_str *dyn_pdl = dyn_str_new(); dyn_print_disjunct_list(dyn_pdl, d, int_flags, select, &criterion); @@ -624,7 +766,7 @@ static size_t unknown_flag(const char *display_type, const char *flags) if (&do_display_expr == display_type) known_flags = "lm"; else - known_flags = ""; + known_flags = "m"; return strspn(flags, known_flags); } diff --git a/link-grammar/prepare/build-disjuncts.c b/link-grammar/prepare/build-disjuncts.c index c467ee714e..4882bc3ae0 100644 --- a/link-grammar/prepare/build-disjuncts.c +++ b/link-grammar/prepare/build-disjuncts.c @@ -148,7 +148,7 @@ static Tconnector * build_terminal(Exp *e, clause_context *ct) Tconnector *c = pool_alloc(ct->Tconnector_pool); c->e = e; c->next = NULL; - ct->exp_pos++; + c->exp_pos = ct->exp_pos++; return c; } From 5c7df40069eaa18bfa5e21f1d80800c3696711a7 Mon Sep 17 00:00:00 2001 From: ampli Date: Thu, 23 Jan 2020 16:58:34 +0200 Subject: [PATCH 14/16] !!word//: Update the help text for the recent changes --- data/command-help-en.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/data/command-help-en.txt b/data/command-help-en.txt index 2b714cb0cb..81c708df2e 100644 --- a/data/command-help-en.txt +++ b/data/command-help-en.txt @@ -331,11 +331,17 @@ Show also low-level memory details of the expression: Show the disjuncts (without duplicates): !!test.n// +Show disjunct connector expression source macros: + !!test.n//m + +The above command is more useful for a single disjunct (1234 is an example +for a disjunct number, see below for disjunct print format): + !!test.n/1234/m + Show selected disjuncts according to the supplied regex: !!test.n/ Wd-.*<-->.*@M\+/ !!test.n/ J[sk]- D[\w*]+c\-/ - Show selected disjuncts according to the supplied string (supposing the regex engine is PCRE, which supports "\Q"): !!test.n/\Q Ds**x+/ @@ -346,6 +352,7 @@ Display all the words that start with "test": Display all the words that start with "test" and have subscript ".q": !!test*.q + A sample output of a disjunct-list display: Token "test.n" matches: test.n 8509 disjuncts From b9708d02cd65b00535869e33b3903b125c6e0bf6 Mon Sep 17 00:00:00 2001 From: ampli Date: Thu, 23 Jan 2020 18:55:39 +0200 Subject: [PATCH 15/16] Add dyn_strlen() --- link-grammar/utilities.c | 5 +++++ link-grammar/utilities.h | 1 + 2 files changed, 6 insertions(+) diff --git a/link-grammar/utilities.c b/link-grammar/utilities.c index c65381cc34..e5dfb69e5e 100644 --- a/link-grammar/utilities.c +++ b/link-grammar/utilities.c @@ -561,6 +561,11 @@ const char * dyn_str_value(dyn_str* s) return s->str; } +size_t dyn_strlen(dyn_str* s) +{ + return s->end; +} + /* ======================================================== */ /* Locale routines */ diff --git a/link-grammar/utilities.h b/link-grammar/utilities.h index 21a566ea02..711273c77c 100644 --- a/link-grammar/utilities.h +++ b/link-grammar/utilities.h @@ -480,6 +480,7 @@ void dyn_strcat(dyn_str*, const char*); void dyn_trimback(dyn_str*); char * dyn_str_take(dyn_str*); const char * dyn_str_value(dyn_str*); +size_t dyn_strlen(dyn_str*); size_t altlen(const char **); From 4fa0843d4d2c86be0ff28eaa011e94d54b2ec5ba Mon Sep 17 00:00:00 2001 From: ampli Date: Thu, 23 Jan 2020 19:24:56 +0200 Subject: [PATCH 16/16] !!word/m: Prevent empty lines --- link-grammar/dict-common/print-dict.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/link-grammar/dict-common/print-dict.c b/link-grammar/dict-common/print-dict.c index bfc98f4c7a..56b6dceed6 100644 --- a/link-grammar/dict-common/print-dict.c +++ b/link-grammar/dict-common/print-dict.c @@ -89,7 +89,15 @@ static void print_expression_tag_end(Dictionary dict, dyn_str *e, const Exp *n, break; case Exptag_macro: if (*indent < 0) break; - dyn_strcat(e, "\n"); + /* The sole purpose of the checks before issuing "\n" is to prevent + * empty lines when printing connector macros w/o introducing a + * separate version of this function for connector macro printing. */ + if (dyn_strlen(e) > 0) + { + dyn_trimback(e); + if ((dyn_str_value(e)[dyn_strlen(e)-1]) != '\n') + dyn_strcat(e, "\n"); + } for(int i = 0; i < *indent - MACRO_INDENTATION/2; i++) dyn_strcat(e, " "); (*indent) -= MACRO_INDENTATION;