From 6ce82b63cd35eac37a4ddf1d0253342d5160b7af Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 3 Aug 2016 19:22:27 +0000 Subject: [PATCH] lib: Implement status variable Matcher now keeps track of why it failed Signed-off-by: Quentin Young --- lib/.command.h.swo | Bin 16384 -> 0 bytes lib/command_match.c | 82 +++++++++++++++++++++++------------------- lib/command_match.h | 16 ++++----- lib/grammar_sandbox.c | 22 +++++++++--- 4 files changed, 70 insertions(+), 50 deletions(-) delete mode 100644 lib/.command.h.swo diff --git a/lib/.command.h.swo b/lib/.command.h.swo deleted file mode 100644 index 71a42cc20a022a18e2d1af9455f52606f192dfa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHOU5p!76`r<0nwGQ`Jn$od4#~@A@%|;-lx0I<;`Q#1vi4dYdy@?k*6hr+J!CxN z%#6M3Mkye8K_U_e2`W&f_MtqqARgfXBm@Wv34sJWAS6Jdz!QifAt8Q3`Ocj?-m#r* zQuV1~EPdL{z2}~L&UenebMLXUx42`J>52Je4WGv}?bvf)z4ZKt@7KPyp=ox%+xPkr z_Z<0ggy+pg=N1bE5y2>fciB6*WOR&wo_^j_Uu)ME}24zoGhH zndtwQ>VL25Ur`RF`c-rOCubmMAZH+FAZH+FAZH+FAZH+FAZH+FAZOtJk^#%nv>A9V z@6-7HKfV9odQ{VX0z3yi3p@qv180E0JfdkY0XKoq0wv%W@ck2-_9ftpKm|As{P?Y! z_9E~#;054wKm>%q$AB`h2rK|6fct<~AJ(+r06znM3cLtB13V4f00htgJ_MWx-U&Pm zJOupxAx(Q3_&x9);OoFkz~_Na0@r{ZPy?O>3czV#2Kd8qP5UMAbKuKB8<+w9^dNi# zJ_URfSOFdY{&-B&z6;z0Y~XR=LEu+!!JNQ#;3L2Z;MZ>kmw*kN1^)3S_y@cI+yE{D zr+`}zXxcA;XMg}$2i^m`f_laefMo@N&`BD37MoE0-GiQ@GJTW&M3bF-8b#PAFnrLQ$tmg3n>{B9lVWZkCRf_s}gwaZ} zl}vrzn2=1>!i+n~al(xJS8|DgDNkfMPRNPTvbwG}RBMB+nMgLCLJl1taA*_cmv1xI z@?lJ-<{BS7;SVNTCM+6`<`E-zs+F-t!FHCbTjm@(s9GX%V0SFPovwQJjE5{w%yyR{ znY8B###3m&hO1=}eq2Xz<$;!!t_)-4oJxkmW^C*Dq|9 zvf^RfZN}D~Cnyr0uqU^$E2RrHJuCl|*b6P*^89IGqf#%`*7f3O0vK=ju?Sn1jeU>v zHe>frZItAsK9EQ2l;p+IZgEpLDoy+&wFROV#c&RBa(%ighFQ%cc@=>%*^C9cKIR%8 zvs&1`wbF%#ibZN;#?-JyYhth8&W_5ANZuq<5@xBkW279BeA}2J9Jrt;V_R{%vTlr} zK~cVDl+2oFSy+w6a~mkNxMco!c4?PfBu|3h)1`NI?X@Ba#d& zZdZ4W$_9>4MhiGP3J%>8hKu{=b;SR8__*K#yCg~~U1RDZt z1Q}KB?|C=`Zed^aBUZwCZr_=l;sUtmh}d$yNIG6F)$rD+;EiW&;do8Rjdi15!7-QC zw`-(RRj<{JVq;6MQMFO4Zkr`|U@FJpD^GaIsBdmJ>ZDh8>5^WnLErAGWCJHt!bags z8e9?D)1j z+RI08Bzf1s3dDNX`2PPR+?%i9-p#-NPrpC^2JZQnf%Cw-fp-Ca!yW(6zz>0M0-pgs z4cNd6@CfiS?)={dZUSv!75E_V81N|YJIwQ2;Cnz?6ZiuDeE_fxyFmWQ8ORyP8ORyP z8ORyP8ORyP8ORxUqcLzw__*qDF=+Cl&$oGTfXkP!3P-9O)wIJ^u0fnUZ--Bwq_!9A z;dabb2PK`URmg(Hs;q5gTaz&ba_y_xfm~yqx#k9)zM6Y zz;#et#<-@sf6|enTx@D4Ws_!vZ__4)$K1^dCsy!un0?$$HW-EKE((eF6ujpQbe?L&dqavDV zqFFqEq1*Lnd;`DhcnoHiIlsE18{n%m{Eu_1ozN?5zJ~^6Q%7b3TcQepDE7>ZhifF^ z;wwy=LCze8GEF>jAZ(OFkRr11+Jqk{`$Cf}ixo)u#TC8T(bJg!vv*bcnzUhwNIU-r D#5D@v diff --git a/lib/command_match.c b/lib/command_match.c index 6923da776b..5ba1c1b6e7 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -54,46 +54,41 @@ static enum match_type match_variable (struct graph_node *, const char *); /* matching functions */ +static enum matcher_rv matcher_result_value; -struct cmd_element * -match_command (struct graph_node *start, const char *line, struct list **argv) +enum matcher_rv +match_command (struct graph_node *start, + const char *line, + struct list **argvv, + struct cmd_element **el) { + matcher_result_value = MATCHER_NO_MATCH; // parse command vector vline = cmd_make_strvec (line); for (unsigned int i = 0; i < vector_active(start->children); i++) { - // call recursive builder on each starting child - *argv = match_command_r(vector_slot(start->children, i), vline, 0); - // if any of them succeed, return their argv - // since all command DFA's must begin with a word, there can only be - // one valid return value - if (*argv) break; + // call recursive matcher on each starting child + *argvv = match_command_r(vector_slot(start->children, i), vline, 0); + if (*argvv) break; } - // walk the list, find the END_GN, return that - if (*argv) { + if (*argvv) { struct listnode *ln; struct graph_node *gn; - char buf[50]; - for (ALL_LIST_ELEMENTS_RO(*argv,ln,gn)) { - describe_node(gn, buf, 50); - fprintf(stderr, "%s[%d]\n", buf, gn->type); - if (gn->type == END_GN) - return gn->element; - } - assert(0); + for (ALL_LIST_ELEMENTS_RO(*argvv,ln,gn)) + if (gn->type == END_GN) { + *el = gn->element; + break; + } + assert(el); } - return NULL; + return matcher_result_value; } /** - * Matches a given input line against a DFA. - * - * Builds an argument list given a DFA and a matching input line. This function - * should be passed the start node of the DFA, a matching input line, and the - * index of the first token in the input line. + * Builds an argument list given a DFA and a matching input line. * * First the function determines if the node it is passed matches the first * token of input. If it does not, it returns NULL. If it does match, then it @@ -177,7 +172,7 @@ match_command_r (struct graph_node *start, vector vline, unsigned int n) else continue; } - // else recurse on node + // else recurse on candidate child node struct list *result = match_command_r (gn, vline, n+1); // save the best match, subtle logic at play here @@ -200,16 +195,23 @@ match_command_r (struct graph_node *start, vector vline, unsigned int n) } } - if (ambiguous) { - list_delete(bestmatch); - bestmatch = NULL; - } - if (bestmatch) { - // copy current node, set arg and prepend to bestmatch - struct graph_node *curr = copy_node(start); - curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, token); - list_add_node_prev (bestmatch, bestmatch->head, curr); + if (ambiguous) { + list_delete(bestmatch); + bestmatch = NULL; + matcher_result_value = MATCHER_AMBIGUOUS; + } + else { + // copy current node, set arg and prepend to bestmatch + struct graph_node *curr = copy_node(start); + curr->arg = XSTRDUP(MTYPE_CMD_TOKENS, token); + list_add_node_prev (bestmatch, bestmatch->head, curr); + matcher_result_value = MATCHER_OK; + } + } + else { + if (n+1 == vector_active(vline) && matcher_result_value == MATCHER_NO_MATCH) + matcher_result_value = MATCHER_INCOMPLETE; } // cleanup @@ -271,9 +273,13 @@ match_command_complete (struct graph_node *start, const char *line) * next = set of all nodes reachable from all nodes in `matched` */ list_free (current); - cmd_free_strvec(vline); + matcher_result_value = + idx + 1 == vector_active(vline) && next->count ? + MATCHER_OK : + MATCHER_NO_MATCH; + return next; } @@ -329,13 +335,15 @@ score_precedence (enum graph_node_type type) { switch (type) { - // some of these are mutually exclusive, order is important + // some of these are mutually exclusive, so they share + // the same precedence value case IPV4_GN: case IPV4_PREFIX_GN: case IPV6_GN: case IPV6_PREFIX_GN: - case RANGE_GN: case NUMBER_GN: + return 1; + case RANGE_GN: return 2; case WORD_GN: return 3; diff --git a/lib/command_match.h b/lib/command_match.h index 8ad7ab0556..895a678dce 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -18,12 +18,10 @@ enum filter_type /* matcher result value. */ enum matcher_rv { - MATCHER_OK, - MATCHER_COMPLETE, - MATCHER_INCOMPLETE, MATCHER_NO_MATCH, + MATCHER_INCOMPLETE, MATCHER_AMBIGUOUS, - MATCHER_EXCEED_ARGC_MAX + MATCHER_OK, }; /* Completion match types. */ @@ -42,7 +40,6 @@ enum match_type ( (matcher_rv) == MATCHER_INCOMPLETE \ || (matcher_rv) == MATCHER_NO_MATCH \ || (matcher_rv) == MATCHER_AMBIGUOUS \ - || (matcher_rv) == MATCHER_EXCEED_ARGC_MAX \ ) /** @@ -50,11 +47,12 @@ enum match_type * * @param DFA to match against * @param input string - * @param pointer to argv pointer - * @return cmd_element found, or NULL if there is no match. + * @param pointer which will be pointed at argv upon match + * @param pointer which will be pointed at matching cmd_element upon match + * @return result of matcher run */ -struct cmd_element * -match_command (struct graph_node *, const char *, struct list **); +enum matcher_rv +match_command (struct graph_node *, const char *, struct list **, struct cmd_element **); /** * Compiles next-hops for a given line of user input. diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index c53811e062..0eb8d69cee 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -77,9 +77,11 @@ DEFUN (grammar_test_match, "attempt to match input on DFA\n" "command to match") { + const char *line = argv_concat(argv, argc, 0); + struct list *argvv = NULL; - const char *command = argv_concat(argv, argc, 0); - struct cmd_element *element = match_command (nodegraph, command, &argvv); + struct cmd_element *element = NULL; + enum matcher_rv result = match_command (nodegraph, line, &argvv, &element); if (element) { fprintf(stderr, "Matched: %s\n", element->string); @@ -89,8 +91,20 @@ DEFUN (grammar_test_match, fprintf(stderr, "%s -- %s\n", gn->text, gn->arg); } else { - fprintf(stderr, "Returned NULL\n"); - return CMD_SUCCESS; + switch (result) { + case MATCHER_NO_MATCH: + fprintf(stderr, "%% Unknown command\n"); + break; + case MATCHER_INCOMPLETE: + fprintf(stderr, "%% Incomplete command\n"); + break; + case MATCHER_AMBIGUOUS: + fprintf(stderr, "%% Ambiguous command\n"); + break; + default: + fprintf(stderr, "%% Unknown error\n"); + break; + } } return CMD_SUCCESS; -- 2.39.5