* Break-out RFC 7950 Section 6.1 tokenization

* This enables full string lexical parsing of some rules previously not fully compliant, including:
    * refine
    * user-augment
    * if-feature
  * Also solves previous tokenization issues
This commit is contained in:
Olof hagsand 2022-07-22 09:17:43 +02:00
parent f9eacebf68
commit 9d65fb81d7
21 changed files with 811 additions and 218 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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_ */

View file

@ -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

View file

@ -94,7 +94,6 @@ int clixon_text_syntax_parsewrap(void)
<INITIAL>[^\n\r \t\[\]\{\}\;\"]+ {
clixon_text_syntax_parselval.string = strdup(yytext);
return TOKEN; }
<INITIAL>. { return -1; }
<COMMENT>\n { _TS->ts_linenum++; BEGIN(_TS->ts_lex_state);}
<COMMENT><<EOF>> { return MY_EOF; }
@ -106,7 +105,6 @@ int clixon_text_syntax_parsewrap(void)
<STRING>\" { BEGIN(_TS->ts_lex_state); return *yytext; }
<STRING>[^\n\"]+ { clixon_text_syntax_parselval.string = strdup(yytext);
return TOKEN; }
<STRING>. { return -1; }
%%

View file

@ -139,7 +139,6 @@ ncname {namestart}{namechar}*
<STATEA>\r { clixon_xml_parselval.string = "\n";return WHITESPACE; }
<STATEA>\n { clixon_xml_parselval.string = "\n"; _XY->xy_linenum++;return WHITESPACE; }
<STATEA>[^&\r\n \t\<]+ { clixon_xml_parselval.string = yytext; return CHARDATA; /* Optimized */}
<STATEA>. { clixon_xml_parselval.string = yytext; return CHARDATA; }
/* @see xml_chardata_encode */
<AMPERSAND>"amp;" { BEGIN(_XY->xy_lex_state); clixon_xml_parselval.string = "&"; return CHARDATA;}

View file

@ -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;

View file

