diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ffa9b7..f530b23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,15 @@ * [3.3.2](#332) Aug 27 2017 * [3.3.1](#331) June 7 2017 +## Refine branch + +* Break-out RFC 7950 Section 6.1 tokenization + * This enables full string lexical parsing of some rules previously not fully compliant, including: + * refine, uses-augment, augment, if-feature, type, base. + * Also solves previous tokenization issues + * [String concatenation in YANG model leads to syntax error ](https://github.com/clicon/clixon/issues/265) + * [Can't use + symbol in the enum statement without quotes](https://github.com/clicon/clixon/issues/241) + ## 5.8.0 Planned: July 2022 @@ -122,6 +131,8 @@ Developers may need to change their code ### Corrected Bugs +* Fixed: [Can't use + symbol in the enum statement without quotes](https://github.com/clicon/clixon/issues/241) +* Fixed: [String concatenation in YANG model leads to syntax error ](https://github.com/clicon/clixon/issues/265) * Fixed: ["autocli:hide-show" extension cause bug in xmldb_put method #343](https://github.com/clicon/clixon/issues/343) * Fixed: [Schema Ambiguity Error with openconfig-system re: NTP](https://github.com/clicon/clixon/issues/334) * Fixed: [YANG mandatory statements within case nodes do not work](https://github.com/clicon/clixon/issues/344) diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index c51cd979..281274d6 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -229,6 +229,7 @@ int yang_stats(yang_stmt *y, uint64_t *nrp, size_t *szp); yang_stmt *yspec_new(void); yang_stmt *ys_new(enum rfc_6020 keyw); yang_stmt *ys_prune(yang_stmt *yp, int i); +int ys_prune_self(yang_stmt *ys); int ys_free1(yang_stmt *ys, int self); int ys_free(yang_stmt *ys); int ys_cp(yang_stmt *nw, yang_stmt *old); diff --git a/lib/clixon/clixon_yang_parse_lib.h b/lib/clixon/clixon_yang_parse_lib.h index 1072229e..a2cc6a4c 100644 --- a/lib/clixon/clixon_yang_parse_lib.h +++ b/lib/clixon/clixon_yang_parse_lib.h @@ -59,6 +59,6 @@ int yang_spec_parse_file(clicon_handle h, char *filename, yang_stmt *yspe int yang_spec_load_dir(clicon_handle h, char *dir, yang_stmt *yspec); int ys_parse_date_arg(char *datearg, uint32_t *dateint); cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype); -int ys_parse_sub(yang_stmt *ys, char *extra); +int ys_parse_sub(yang_stmt *ys, const char *filename, char *extra); #endif /* _CLIXON_YANG_LIB_H_ */ diff --git a/lib/src/Makefile.in b/lib/src/Makefile.in index f300cf7b..66096ce9 100644 --- a/lib/src/Makefile.in +++ b/lib/src/Makefile.in @@ -77,7 +77,7 @@ SRC = clixon_sig.c clixon_uid.c clixon_log.c clixon_err.c clixon_event.c \ clixon_xml.c clixon_xml_io.c clixon_xml_sort.c clixon_xml_map.c clixon_xml_vec.c \ clixon_xml_bind.c clixon_json.c clixon_proc.c \ clixon_yang.c clixon_yang_type.c clixon_yang_module.c \ - clixon_yang_parse_lib.c clixon_yang_parse_sub.c \ + clixon_yang_parse_lib.c clixon_yang_sub_parse.c \ clixon_yang_cardinality.c clixon_xml_changelog.c clixon_xml_nsctx.c \ clixon_path.c clixon_validate.c \ clixon_hash.c clixon_options.c clixon_data.c clixon_plugin.c \ @@ -95,7 +95,8 @@ YACCOBJS = lex.clixon_xml_parse.o clixon_xml_parse.tab.o \ lex.clixon_api_path_parse.o clixon_api_path_parse.tab.o \ lex.clixon_instance_id_parse.o clixon_instance_id_parse.tab.o \ lex.clixon_text_syntax_parse.o clixon_text_syntax_parse.tab.o \ - lex.clixon_if_feature_parse.o clixon_if_feature_parse.tab.o + lex.clixon_yang_sub_parse.o clixon_yang_sub_parse.tab.o \ + lex.clixon_yang_schemanode_parse.o clixon_yang_schemanode_parse.tab.o # Generated src GENSRC = build.c @@ -120,14 +121,15 @@ endif clean: rm -f $(OBJS) $(MYLIBLINK) $(MYLIBSTATIC) $(MYLIBDYNAMIC) $(GENOBJS) $(GENSRC) *.core - rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co] - rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co] - rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co] - rm -f clixon_xpath_parse.tab.[ch] clixon_xpath_parse.[co] - rm -f clixon_api_path_parse.tab.[ch] clixon_api_path_parse.[co] - rm -f clixon_instance_id_parse.tab.[ch] clixon_instance_id_parse.[co] - rm -f clixon_text_syntax_parse.tab.[ch] clixon_text_syntax_parse.[co] - rm -f clixon_if_feature_parse.tab.[ch] clixon_if_feature_parse.[co] + rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.[o] + rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[o] + rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[o] + rm -f clixon_xpath_parse.tab.[ch] clixon_xpath_parse.[o] + rm -f clixon_api_path_parse.tab.[ch] clixon_api_path_parse.[o] + rm -f clixon_instance_id_parse.tab.[ch] clixon_instance_id_parse.[o] + rm -f clixon_text_syntax_parse.tab.[ch] clixon_text_syntax_parse.[o] + rm -f clixon_yang_sub_parse.tab.[ch] clixon_yang_sub_parse.[o] + rm -f clixon_yang_schemanode_parse.tab.[ch] clixon_yang_schemanode_parse.[o] rm -f lex.clixon_xml_parse.c rm -f lex.clixon_yang_parse.c rm -f lex.clixon_json_parse.c @@ -135,7 +137,7 @@ clean: rm -f lex.clixon_api_path_parse.c rm -f lex.clixon_instance_id_parse.c rm -f lex.clixon_text_syntax_parse.c - rm -f lex.clixon_if_feature_parse.c + rm -f lex.clixon_yang_sub_parse.c rm -f *.gcda *.gcno *.gcov # coverage ############################################################################# @@ -241,17 +243,30 @@ clixon_text_syntax_parse.tab.c: clixon_text_syntax_parse.tab.h lex.clixon_text_syntax_parse.o : lex.clixon_text_syntax_parse.c clixon_text_syntax_parse.tab.h $(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $< -# if-feature-expr parser -lex.clixon_if_feature_parse.c : clixon_if_feature_parse.l clixon_if_feature_parse.tab.h - $(LEX) -Pclixon_if_feature_parse clixon_if_feature_parse.l # -d is debug +# yang-sub parser +lex.clixon_yang_sub_parse.c : clixon_yang_sub_parse.l clixon_yang_sub_parse.tab.h + $(LEX) -Pclixon_yang_sub_parse clixon_yang_sub_parse.l # -d is debug -clixon_if_feature_parse.tab.h: clixon_if_feature_parse.y - $(YACC) -l -d -b clixon_if_feature_parse -p clixon_if_feature_parse clixon_if_feature_parse.y # -t is debug +clixon_yang_sub_parse.tab.h: clixon_yang_sub_parse.y + $(YACC) -l -d -b clixon_yang_sub_parse -p clixon_yang_sub_parse clixon_yang_sub_parse.y # -t is debug # extra rule to avoid parallell yaccs -clixon_if_feature_parse.tab.c: clixon_if_feature_parse.tab.h +clixon_yang_sub_parse.tab.c: clixon_yang_sub_parse.tab.h -lex.clixon_if_feature_parse.o : lex.clixon_if_feature_parse.c clixon_if_feature_parse.tab.h +lex.clixon_yang_sub_parse.o : lex.clixon_yang_sub_parse.c clixon_yang_sub_parse.tab.h + $(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $< + +# descendant-schema-nodeid parser +lex.clixon_yang_schemanode_parse.c : clixon_yang_schemanode_parse.l clixon_yang_schemanode_parse.tab.h + $(LEX) -Pclixon_yang_schemanode_parse clixon_yang_schemanode_parse.l # -d is debug + +clixon_yang_schemanode_parse.tab.h: clixon_yang_schemanode_parse.y + $(YACC) -l -d -b clixon_yang_schemanode_parse -p clixon_yang_schemanode_parse clixon_yang_schemanode_parse.y # -t is debug + +# extra rule to avoid parallell yaccs +clixon_yang_schemanode_parse.tab.c: clixon_yang_schemanode_parse.tab.h + +lex.clixon_yang_schemanode_parse.o : lex.clixon_yang_schemanode_parse.c clixon_yang_schemanode_parse.tab.h $(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $< distclean: clean diff --git a/lib/src/clixon_text_syntax_parse.l b/lib/src/clixon_text_syntax_parse.l index 11c4f73b..70dd5ccf 100644 --- a/lib/src/clixon_text_syntax_parse.l +++ b/lib/src/clixon_text_syntax_parse.l @@ -94,7 +94,6 @@ int clixon_text_syntax_parsewrap(void) [^\n\r \t\[\]\{\}\;\"]+ { clixon_text_syntax_parselval.string = strdup(yytext); return TOKEN; } -. { return -1; } \n { _TS->ts_linenum++; BEGIN(_TS->ts_lex_state);} <> { return MY_EOF; } @@ -106,7 +105,6 @@ int clixon_text_syntax_parsewrap(void) \" { BEGIN(_TS->ts_lex_state); return *yytext; } [^\n\"]+ { clixon_text_syntax_parselval.string = strdup(yytext); return TOKEN; } -. { return -1; } %% diff --git a/lib/src/clixon_xml_nsctx.c b/lib/src/clixon_xml_nsctx.c index 099272e9..22bb27be 100644 --- a/lib/src/clixon_xml_nsctx.c +++ b/lib/src/clixon_xml_nsctx.c @@ -95,7 +95,7 @@ xml_nsctx_namespace_netconf_default(clicon_handle h) /*! Create and initialize XML namespace context * @param[in] prefix Namespace prefix, or NULL for default - * @param[in] ns Set this namespace. If NULL create empty nsctx + * @param[in] ns Set this namespace. If NULL create empty nsctx * @retval nsc Return namespace context in form of a cvec * @retval NULL Error * @code diff --git a/lib/src/clixon_xml_parse.l b/lib/src/clixon_xml_parse.l index a33c5c37..d6970e5e 100644 --- a/lib/src/clixon_xml_parse.l +++ b/lib/src/clixon_xml_parse.l @@ -139,7 +139,6 @@ ncname {namestart}{namechar}* \r { clixon_xml_parselval.string = "\n";return WHITESPACE; } \n { clixon_xml_parselval.string = "\n"; _XY->xy_linenum++;return WHITESPACE; } [^&\r\n \t\<]+ { clixon_xml_parselval.string = yytext; return CHARDATA; /* Optimized */} -. { clixon_xml_parselval.string = yytext; return CHARDATA; } /* @see xml_chardata_encode */ "amp;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "&"; return CHARDATA;} diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index f99fc834..a1532442 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -80,7 +80,7 @@ #include "clixon_data.h" #include "clixon_options.h" #include "clixon_yang_parse.h" -#include "clixon_yang_parse_sub.h" +#include "clixon_yang_sub_parse.h" #include "clixon_yang_parse_lib.h" #include "clixon_yang_cardinality.h" #include "clixon_yang_type.h" @@ -673,6 +673,7 @@ ys_free1(yang_stmt *ys, * @retval NULL No such node, nothing done * @retval yc returned orphaned yang node * @see ys_free Deallocate yang node + * @see ys_prune_self Prune child itself * @note Do not call this in a loop of yang children (unless you know what you are doing) */ yang_stmt * @@ -705,7 +706,7 @@ ys_prune(yang_stmt *yp, * @see ys_free Deallocate yang node * @note Do not call this in a loop of yang children (unless you know what you are doing) */ -static int +int ys_prune_self(yang_stmt *ys) { int retval = -1; @@ -2800,6 +2801,8 @@ yang_features(clicon_handle h, int i; int j; yang_stmt *ys = NULL; + yang_stmt *ymod; + const char *mainfile = NULL; int ret; i = 0; @@ -2807,8 +2810,10 @@ yang_features(clicon_handle h, ys = yt->ys_stmt[i]; if (ys->ys_keyword == Y_IF_FEATURE){ /* Parse the if-feature-expr string using yang sub-parser */ + if ((ymod = ys_module(ys)) != NULL) + mainfile = yang_filename_get(ymod); ret = 0; - if (yang_if_feature_parse(yang_argument_get(ys), ys, 1, &ret) < 0) + if (yang_subparse(yang_argument_get(ys), ys, YA_IF_FEATURE, mainfile, 1, &ret) < 0) goto done; clicon_debug(1, "%s %s %d", __FUNCTION__, yang_argument_get(ys), ret); if (ret == 0) @@ -2938,6 +2943,7 @@ yang_datanode(yang_stmt *ys) /*! All the work for schema_nodeid functions both absolute and descendant * * @param[in] yn Yang node. For absolute schemanodeids this should be a module, otherwise any yang + * @param[in] yspec Yang spec (Cornsercase if yn is pruned) * @param[in] cvv Schema-node path encoded as a name/value pair list. * @param[in] nsc Namespace context from yang for the prefixes (names) of cvv * @param[out] yres Result yang statement node, or NULL if not found @@ -2954,6 +2960,7 @@ yang_datanode(yang_stmt *ys) */ static int schema_nodeid_iterate(yang_stmt *yn, + yang_stmt *yspec, cvec *nodeid_cvv, cvec *nsc, yang_stmt **yres) @@ -2966,9 +2973,7 @@ schema_nodeid_iterate(yang_stmt *yn, yang_stmt *yp; cg_var *cv; char *ns; - yang_stmt *yspec; - yspec = ys_spec(yn); yp = yn; /* Iterate over node identifiers /prefix:id/... */ cv = NULL; @@ -3050,8 +3055,11 @@ yang_abs_schema_nodeid(yang_stmt *yn, yang_stmt *ymod; char *str; + if ((yspec = ys_spec(yn)) == NULL){ + clicon_err(OE_YANG, EINVAL, "No yang spec"); + goto done; + } *yres = NULL; - yspec = ys_spec(yn); /* check absolute schema_nodeid */ if (schema_nodeid[0] != '/'){ clicon_err(OE_YANG, EINVAL, "absolute schema nodeid should start with /"); @@ -3099,7 +3107,7 @@ yang_abs_schema_nodeid(yang_stmt *yn, goto done; } /* Iterate through cvv to find schemanode using ymod as starting point (since it is absolute) */ - if (schema_nodeid_iterate(ymod, nodeid_cvv, nsc, yres) < 0) + if (schema_nodeid_iterate(ymod, yspec, nodeid_cvv, nsc, yres) < 0) goto done; ok: retval = 0; @@ -3112,9 +3120,10 @@ yang_abs_schema_nodeid(yang_stmt *yn, } /*! Given a descendant schema-nodeid (eg a/b/c) find matching yang spec - * @param[in] yn Yang node + * @param[in] yn Yang node (must be part of yspec tree, cannot be "dangling") * @param[in] schema_nodeid Descendant schema-node-id, ie a/b * @param[in] keyword A schemode of this type, or -1 if any + * @param[in] ns Namespace context * @param[out] yres First yang node matching schema nodeid * @retval 0 OK * @retval -1 Error, with clicon_err called @@ -3130,12 +3139,17 @@ yang_desc_schema_nodeid(yang_stmt *yn, cvec *nodeid_cvv = NULL; cg_var *cv; char *str; + yang_stmt *yspec; cvec *nsc = NULL; if (schema_nodeid == NULL || strlen(schema_nodeid) == 0){ clicon_err(OE_YANG, EINVAL, "nodeid is empty"); goto done; } + if ((yspec = ys_spec(yn)) == NULL){ + clicon_err(OE_YANG, EINVAL, "No yang spec"); + goto done; + } *yres = NULL; /* check absolute schema_nodeid */ if (schema_nodeid[0] == '/'){ @@ -3161,11 +3175,13 @@ yang_desc_schema_nodeid(yang_stmt *yn, cv_name_set(cv, NULL); } } - /* Make a namespace context from yang for the prefixes (names) of nodeid_cvv */ + /* Make a namespace context from yang for the prefixes (names) of nodeid_cvv + * Requires yn exist in hierarchy + */ if (xml_nsctx_yang(yn, &nsc) < 0) goto done; /* Iterate through cvv to find schemanode using yn as relative starting point */ - if (schema_nodeid_iterate(yn, nodeid_cvv, nsc, yres) < 0) + if (schema_nodeid_iterate(yn, yspec, nodeid_cvv, nsc, yres) < 0) goto done; ok: retval = 0; diff --git a/lib/src/clixon_yang_parse.l b/lib/src/clixon_yang_parse.l index 6ce16cf5..3e785020 100644 --- a/lib/src/clixon_yang_parse.l +++ b/lib/src/clixon_yang_parse.l @@ -119,7 +119,6 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* anydata { BEGIN(STRARG); return K_ANYDATA; } anyxml { BEGIN(STRARG); return K_ANYXML; } argument { BEGIN(STRARG); return K_ARGUMENT; } -base { BEGIN(STRARG); return K_BASE; } belongs-to { BEGIN(STRARG); return K_BELONGS_TO; } bit { BEGIN(STRARG); return K_BIT; } case { BEGIN(STRARG); return K_CASE; } @@ -137,12 +136,9 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* module { BEGIN(STRARG); return K_MODULE; } notification { BEGIN(STRARG); return K_NOTIFICATION; } prefix { BEGIN(STRARG); return K_PREFIX; } -refine { BEGIN(STRARG); return K_REFINE; } rpc { BEGIN(STRARG); return K_RPC; } submodule { BEGIN(STRARG); return K_SUBMODULE; } -type { BEGIN(STRARG); return K_TYPE; } typedef { BEGIN(STRARG); return K_TYPEDEF; } -uses { BEGIN(STRARG); return K_USES; } /* RFC 7950 keywords using boolean string arguments */ config { BEGIN(BOOLEAN); return K_CONFIG; } @@ -157,6 +153,7 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* /* RFC 7950 keywords using strings */ augment { BEGIN(STRING); return K_AUGMENT; } +base { BEGIN(STRING); return K_BASE; } contact { BEGIN(STRING); return K_CONTACT; } default { BEGIN(STRING); return K_DEFAULT; } description { BEGIN(STRING); return K_DESCRIPTION; } @@ -178,13 +175,16 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* path { BEGIN(STRING); return K_PATH; } pattern { BEGIN(STRING); return K_PATTERN; } presence { BEGIN(STRING); return K_PRESENCE; } +type { BEGIN(STRING); return K_TYPE; } unique { BEGIN(STRING); return K_UNIQUE; } range { BEGIN(STRING); return K_RANGE; } reference { BEGIN(STRING); return K_REFERENCE; } +refine { BEGIN(STRING); return K_REFINE; } revision { BEGIN(STRING); return K_REVISION; } revision-date { BEGIN(STRING); return K_REVISION_DATE; } status { BEGIN(STRING); return K_STATUS; } units { BEGIN(STRING); return K_UNITS; } +uses { BEGIN(STRING); return K_USES; } when { BEGIN(STRING); return K_WHEN; } yang-version { BEGIN(STRING); return K_YANG_VERSION; } : { return *yytext; } @@ -239,7 +239,6 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* ; { BEGIN(KEYWORD); return *yytext; } {identifier} { clixon_yang_parselval.string = strdup(yytext); return IDENTIFIER;} - . { return *yytext; } \{ { BEGIN(KEYWORD); return *yytext; } @@ -247,7 +246,7 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]* \" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return *yytext; } \' { _YY->yy_lex_string_state =STRING; BEGIN(STRINGSQ); return *yytext; } \+ { return *yytext; } -[^\"\'\+\{\;\n \t\r]+ { clixon_yang_parselval.string = strdup(yytext); /* XXX [.]+ */ +[^\"\'\{\;\n \t\r]+ { clixon_yang_parselval.string = strdup(yytext); /* XXX [.]+ */ return CHARS;} \\ { _YY->yy_lex_state = STRINGDQ; BEGIN(DQESC); } diff --git a/lib/src/clixon_yang_parse.y b/lib/src/clixon_yang_parse.y index e778479e..a29e0536 100644 --- a/lib/src/clixon_yang_parse.y +++ b/lib/src/clixon_yang_parse.y @@ -68,15 +68,12 @@ %type qstring %type string %type integer_value_str -%type identifier_ref +%type identifier_ref_arg_str %type if_feature_expr_str -%type abs_schema_nodeid -%type desc_schema_nodeid_strs -%type desc_schema_nodeid_str -%type desc_schema_nodeid -%type node_identifier +%type refine_arg_str +%type augment_arg_str +%type uses_augment_arg_str %type identifier_str -%type identifier_ref_str %type bool_str /* rfc 6020 keywords @@ -293,7 +290,7 @@ ystack_push(clixon_yang_yacc *yy, * @note consumes 'argument' and 'extra' which assumes it is malloced and not freed by caller */ static yang_stmt * -ysp_add(clixon_yang_yacc *yy, +ysp_add(clixon_yang_yacc *yy, enum rfc_6020 keyword, char *argument, char *extra) @@ -318,7 +315,7 @@ ysp_add(clixon_yang_yacc *yy, if (yn_insert(yn, ys) < 0) /* Insert into hierarchy */ goto err; yang_linenum_set(ys, yy->yy_linenum); /* For error/debugging */ - if (ys_parse_sub(ys, extra) < 0) /* Check statement-specific syntax */ + if (ys_parse_sub(ys, yy->yy_name, extra) < 0) /* Check statement-specific syntax */ goto err2; /* dont free since part of tree */ return ys; err: @@ -657,7 +654,7 @@ identity_substmt : if_feature_stmt { _PARSE_DEBUG("identity-substmt -> if-feat | { _PARSE_DEBUG("identity-substmt -> "); } ; -base_stmt : K_BASE identifier_ref_str stmtend +base_stmt : K_BASE identifier_ref_arg_str stmtend { if (ysp_add(_yy, Y_BASE, $2, NULL)== NULL) _YYERROR("base_stmt"); _PARSE_DEBUG("base-stmt -> BASE identifier-ref-arg-str"); } ; @@ -728,10 +725,10 @@ typedef_substmt : type_stmt { _PARSE_DEBUG("typedef-substmt -> type-stm ; /* Type */ -type_stmt : K_TYPE identifier_ref_str ';' +type_stmt : K_TYPE identifier_ref_arg_str ';' { if (ysp_add(_yy, Y_TYPE, $2, NULL) == NULL) _YYERROR("type_stmt"); _PARSE_DEBUG("type-stmt -> TYPE identifier-ref-arg-str ;");} - | K_TYPE identifier_ref_str + | K_TYPE identifier_ref_arg_str { if (ysp_add_push(_yy, Y_TYPE, $2, NULL) == NULL) _YYERROR("type_stmt"); } '{' type_body_stmts '}' @@ -1298,14 +1295,14 @@ anyxml_substmt : when_stmt { _PARSE_DEBUG("anyxml-substmt -> when-stmt ; /* uses-stmt = uses-keyword identifier-ref-arg-str */ -uses_stmt : K_USES identifier_ref_str ';' +uses_stmt : K_USES identifier_ref_arg_str ';' { if (ysp_add(_yy, Y_USES, $2, NULL) == NULL) _YYERROR("uses_stmt"); - _PARSE_DEBUG("uses-stmt -> USES id-arg-str ;"); } - | K_USES identifier_ref_str + _PARSE_DEBUG("uses-stmt -> USES identifier-ref-arg-str ;"); } + | K_USES identifier_ref_arg_str { if (ysp_add_push(_yy, Y_USES, $2, NULL) == NULL) _YYERROR("uses_stmt"); } '{' uses_substmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("uses_stmt"); - _PARSE_DEBUG("uses-stmt -> USES id-arg-str { uses-substmts }"); } + _PARSE_DEBUG("uses-stmt -> USES identifier-ref-arg-str { uses-substmts }"); } ; uses_substmts : uses_substmts uses_substmt @@ -1326,12 +1323,12 @@ uses_substmt : when_stmt { _PARSE_DEBUG("uses-substmt -> when-stmt") ; /* refine-stmt = refine-keyword sep refine-arg-str */ -refine_stmt : K_REFINE desc_schema_nodeid_strs ';' +refine_stmt : K_REFINE refine_arg_str ';' { if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt"); _PARSE_DEBUG("refine-stmt -> REFINE id-arg-str ;"); } - | K_REFINE desc_schema_nodeid_strs + | K_REFINE refine_arg_str '{' { if (ysp_add_push(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt"); } - '{' refine_substmts '}' + refine_substmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("refine_stmt"); _PARSE_DEBUG("refine-stmt -> REFINE id-arg-str { refine-substmts }"); } ; @@ -1356,21 +1353,28 @@ refine_substmt : if_feature_stmt { _PARSE_DEBUG("refine-substmt -> if-feature- | { _PARSE_DEBUG("refine-substmt -> "); } ; -/* uses-augment-stmt = augment-keyword augment-arg-str -uses_augment_stmt : K_AUGMENT desc_schema_nodeid_strs -*/ -uses_augment_stmt : K_AUGMENT string - { if (ysp_add_push(_yy, Y_AUGMENT, $2, NULL) == NULL) _YYERROR("uses_augment_stmt"); } +/* refine-arg-str = < a string that matches the rule refine-arg > + * @see yang_schema_nodeid_subparse sub-parser + */ +refine_arg_str : string + { $$ = $1; + _PARSE_DEBUG("refine-arg-str -> < a string that matches the rule refine-arg >"); } + ; + +/* uses-augment-stmt = augment-keyword uses-augment-arg-str + * Same keyword as in augment-stmt, but here is sub of uses + */ +uses_augment_stmt : K_AUGMENT uses_augment_arg_str + { if (ysp_add_push(_yy, Y_AUGMENT, $2, NULL) == NULL) _YYERROR("uses_augment_stmt"); } '{' augment_substmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("uses_augment_stmt"); - _PARSE_DEBUG("uses-augment-stmt -> AUGMENT desc-schema-node-str { augment-substmts }"); } - + _PARSE_DEBUG("uses-augment-stmt -> AUGMENT uses-augment-arg-str { augment-substmts }"); } /* augment-stmt = augment-keyword sep augment-arg-str - * XXX abs-schema-nodeid-str is too difficult, it needs the + semantics -augment_stmt : K_AUGMENT abs_schema_nodeid_strs + * augment_stmt : K_AUGMENT abs_schema_nodeid_strs + * Same keyword as in uses-augment-stmt, but here is sub of (sub)module */ -augment_stmt : K_AUGMENT string +augment_stmt : K_AUGMENT augment_arg_str { if (ysp_add_push(_yy, Y_AUGMENT, $2, NULL) == NULL) _YYERROR("augment_stmt"); } '{' augment_substmts '}' { if (ystack_pop(_yy) < 0) _YYERROR("augment_stmt"); @@ -1396,6 +1400,22 @@ augment_substmt : when_stmt { _PARSE_DEBUG("augment-substmt -> when-stm | { _PARSE_DEBUG("augment-substmt -> "); } ; +/* augment-arg-str = < a string that matches the rule augment-arg > + * @see yang_schema_nodeid_subparse sub-parser + */ +augment_arg_str : string + { $$ = $1; + _PARSE_DEBUG("augment-arg-str -> < a string that matches the rule augment-arg >"); } + ; + +/* uses-augment-arg-str = < a string that matches the rule uses-augment-arg > + * @see yang_schema_nodeid_subparse sub-parser + */ +uses_augment_arg_str : string + { $$ = $1; + _PARSE_DEBUG("uses-augment-arg-str -> < a string that matches the rule uses-augment-arg >"); } + ; + /* when */ when_stmt : K_WHEN string ';' { if (ysp_add(_yy, Y_WHEN, $2, NULL) == NULL) _YYERROR("when_stmt"); @@ -1799,6 +1819,8 @@ output_stmt : K_OUTPUT /* XXX reuse input-substatements since they are same */ _PARSE_DEBUG("output-stmt -> OUTPUT { input-substmts }"); } ; +/* XXX this is not the "string" rule in Section 14, rather it is the string as described in 6.1 + */ string : qstrings { $$=$1; _PARSE_DEBUG("string -> qstrings"); } | ustring { $$=$1; @@ -1844,54 +1866,6 @@ ustring : ustring CHARS { _PARSE_DEBUG1("ustring-> ERRCHARS(%s)", $1); _YYERROR("Invalid string chars"); } ; -abs_schema_nodeid : abs_schema_nodeid '/' node_identifier - { - if (($$=clixon_string_del_join($1, "/", $3)) == NULL) _YYERROR("abs_schema_nodeid"); - free($3); - _PARSE_DEBUG("absolute-schema-nodeid -> absolute-schema-nodeid / node-identifier"); } - | '/' node_identifier - { - if (($$=clixon_string_del_join(NULL, "/", $2)) == NULL) _YYERROR("abs_schema_nodeid"); - free($2); - _PARSE_DEBUG("absolute-schema-nodeid -> / node-identifier"); } - ; - -desc_schema_nodeid_strs : desc_schema_nodeid_strs '+' desc_schema_nodeid_str - { - int len = strlen($1); - $$ = realloc($1, len + strlen($3) + 1); - sprintf($$+len, "%s", $3); - free($3); - _PARSE_DEBUG("desc-schema-nodeid-strs-> desc-schema-nodeid-strs + desc-schema-nodeid-str"); - } - | desc_schema_nodeid_str - { $$=$1; - _PARSE_DEBUG("desc-schema-nodeid-strs-> desc-schema-nodeid-str"); } - ; - -desc_schema_nodeid_str : desc_schema_nodeid - { $$=$1; - _PARSE_DEBUG("descendant-schema-nodeid-str -> descendant-schema-nodeid"); } - | '"' desc_schema_nodeid '"' - { $$=$2; - _PARSE_DEBUG("descendant-schema-nodeid-str -> \" descendant-schema-nodeid \" "); } - | '\'' desc_schema_nodeid '\'' - { $$=$2; - _PARSE_DEBUG("descendant-schema-nodeid-str -> ' descendant-schema-nodeid '"); } - -; - -/* descendant-schema-nodeid */ -desc_schema_nodeid : node_identifier - { $$= $1; - _PARSE_DEBUG("descendant-schema-nodeid -> node_identifier"); } - | node_identifier abs_schema_nodeid - { - if (($$=clixon_string_del_join($1, "", $2)) == NULL) _YYERROR("desc_schema_nodeid"); - free($2); - _PARSE_DEBUG("descendant-schema-nodeid -> node_identifier abs_schema_nodeid"); } - ; - identifier_str : '"' IDENTIFIER '"' { $$ = $2; _PARSE_DEBUG("identifier_str -> \" IDENTIFIER \" ");} | '\'' IDENTIFIER '\'' { $$ = $2; @@ -1900,14 +1874,6 @@ identifier_str : '"' IDENTIFIER '"' { $$ = $2; _PARSE_DEBUG("identifier_str -> IDENTIFIER ");} ; -identifier_ref_str : '"' identifier_ref '"' { $$ = $2; - _PARSE_DEBUG("identifier_ref_str -> \" identifier_ref \" ");} - | '\'' identifier_ref '\'' { $$ = $2; - _PARSE_DEBUG("identifier_ref_str -> ' identifier_ref ' ");} - | identifier_ref { $$ = $1; - _PARSE_DEBUG("identifier_ref_str -> identifier_ref ");} - ; - integer_value_str : '"' INT '"' { $$=$2; } | '\'' INT '\'' { $$=$2; } | INT { $$=$1; } @@ -1922,21 +1888,14 @@ bool_str : '"' BOOL '"' { $$ = $2; ; -/* node-identifier = [prefix ":"] identifier */ -node_identifier : IDENTIFIER - { $$=$1; - _PARSE_DEBUG("identifier-ref-arg-str -> string"); } - | IDENTIFIER ':' IDENTIFIER - { - if (($$=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("node_identifier"); - free($3); - _PARSE_DEBUG("identifier-ref-arg-str -> prefix : string"); } - ; - /* ;;; Basic Rules */ -/* identifier-ref = [prefix ":"] identifier */ -identifier_ref : node_identifier { $$=$1;} +/* identifier-ref-arg-str = < a string that matches the rule idenetifier-ref-arg > + * @see yang_schema_nodeid_subparse sub-parser + */ +identifier_ref_arg_str : string + { $$ = $1; + _PARSE_DEBUG("identifier-ref-arg-str -> < a string that matches the rule identifier-ref-arg >"); } ; /* optsep = *(WSP / line-break) */ diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index 255972f9..8d6947d4 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -97,7 +97,7 @@ #include "clixon_yang_cardinality.h" #include "clixon_plugin.h" #include "clixon_yang_internal.h" -#include "clixon_yang_parse_sub.h" +#include "clixon_yang_sub_parse.h" #include "clixon_yang_parse_lib.h" /* Size of json read buffer when reading from file*/ @@ -562,7 +562,7 @@ yang_expand_uses_node(yang_stmt *yn, goto done; } /* Make a copy of the grouping, then make refinements to this copy - * Note this ygrouping2 object does not gave a parent and does not work in many + * Note this ygrouping2 object does not have a parent and does not work in many * functions which assume a full hierarchy, use the original ygrouping in those cases. */ if ((ygrouping2 = ys_dup(ygrouping)) == NULL) @@ -600,6 +600,11 @@ yang_expand_uses_node(yang_stmt *yn, if (xml_nsctx_yang(ywhen, &wnsc) < 0) goto done; } + /* Note: yang_desc_schema_nodeid() requires ygrouping2 to be in yspec tree, + * cannot be dangling, insert into tree here and then prune immediately after while loop + */ + if (yn_insert(yang_parent_get(ygrouping), ygrouping2) < 0) + goto done; /* Iterate through refinements and modify grouping copy * See RFC 7950 7.13.2 yrt is the refine target node */ @@ -609,7 +614,7 @@ yang_expand_uses_node(yang_stmt *yn, if (yang_keyword_get(yr) != Y_REFINE) continue; /* Find a node */ - if (yang_desc_schema_nodeid(ygrouping, /* Cannot use ygrouping2 */ + if (yang_desc_schema_nodeid(ygrouping2, yang_argument_get(yr), &yrt) < 0) goto done; @@ -622,10 +627,10 @@ yang_expand_uses_node(yang_stmt *yn, /* Do the actual refinement */ if (ys_do_refine(yr, yrt) < 0) goto done; - /* RFC: The argument is a string that identifies a node in the - * grouping. I interpret that as only one node --> break */ - break; } /* while yr */ + /* Note: prune here to make dangling again after while loop */ + if (ys_prune_self(ygrouping2) < 0) + goto done; /* Then copy and insert each child element from ygrouping2 to yn */ k=0; for (j=0; j +#include +#include + +#include "clixon_yang_schemanode_parse.tab.h" /* generated file */ + +/* cligen */ +#include + +/* clicon */ +#include "clixon_queue.h" +#include "clixon_hash.h" +#include "clixon_handle.h" +#include "clixon_yang.h" +#include "clixon_xml.h" +#include "clixon_yang_sub_parse.h" +#include "clixon_yang_schemanode_parse.h" + +/* Redefine main lex function so that you can send arguments to it: _if is added to arg list */ +#define YY_DECL int clixon_yang_schemanode_parselex(void *_if) + +/* Dont use input function (use user-buffer) */ +#define YY_NO_INPUT + +/* typecast macro */ +#define _IF ((clixon_yang_schemanode_yacc *)_if) + +#undef clixon_xml_parsewrap +int clixon_yang_schemanode_parsewrap(void) +{ + return 1; +} + +/* + */ + +%} + +identifier [A-Za-z_][A-Za-z0-9_\-\.]* + +%% + +\n { _IF->if_linenum++; return *yytext; } +: { return *yytext; } +\/ { return *yytext; } +{identifier} { clixon_yang_schemanode_parselval.string = strdup(yytext); + return IDENTIFIER;} +<> { return MY_EOF; } +. { return -1; } + +%% + +/*! Initialize XML scanner. + */ +int +clixon_yang_schemanode_parsel_init(clixon_yang_schemanode_yacc *ife) +{ + BEGIN(INITIAL); + ife->if_lexbuf = yy_scan_string (ife->if_parse_string); + if (0) + yyunput(0, ""); /* XXX: just to use unput to avoid warning */ + return 0; +} + +/*! Exit xml scanner */ +int +clixon_yang_schemanode_parsel_exit(clixon_yang_schemanode_yacc *ife) +{ + yy_delete_buffer(ife->if_lexbuf); + clixon_yang_schemanode_parselex_destroy(); /* modern */ + + return 0; +} diff --git a/lib/src/clixon_yang_schemanode_parse.y b/lib/src/clixon_yang_schemanode_parse.y new file mode 100644 index 00000000..a793cd60 --- /dev/null +++ b/lib/src/clixon_yang_schemanode_parse.y @@ -0,0 +1,198 @@ +/* + * + ***** BEGIN LICENSE BLOCK ***** + + Copyright (C) 2022 Olof Hagsand and Rubicon Communications, LLC(Netgate) + + This file is part of CLIXON. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Alternatively, the contents of this file may be used under the terms of + the GNU General Public License Version 3 or later (the "GPL"), + in which case the provisions of the GPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of the GPL, and not to allow others to + use your version of this file under the terms of Apache License version 2, + indicate your decision by deleting the provisions above and replace them with + the notice and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the Apache License version 2 or the GPL. + + ***** END LICENSE BLOCK ***** + + Just syntax check, return no data + + * descendant-schema-nodeid RFC7950 14 + descendant-schema-nodeid = node-identifier + [absolute-schema-nodeid] + + absolute-schema-nodeid = 1*("/" node-identifier) + + node-identifier = [prefix ":"] identifier + + prefix = identifier + identifier = (ALPHA / "_") + *(ALPHA / DIGIT / "_" / "-" / ".") + + */ +%union { + char *string; + void *stack; + int number; +} + +%token MY_EOF +%token IDENTIFIER + +%start top + +%lex-param {void *_if} /* Add this argument to parse() and lex() function */ +%parse-param {void *_if} + +%{ +/* Here starts user C-code */ + +/* typecast macro */ +#define _IF ((clixon_yang_schemanode_yacc *)_if) +#define _YYERROR(msg) {clicon_err(OE_YANG, 0, "%s", (msg)); YYERROR;} + +#include +#include +#include +#include +#include +#include + +/* cligen */ +#include + +/* clicon */ +#include "clixon_err.h" +#include "clixon_log.h" +#include "clixon_queue.h" +#include "clixon_hash.h" +#include "clixon_string.h" +#include "clixon_handle.h" +#include "clixon_yang.h" +#include "clixon_xml.h" +#include "clixon_yang_module.h" +#include "clixon_xml_vec.h" +#include "clixon_data.h" +#include "clixon_yang_sub_parse.h" +#include "clixon_yang_schemanode_parse.h" + +/* Enable for debugging, steals some cycles otherwise */ +#if 1 +#define _PARSE_DEBUG(s) clicon_debug(1,(s)) +#else +#define _PARSE_DEBUG(s) +#endif + +void +clixon_yang_schemanode_parseerror(void *arg, + char *s) +{ + clixon_yang_schemanode_yacc *ife = (clixon_yang_schemanode_yacc *)arg; + + clicon_err_fn(NULL, 0, OE_YANG, 0, "yang_schemanode_parse: file:%s:%d \"%s\" %s: at or before: %s", + ife->if_mainfile, + ife->if_linenum, + ife->if_parse_string, + s, + clixon_yang_schemanode_parsetext); + return; +} + +%} + +%% + +/* See RFC 7950 Sec 14 refine-arg-str / usage-augment-arg-str */ +top : descendant_schema_nodeid MY_EOF + { + _PARSE_DEBUG("top->descendant-schema-nodeid"); + if (_IF->if_accept == YA_DESC_SCHEMANODEID){ + YYACCEPT; + } + else{ + _YYERROR("descendant-schema-nodeid unexpected"); + } + } + | absolute_schema_nodeid MY_EOF + { + _PARSE_DEBUG("top->absolute-schema-nodeid"); + if (_IF->if_accept == YA_ABS_SCHEMANODEID){ + YYACCEPT; + } + else{ + _YYERROR("absolute-schema-nodeid unexpected"); + } + } + ; + +descendant_schema_nodeid + : node_identifier + { + _PARSE_DEBUG("descendant-schema-nodeid->node-identifier"); + } + | node_identifier absolute_schema_nodeid + { + _PARSE_DEBUG("descendant-schema-nodeid->absolute-schema-nodeid"); + } + ; + +absolute_schema_nodeid + : absolute_schema_nodeid '/' node_identifier + { + _PARSE_DEBUG("absolute-schema-nodeid->absolute-schema-nodeid '/' node-identifier"); + } + | '/' node_identifier + { + _PARSE_DEBUG("absolute-schema-nodeid->'/' node-identifier"); + } + ; + +/* node-identifier = [prefix ":"] identifier */ +node_identifier : identifier + { + _PARSE_DEBUG("node-identifier -> identifier"); + if (_IF->if_accept == YA_ID_REF){ + YYACCEPT; + } + } + | prefix ':' identifier + { + _PARSE_DEBUG("node_identifier -> prefix : identifier"); + if (_IF->if_accept == YA_ID_REF){ + YYACCEPT; + } + } + ; + +prefix : IDENTIFIER + { + _PARSE_DEBUG("prefix -> IDENTIFIER"); + free($1); + } + ; + +identifier : IDENTIFIER + { + _PARSE_DEBUG("identifier -> IDENTIFIER"); + free($1); + } + ; + +%% + diff --git a/lib/src/clixon_yang_parse_sub.c b/lib/src/clixon_yang_sub_parse.c similarity index 50% rename from lib/src/clixon_yang_parse_sub.c rename to lib/src/clixon_yang_sub_parse.c index bf164930..1f3b5c13 100644 --- a/lib/src/clixon_yang_parse_sub.c +++ b/lib/src/clixon_yang_sub_parse.c @@ -54,34 +54,41 @@ #include "clixon_hash.h" #include "clixon_handle.h" #include "clixon_yang.h" -#include "clixon_if_feature_parse.h" +#include "clixon_yang_sub_parse.h" +#include "clixon_yang_schemanode_parse.h" -/*! Invoke yang if-feature sub-parser on string +/*! Invoke yang sub-parser on string * - * @param[in] str If-feature-expr string - * @param[in] ys Yang if-feature statement - * @param[in] linenum Line number context - * @param[out] enabled 0: Disabled, 1: Enabled - * @retval 0 OK - * @retval -1 Error + * @param[in] str yang string + * @param[in] ys Yang statement + * @param[in] accept Sub-parse rule to accept + * @param[in] mainfile Name of main parse file + * @param[in] linenum Line number context in mainfile (assume parse module of ys) + * @param[out] enabled 0: Disabled, 1: Enabled (if present) + * @retval 0 OK + * @retval -1 Error */ int -yang_if_feature_parse(char *str, - yang_stmt *ys, - int linenum, - int *enabled) +yang_subparse(char *str, + yang_stmt *ys, + enum yang_sub_parse_accept accept, + const char *mainfile, + int linenum, + int *enabled) { int retval = -1; - clixon_if_feature_yacc ife = {0,}; + clixon_yang_sub_parse_yacc ife = {0,}; clicon_debug(2, "%s %s", __FUNCTION__, str); ife.if_parse_string = str; ife.if_linenum = linenum; - ife.if_ys = ys; - if (clixon_if_feature_parsel_init(&ife) < 0) + if (enabled) + ife.if_ys = ys; /* Used as trigger to check if enabled */ + ife.if_accept = accept; + ife.if_mainfile = mainfile; + if (clixon_yang_sub_parsel_init(&ife) < 0) goto done; - if (clixon_if_feature_parseparse(&ife) != 0) { /* yacc returns 1 on error */ - clicon_log(LOG_NOTICE, "If-feature error: line %d str:%s", ife.if_linenum, str); + if (clixon_yang_sub_parseparse(&ife) != 0) { /* yacc returns 1 on error */ if (clicon_errno == 0) clicon_err(OE_YANG, 0, "If-feature parser error with no error code (should not happen)"); goto done; @@ -90,6 +97,43 @@ yang_if_feature_parse(char *str, *enabled = ife.if_enabled; retval = 0; done: - clixon_if_feature_parsel_exit(&ife); + clixon_yang_sub_parsel_exit(&ife); + return retval; +} + +/*! Invoke yang (absolute_/descendant-)schema-nodeid sub-parser on string + * + * Used for refine-arg-str / usage-augment-arg-str in RFC 7950 Sec 14 + * @param[in] str (abs/desc)_schema_nodeid string + * @param[in] accept Sub-parse rule to accept + * @param[in] mainfile Name of main parse file + * @param[in] linenum Line number context in mainfile + * @retval 0 OK + * @retval -1 Error + */ +int +yang_schema_nodeid_subparse(char *str, + enum yang_sub_parse_accept accept, + const char *mainfile, + int linenum) +{ + int retval = -1; + clixon_yang_schemanode_yacc ife = {0,}; + + clicon_debug(1, "%s %s", __FUNCTION__, str); + ife.if_parse_string = str; + ife.if_linenum = linenum; + ife.if_mainfile = mainfile; + ife.if_accept = accept; /* accept absolute-schema-nodeid */ + if (clixon_yang_schemanode_parsel_init(&ife) < 0) + goto done; + if (clixon_yang_schemanode_parseparse(&ife) != 0) { /* yacc returns 1 on error */ + if (clicon_errno == 0) + clicon_err(OE_YANG, 0, "descendant-schema-nodeid parser error with no error code (should not happen)"); + goto done; + } + retval = 0; + done: + clixon_yang_schemanode_parsel_exit(&ife); return retval; } diff --git a/lib/src/clixon_yang_parse_sub.h b/lib/src/clixon_yang_sub_parse.h similarity index 51% rename from lib/src/clixon_yang_parse_sub.h rename to lib/src/clixon_yang_sub_parse.h index 4e906635..e8c18ad9 100644 --- a/lib/src/clixon_yang_parse_sub.h +++ b/lib/src/clixon_yang_sub_parse.h @@ -33,12 +33,47 @@ * Sub-parsers to upper-level YANG parser: everything that is "stringified" */ -#ifndef _CLIXON_YANG_PARSE_SUB_H_ -#define _CLIXON_YANG_PARSE_SUB_H_ +#ifndef _CLIXON_YANG_SUB_PARSE_H_ +#define _CLIXON_YANG_SUB_PARSE_H_ + +/* + * Types + */ +/*! Sub-parse rule to accept */ +enum yang_sub_parse_accept{ + YA_IF_FEATURE, + YA_ID_REF, + YA_ABS_SCHEMANODEID, + YA_DESC_SCHEMANODEID +}; + +/*! XML parser yacc handler struct */ +struct clixon_yang_sub_parse_yacc { + char *if_parse_string; /* original (copy of) parse string */ + const char *if_mainfile; /* Original main-file (this is a sib-parser) */ + int if_linenum; /* Number of \n in parsed buffer (in mainfile) */ + void *if_lexbuf; /* Internal parse buffer from lex */ + yang_stmt *if_ys; /* Yang statement, NULL if no check */ + enum yang_sub_parse_accept if_accept; /* Which sub-parse rule to accept */ + int if_enabled; /* Result: 0: feature disabled, 1: enabled */ +}; +typedef struct clixon_yang_sub_parse_yacc clixon_yang_sub_parse_yacc; + +/* + * Variables + */ +extern char *clixon_yang_sub_parsetext; /* * Prototypes */ -int yang_if_feature_parse(char *str, yang_stmt *ys, int linenum, int *enabled); +int clixon_yang_sub_parsel_init(clixon_yang_sub_parse_yacc *ya); +int clixon_yang_sub_parsel_exit(clixon_yang_sub_parse_yacc *ya); +int clixon_yang_sub_parsel_linenr(void); +int clixon_yang_sub_parselex(void *); +int clixon_yang_sub_parseparse(void *); -#endif /* _CLIXON_YANG_PARSER_SUB_H_ */ +int yang_subparse(char *str, yang_stmt *ys, enum yang_sub_parse_accept accept, const char *mainfile, int linenum, int *enabled); +int yang_schema_nodeid_subparse(char *str, enum yang_sub_parse_accept accept, const char *mainfile, int linenum); + +#endif /* _CLIXON_YANG_SUB_PARSER_H_ */ diff --git a/lib/src/clixon_if_feature_parse.l b/lib/src/clixon_yang_sub_parse.l similarity index 81% rename from lib/src/clixon_if_feature_parse.l rename to lib/src/clixon_yang_sub_parse.l index bfa413e4..5d9b2adf 100644 --- a/lib/src/clixon_if_feature_parse.l +++ b/lib/src/clixon_yang_sub_parse.l @@ -42,7 +42,7 @@ #include #include -#include "clixon_if_feature_parse.tab.h" /* generated file */ +#include "clixon_yang_sub_parse.tab.h" /* generated file */ /* cligen */ #include @@ -53,19 +53,19 @@ #include "clixon_handle.h" #include "clixon_yang.h" #include "clixon_xml.h" -#include "clixon_if_feature_parse.h" +#include "clixon_yang_sub_parse.h" /* Redefine main lex function so that you can send arguments to it: _if is added to arg list */ -#define YY_DECL int clixon_if_feature_parselex(void *_if) +#define YY_DECL int clixon_yang_sub_parselex(void *_if) /* Dont use input function (use user-buffer) */ #define YY_NO_INPUT /* typecast macro */ -#define _IF ((clixon_if_feature_yacc *)_if) +#define _IF ((clixon_yang_sub_parse_yacc *)_if) #undef clixon_xml_parsewrap -int clixon_if_feature_parsewrap(void) +int clixon_yang_sub_parsewrap(void) { return 1; } @@ -78,19 +78,21 @@ int clixon_if_feature_parsewrap(void) %x COMMENT %x STRING +identifier [A-Za-z_][A-Za-z0-9_\-\.]* + %% [ \t\r]* { return SEP; } \n { _IF->if_linenum++; return SEP; } \( { return *yytext; } \) { return *yytext; } +: { return *yytext; } not { return NOT; } and { return AND; } or { return OR; } +{identifier} { clixon_yang_sub_parselval.string = strdup(yytext); + return IDENTIFIER;} <> { return MY_EOF; } -[^\n\r \t\(\)]+ { - clixon_if_feature_parselval.string = strdup(yytext); - return TOKEN; } . { return -1; } %% @@ -98,7 +100,7 @@ int clixon_if_feature_parsewrap(void) /*! Initialize XML scanner. */ int -clixon_if_feature_parsel_init(clixon_if_feature_yacc *ife) +clixon_yang_sub_parsel_init(clixon_yang_sub_parse_yacc *ife) { BEGIN(INITIAL); ife->if_lexbuf = yy_scan_string (ife->if_parse_string); @@ -109,10 +111,10 @@ clixon_if_feature_parsel_init(clixon_if_feature_yacc *ife) /*! Exit xml scanner */ int -clixon_if_feature_parsel_exit(clixon_if_feature_yacc *ife) +clixon_yang_sub_parsel_exit(clixon_yang_sub_parse_yacc *ife) { yy_delete_buffer(ife->if_lexbuf); - clixon_if_feature_parselex_destroy(); /* modern */ + clixon_yang_sub_parselex_destroy(); /* modern */ return 0; } diff --git a/lib/src/clixon_if_feature_parse.y b/lib/src/clixon_yang_sub_parse.y similarity index 73% rename from lib/src/clixon_if_feature_parse.y rename to lib/src/clixon_yang_sub_parse.y index d04175a8..80d7ed1a 100644 --- a/lib/src/clixon_if_feature_parse.y +++ b/lib/src/clixon_yang_sub_parse.y @@ -31,7 +31,7 @@ ***** END LICENSE BLOCK ***** - * if-feature-expr RFC7950 14 + * Sub-parser for if-feature AND identifier-ref as defined in RFC7950 Section 14 if-feature-expr = if-feature-term [sep or-keyword sep if-feature-expr] @@ -41,8 +41,14 @@ if-feature-factor = not-keyword sep if-feature-factor / "(" optsep if-feature-expr optsep ")" / identifier-ref-arg + identifier-ref-arg = identifier-ref + identifier-ref = [prefix ":"] identifier + prefix = identifier + identifier = (ALPHA / "_") + *(ALPHA / DIGIT / "_" / "-" / ".") + Called twice: - 1. In parsing just for syntac checks (dont do feature-check) + 1. In parsing just for syntax checks (dont do feature-check) 2. In populate when all yangs are resolved, then do semantic feature-check */ %union { @@ -55,10 +61,11 @@ %token AND %token NOT %token OR -%token TOKEN +%token IDENTIFIER %token SEP %type if_feature_factor if_feature_expr +%type identifier_ref identifier prefix %start top @@ -68,8 +75,9 @@ %{ /* typecast macro */ -#define _IF ((clixon_if_feature_yacc *)_if) - +#define _IF ((clixon_yang_sub_parse_yacc *)_if) +#define _YYERROR(msg) {clicon_err(OE_YANG, 0, "%s", (msg)); YYERROR;} + #include #include #include @@ -92,7 +100,7 @@ #include "clixon_yang_module.h" #include "clixon_xml_vec.h" #include "clixon_data.h" -#include "clixon_if_feature_parse.h" +#include "clixon_yang_sub_parse.h" /* Enable for debugging, steals some cycles otherwise */ #if 0 @@ -102,15 +110,17 @@ #endif void -clixon_if_feature_parseerror(void *arg, +clixon_yang_sub_parseerror(void *arg, char *s) { - clixon_if_feature_yacc *ife = (clixon_if_feature_yacc *)arg; + clixon_yang_sub_parse_yacc *ife = (clixon_yang_sub_parse_yacc *)arg; - clicon_err(OE_XML, XMLPARSE_ERRNO, "if_feature_parse: line %d: %s: at or before: %s", + clicon_err_fn(NULL, 0, OE_YANG, 0, "yang_sub_parse: file:%s:%d \"%s\" %s: at or before: %s", + ife->if_mainfile, ife->if_linenum, + ife->if_parse_string, s, - clixon_if_feature_parsetext); + clixon_yang_sub_parsetext); return; } @@ -119,8 +129,8 @@ clixon_if_feature_parseerror(void *arg, * @param[in] ys If-feature type yang node */ static int -if_feature_check(char *str, - yang_stmt *ys) +if_feature_check(clixon_yang_sub_parse_yacc *ife, + char *str) { int retval = -1; char *prefix = NULL; @@ -128,8 +138,9 @@ if_feature_check(char *str, yang_stmt *ymod; /* module yang node */ yang_stmt *yfeat; /* feature yang node */ cg_var *cv; + yang_stmt *ys; - if (ys == NULL) + if ((ys = ife->if_ys) == NULL) return 0; if (nodeid_split(str, &prefix, &feature) < 0) goto done; @@ -172,7 +183,12 @@ top : if_feature_expr MY_EOF { _PARSE_DEBUG("top->if-feature-expr"); _IF->if_enabled = $1; - YYACCEPT; + if (_IF->if_accept == YA_IF_FEATURE){ + YYACCEPT; + } + else{ + _YYERROR("Expected if-feature-expr"); + } } ; @@ -199,10 +215,9 @@ if_feature_factor : NOT sep1 if_feature_factor | '(' optsep if_feature_expr optsep ')' { _PARSE_DEBUG("if-feature-factor-> ( optsep if-feature-expr optsep )"); $$ = $3; } - | TOKEN { - _PARSE_DEBUG("if-feature-factor-> TOKEN"); - if (_IF->if_ys == NULL) $$ = 0; - else if (($$ = if_feature_check($1, _IF->if_ys)) < 0) { + | identifier_ref { + _PARSE_DEBUG("if-feature-factor-> identifier-ref"); + if (($$ = if_feature_check(_IF, $1)) < 0) { free($1); YYERROR; } @@ -210,6 +225,42 @@ if_feature_factor : NOT sep1 if_feature_factor } ; +/* identifier-ref = [prefix ":"] identifier */ +identifier_ref : identifier + { + // XXX memory leak? + _PARSE_DEBUG("identifier-ref -> identifier"); + if (_IF->if_accept == YA_ID_REF){ + YYACCEPT; + } + $$=$1; + } + | prefix ':' identifier + { + if (($$=clixon_string_del_join($1, ":", $3)) == NULL) _YYERROR("identifier_ref"); + free($3); + if (_IF->if_accept == YA_ID_REF){ + YYACCEPT; + } + _PARSE_DEBUG("identifier-ref -> prefix : identifier"); + } + ; + +prefix : IDENTIFIER + { + _PARSE_DEBUG("prefix -> IDENTIFIER"); + $$=$1; + + } + ; + +identifier : IDENTIFIER + { + _PARSE_DEBUG("identifier -> IDENTIFIER"); + $$=$1; + } + ; + optsep : sep1 { _PARSE_DEBUG("optsep->sep"); } | { _PARSE_DEBUG("optsep->"); } ; diff --git a/test/test_refine.sh b/test/test_refine.sh new file mode 100755 index 00000000..5e4db71c --- /dev/null +++ b/test/test_refine.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash +# yang refine +# See eg ietf-tls-server@2022-05-04.yang container certificate : +# 1. dual refine +# 2. refine argument is non-trivial descendant-schema-nodeid stretching over a choice/case +# 3. refine "str1" + "str2" i.e. split refine-arg-str +# +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf_yang.xml +fyang=$dir/clixon-example.yang + +cat < $cfg + + $cfg + $dir + ${YANG_INSTALLDIR} + $fyang + /usr/local/lib/$APPNAME/clispec + /usr/local/lib/$APPNAME/cli + $APPNAME + /usr/local/var/$APPNAME/$APPNAME.sock + /usr/local/var/$APPNAME/$APPNAME.pidfile + /usr/local/var/$APPNAME + true + +EOF + +# This is the main module where the augment exists +cat < $fyang +module clixon-example { + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + + /* see ietf-keystore@2022-05-24.yang */ + grouping mygrouping { + choice mykeystore { + mandatory true; + case local { + container local-definition { + presence true; + leaf dummy1{ + type string; + default "foo1"; + } + } + } + case keystore { + container keystore-reference { + presence true; + leaf dummy2{ + type string; + default "bar1"; + } + } + } + } + } + container certificate { + description "See ietf-tls-server@2022-05-24.yang"; + uses ex:mygrouping{ + refine "mykeystore/local/local-definition/dummy1" { + default "foo2"; + } + refine "mykeystore/keystore/keystore-reference" + + "/dummy2" { + default "bar2"; + } + } + } +} + +EOF + +new "test params: -f $cfg" + +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + + if [ $? -ne 0 ]; then + err + fi + new "start backend -s init -f $cfg" + start_backend -s init -f $cfg +fi + +new "wait backend" +wait_backend + +new "Set local-definition" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + +new "Get config expected foo2 refined default value" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "foo2" + +new "Set keystore-reference" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "" + +new "Get config expected bar2 refined default value" +expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" "bar2" + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + +rm -rf $dir + +new "endtest" +endtest diff --git a/test/test_type.sh b/test/test_type.sh index a4bf15d3..e957b16e 100755 --- a/test/test_type.sh +++ b/test/test_type.sh @@ -36,8 +36,7 @@ module example3{ type union { type w; type enumeration { - enum "bounded"; - enum "un bounded"; /* note w space */ + enum bounded; } } } @@ -272,9 +271,6 @@ EOF new "cli validate" expectpart "$($clixon_cli -1f $cfg -l o -l o validate)" 0 '^$' - new "cli set transitive union string (and space)" - expectpart "$($clixon_cli -1f $cfg -l o set c ulle "un\ bounded")" 0 '^$' - new "cli validate" expectpart "$($clixon_cli -1f $cfg -l o -l o validate)" 0 '^$' diff --git a/test/test_union.sh b/test/test_union.sh index 840fc092..f6d3cf20 100755 --- a/test/test_union.sh +++ b/test/test_union.sh @@ -38,7 +38,7 @@ module example3{ range "4..44"; } type enumeration { - enum "unbounded"; + enum unbounded; } } }