@ -119,7 +119,6 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<KEYWORD>anydata { BEGIN(STRARG); return K_ANYDATA; }
<KEYWORD>anyxml { BEGIN(STRARG); return K_ANYXML; }
<KEYWORD>argument { BEGIN(STRARG); return K_ARGUMENT; }
<KEYWORD>base { BEGIN(STRARG); return K_BASE; }
<KEYWORD>belongs-to { BEGIN(STRARG); return K_BELONGS_TO; }
<KEYWORD>bit { BEGIN(STRARG); return K_BIT; }
<KEYWORD>case { BEGIN(STRARG); return K_CASE; }
@ -137,12 +136,9 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<KEYWORD>module { BEGIN(STRARG); return K_MODULE; }
<KEYWORD>notification { BEGIN(STRARG); return K_NOTIFICATION; }
<KEYWORD>prefix { BEGIN(STRARG); return K_PREFIX; }
<KEYWORD>refine { BEGIN(STRARG); return K_REFINE; }
<KEYWORD>rpc { BEGIN(STRARG); return K_RPC; }
<KEYWORD>submodule { BEGIN(STRARG); return K_SUBMODULE; }
<KEYWORD>type { BEGIN(STRARG); return K_TYPE; }
<KEYWORD>typedef { BEGIN(STRARG); return K_TYPEDEF; }
<KEYWORD>uses { BEGIN(STRARG); return K_USES; }
/* RFC 7950 keywords using boolean string arguments */
<KEYWORD>config { BEGIN(BOOLEAN); return K_CONFIG; }
@ -157,6 +153,7 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
/* RFC 7950 keywords using strings */
<KEYWORD>augment { BEGIN(STRING); return K_AUGMENT; }
<KEYWORD>base { BEGIN(STRING); return K_BASE; }
<KEYWORD>contact { BEGIN(STRING); return K_CONTACT; }
<KEYWORD>default { BEGIN(STRING); return K_DEFAULT; }
<KEYWORD>description { BEGIN(STRING); return K_DESCRIPTION; }
@ -178,13 +175,16 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<KEYWORD>path { BEGIN(STRING); return K_PATH; }
<KEYWORD>pattern { BEGIN(STRING); return K_PATTERN; }
<KEYWORD>presence { BEGIN(STRING); return K_PRESENCE; }
<KEYWORD>type { BEGIN(STRING); return K_TYPE; }
<KEYWORD>unique { BEGIN(STRING); return K_UNIQUE; }
<KEYWORD>range { BEGIN(STRING); return K_RANGE; }
<KEYWORD>reference { BEGIN(STRING); return K_REFERENCE; }
<KEYWORD>refine { BEGIN(STRING); return K_REFINE; }
<KEYWORD>revision { BEGIN(STRING); return K_REVISION; }
<KEYWORD>revision-date { BEGIN(STRING); return K_REVISION_DATE; }
<KEYWORD>status { BEGIN(STRING); return K_STATUS; }
<KEYWORD>units { BEGIN(STRING); return K_UNITS; }
<KEYWORD>uses { BEGIN(STRING); return K_USES; }
<KEYWORD>when { BEGIN(STRING); return K_WHEN; }
<KEYWORD>yang-version { BEGIN(STRING); return K_YANG_VERSION; }
<KEYWORD>: { return *yytext; }
@ -239,7 +239,6 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<STRARG>; { BEGIN(KEYWORD); return *yytext; }
<STRARG>{identifier} { clixon_yang_parselval.string = strdup(yytext);
return IDENTIFIER;}
<STRARG>. { return *yytext; }
<STRING>\{ { BEGIN(KEYWORD); return *yytext; }
@ -247,7 +246,7 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<STRING>\" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return *yytext; }
<STRING>\' { _YY->yy_lex_string_state =STRING; BEGIN(STRINGSQ); return *yytext; }
<STRING>\+ { return *yytext; }
<STRING>[^\"\'\+\{\;\n \t\r]+ { clixon_yang_parselval.string = strdup(yytext); /* XXX [.]+ */
<STRING>[^\"\'\{\;\n \t\r]+ { clixon_yang_parselval.string = strdup(yytext); /* XXX [.]+ */
return CHARS;}
<STRINGDQ>\\ { _YY->yy_lex_state = STRINGDQ; BEGIN(DQESC); }

View file

@ -68,15 +68,12 @@
%type <string> qstring
%type <string> string
%type <string> integer_value_str
%type <string> identifier_ref
%type <string> identifier_ref_arg_str
%type <string> if_feature_expr_str
%type <string> abs_schema_nodeid
%type <string> desc_schema_nodeid_strs
%type <string> desc_schema_nodeid_str
%type <string> desc_schema_nodeid
%type <string> node_identifier
%type <string> refine_arg_str
%type <string> augment_arg_str
%type <string> uses_augment_arg_str
%type <string> identifier_str
%type <string> identifier_ref_str
%type <string> bool_str
/* rfc 6020 keywords
@ -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
/* 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) */

View file

@ -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<yang_len_get(ygrouping2); j++){
@ -1863,7 +1868,10 @@ ys_parse(yang_stmt *ys,
* That is, siblings, etc, may not be there. Complete checks are made in
* ys_populate instead.
* @param[in] ys yang statement
* @param[in] filename Name of parsed file, if any
* @param[in] extra Yang extra for cornercases (unknown/extension). Is consumed
* @retval 0 OK
* @retval -1 Error
*
* The cv:s created in parse-tree as follows:
* fraction-digits : Create cv as uint8, check limits [1:8] (must be made in 1st pass)
@ -1874,6 +1882,7 @@ ys_parse(yang_stmt *ys,
*/
int
ys_parse_sub(yang_stmt *ys,
const char *filename,
char *extra)
{
int retval = -1;
@ -1885,10 +1894,19 @@ ys_parse_sub(yang_stmt *ys,
int ret;
uint32_t minmax;
cg_var *cv = NULL;
yang_stmt *yp;
arg = yang_argument_get(ys);
keyword = yang_keyword_get(ys);
switch (keyword){
case Y_BASE:
case Y_TYPE:
case Y_USES:
/* Invoke next level parser
*/
if (yang_schema_nodeid_subparse(yang_argument_get(ys), YA_ID_REF, filename, yang_linenum_get(ys)) < 0)
goto done;
break;
case Y_FRACTION_DIGITS:
if (ys_parse(ys, CGV_UINT8) == NULL)
goto done;
@ -1962,7 +1980,23 @@ ys_parse_sub(yang_stmt *ys,
* pass 1 is not yet resolved, only check syntax, actual feature check made in next pass
* @see yang_features
*/
if (yang_if_feature_parse(yang_argument_get(ys), NULL, yang_linenum_get(ys), NULL) < 0)
if (yang_subparse(yang_argument_get(ys), ys, YA_IF_FEATURE, filename, yang_linenum_get(ys), NULL) < 0)
goto done;
break;
case Y_AUGMENT: /* If parent is module/submodule: absolute-schema-nodeid
* If parent is uses: descendant-schema-nodeid
*/
if ((yp = yang_parent_get(ys)) &&
yang_keyword_get(yp) != Y_USES){
if (yang_schema_nodeid_subparse(yang_argument_get(ys), YA_ABS_SCHEMANODEID, filename, yang_linenum_get(ys)) < 0)
goto done;
break;
}
// fall through
case Y_REFINE:
/* Invoke next level parser on refine-arg-str / descendant-schema-nodeid
*/
if (yang_schema_nodeid_subparse(yang_argument_get(ys), YA_DESC_SCHEMANODEID, filename, yang_linenum_get(ys)) < 0)
goto done;
break;
case Y_UNKNOWN:{ /* save (optional) argument in ys_cv */

View file

@ -31,36 +31,37 @@
***** END LICENSE BLOCK *****
* if-feature-expr RFC7950 14
* decendant-schema-nodeid RFC7950 14
*/
#ifndef _CLIXON_IF_FEATURE_PARSE_H_
#define _CLIXON_IF_FEATURE_PARSE_H_
#ifndef _CLIXON_YANG_SCHEMANODE_PARSE_H_
#define _CLIXON_YANG_SCHEMANODE_PARSE_H_
/*
* Types
*/
/*! XML parser yacc handler struct */
struct clixon_if_feature_parse_yacc {
struct clixon_yang_schemanode_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 */
void *if_lexbuf; /* Internal parse buffer from lex */
yang_stmt *if_ys; /* Yang statement, NULL if no check */
int if_enabled; /* Result: 0: feature disabled, 1: enabled */
enum yang_sub_parse_accept if_accept;
};
typedef struct clixon_if_feature_parse_yacc clixon_if_feature_yacc;
typedef struct clixon_yang_schemanode_parse_yacc clixon_yang_schemanode_yacc;
/*
* Variables
*/
extern char *clixon_if_feature_parsetext;
extern char *clixon_yang_schemanode_parsetext;
/*
* Prototypes
*/
int clixon_if_feature_parsel_init(clixon_if_feature_yacc *ya);
int clixon_if_feature_parsel_exit(clixon_if_feature_yacc *ya);
int clixon_if_feature_parsel_linenr(void);
int clixon_if_feature_parselex(void *);
int clixon_if_feature_parseparse(void *);
int clixon_yang_schemanode_parsel_init(clixon_yang_schemanode_yacc *ya);
int clixon_yang_schemanode_parsel_exit(clixon_yang_schemanode_yacc *ya);
int clixon_yang_schemanode_parsel_linenr(void);
int clixon_yang_schemanode_parselex(void *);
int clixon_yang_schemanode_parseparse(void *);
#endif /* _CLIXON_IF_FEATURE_PARSE_H_ */
#endif /* _CLIXON_YANG_SCHEMANODE_PARSE_H_ */

View file

@ -0,0 +1,113 @@
/*
*
***** 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 *****
* decendant-schema-nodeid RFC7950 14
*/
%{
#include "clixon_config.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "clixon_yang_schemanode_parse.tab.h" /* generated file */
/* cligen */
#include <cligen/cligen.h>
/* 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_\-\.]*
%%
<INITIAL>\n { _IF->if_linenum++; return *yytext; }
<INITIAL>: { return *yytext; }
<INITIAL>\/ { return *yytext; }
<INITIAL>{identifier} { clixon_yang_schemanode_parselval.string = strdup(yytext);
return IDENTIFIER;}
<INITIAL><<EOF>> { return MY_EOF; }
<INITIAL>. { 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;
}

View file

@ -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 <string> 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <stdlib.h>
/* cligen */
#include <cligen/cligen.h>
/* 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);
}
;
%%

View file

@ -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
* @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_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;
}

View file

@ -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_ */

View file

@ -42,7 +42,7 @@
#include <string.h>
#include <stdint.h>
#include "clixon_if_feature_parse.tab.h" /* generated file */
#include "clixon_yang_sub_parse.tab.h" /* generated file */
/* cligen */
#include <cligen/cligen.h>
@ -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_\-\.]*
%%
<INITIAL>[ \t\r]* { return SEP; }
<INITIAL>\n { _IF->if_linenum++; return SEP; }
<INITIAL>\( { return *yytext; }
<INITIAL>\) { return *yytext; }
<INITIAL>: { return *yytext; }
<INITIAL>not { return NOT; }
<INITIAL>and { return AND; }
<INITIAL>or { return OR; }
<INITIAL>{identifier} { clixon_yang_sub_parselval.string = strdup(yytext);
return IDENTIFIER;}
<INITIAL><<EOF>> { return MY_EOF; }
<INITIAL>[^\n\r \t\(\)]+ {
clixon_if_feature_parselval.string = strdup(yytext);
return TOKEN; }
<INITIAL>. { 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;
}

View file

@ -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 <string> TOKEN
%token <string> IDENTIFIER
%token SEP
%type <number> if_feature_factor if_feature_expr
%type <string> identifier_ref identifier prefix
%start top
@ -68,7 +75,8 @@
%{
/* 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 <stdio.h>
#include <stdint.h>
@ -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,8 +183,13 @@ top : if_feature_expr MY_EOF
{
_PARSE_DEBUG("top->if-feature-expr");
_IF->if_enabled = $1;
if (_IF->if_accept == YA_IF_FEATURE){
YYACCEPT;
}
else{
_YYERROR("Expected if-feature-expr");
}
}
;
if_feature_expr : if_feature_factor sep1 OR sep1 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->"); }
;

121
test/test_refine.sh Executable file
View file

@ -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 <<EOF > $cfg
<clixon-config xmlns="http://clicon.org/config">
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
<CLICON_YANG_DIR>$dir</CLICON_YANG_DIR>
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_SOCK>/usr/local/var/$APPNAME/$APPNAME.sock</CLICON_SOCK>
<CLICON_BACKEND_PIDFILE>/usr/local/var/$APPNAME/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
<CLICON_XMLDB_DIR>/usr/local/var/$APPNAME</CLICON_XMLDB_DIR>
<CLICON_YANG_LIBRARY>true</CLICON_YANG_LIBRARY>
</clixon-config>
EOF
# This is the main module where the augment exists
cat <<EOF > $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" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><certificate xmlns=\"urn:example:clixon\"><local-definition/></certificate></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "Get config expected foo2 refined default value"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><certificate xmlns=\"urn:example:clixon\"><local-definition><dummy1>foo2</dummy1></local-definition></certificate></data></rpc-reply>"
new "Set keystore-reference"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><target><candidate/></target><config><certificate xmlns=\"urn:example:clixon\"><keystore-reference/></certificate></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "Get config expected bar2 refined default value"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><certificate xmlns=\"urn:example:clixon\"><keystore-reference><dummy2>bar2</dummy2></keystore-reference></certificate></data></rpc-reply>"
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

View file

@ -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 '^$'

View file

@ -38,7 +38,7 @@ module example3{
range "4..44";
}
type enumeration {
enum "unbounded";
enum unbounded;
}
}
}