/** | |
* @file yang.y | |
* @author Pavol Vican | |
* @brief YANG parser for libyang (bison grammar) | |
* | |
* Copyright (c) 2015 CESNET, z.s.p.o. | |
* | |
* This source code is licensed under BSD 3-Clause License (the "License"). | |
* You may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* https://opensource.org/licenses/BSD-3-Clause | |
*/ | |
%define api.pure full | |
%locations | |
%parse-param {void *scanner} | |
%parse-param {struct yang_parameter *param} | |
%lex-param {void *scanner} | |
%{ | |
#include <stdio.h> | |
#include <stdarg.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include "context.h" | |
#include "resolve.h" | |
#include "common.h" | |
#include "parser_yang.h" | |
#include "parser_yang_lex.h" | |
#include "parser.h" | |
/* only syntax rules */ | |
#define EXTENSION_ARG 0x01 | |
#define EXTENSION_STA 0x02 | |
#define EXTENSION_DSC 0x04 | |
#define EXTENSION_REF 0x08 | |
#define YANG_ADDELEM(current_ptr, size) \ | |
if (!(size % LY_YANG_ARRAY_SIZE)) { \ | |
void *tmp; \ | |
\ | |
tmp = realloc(current_ptr, (sizeof *current_ptr) * (size + LY_YANG_ARRAY_SIZE)); \ | |
if (!tmp) { \ | |
LOGMEM; \ | |
free(s); \ | |
YYABORT; \ | |
} \ | |
memset(tmp + (sizeof *current_ptr) * size, 0, (sizeof *current_ptr) * LY_YANG_ARRAY_SIZE); \ | |
current_ptr = tmp; \ | |
} \ | |
actual = ¤t_ptr[size++]; \ | |
void yyerror(YYLTYPE *yylloc, void *scanner, struct yang_parameter *param, ...); | |
/* pointer on the current parsed element 'actual' */ | |
%} | |
%union { | |
int32_t i; | |
uint32_t uint; | |
char *str; | |
char **p_str; | |
void *v; | |
char ch; | |
struct yang_type *type; | |
struct lys_deviation *dev; | |
struct lys_deviate *deviate; | |
union { | |
uint32_t index; | |
struct lys_node_container *container; | |
struct lys_node_anydata *anydata; | |
struct type_node node; | |
struct lys_node_case *cs; | |
struct lys_node_grp *grouping; | |
struct lys_refine *refine; | |
struct lys_node_notif *notif; | |
struct lys_node_uses *uses; | |
struct lys_node_inout *inout; | |
struct lys_node_augment *augment; | |
} nodes; | |
enum yytokentype token; | |
struct { | |
void *actual; | |
enum yytokentype token; | |
} backup_token; | |
} | |
%token UNION_KEYWORD | |
%token ANYXML_KEYWORD | |
%token WHITESPACE | |
%token ERROR | |
%token EOL | |
%token STRING | |
%token STRINGS | |
%token IDENTIFIER | |
%token IDENTIFIERPREFIX | |
%token REVISION_DATE | |
%token TAB | |
%token DOUBLEDOT | |
%token URI | |
%token INTEGER | |
%token NON_NEGATIVE_INTEGER | |
%token ZERO | |
%token DECIMAL | |
%token ARGUMENT_KEYWORD | |
%token AUGMENT_KEYWORD | |
%token BASE_KEYWORD | |
%token BELONGS_TO_KEYWORD | |
%token BIT_KEYWORD | |
%token CASE_KEYWORD | |
%token CHOICE_KEYWORD | |
%token CONFIG_KEYWORD | |
%token CONTACT_KEYWORD | |
%token CONTAINER_KEYWORD | |
%token DEFAULT_KEYWORD | |
%token DESCRIPTION_KEYWORD | |
%token ENUM_KEYWORD | |
%token ERROR_APP_TAG_KEYWORD | |
%token ERROR_MESSAGE_KEYWORD | |
%token EXTENSION_KEYWORD | |
%token DEVIATION_KEYWORD | |
%token DEVIATE_KEYWORD | |
%token FEATURE_KEYWORD | |
%token FRACTION_DIGITS_KEYWORD | |
%token GROUPING_KEYWORD | |
%token IDENTITY_KEYWORD | |
%token IF_FEATURE_KEYWORD | |
%token IMPORT_KEYWORD | |
%token INCLUDE_KEYWORD | |
%token INPUT_KEYWORD | |
%token KEY_KEYWORD | |
%token LEAF_KEYWORD | |
%token LEAF_LIST_KEYWORD | |
%token LENGTH_KEYWORD | |
%token LIST_KEYWORD | |
%token MANDATORY_KEYWORD | |
%token MAX_ELEMENTS_KEYWORD | |
%token MIN_ELEMENTS_KEYWORD | |
%token MODULE_KEYWORD | |
%token MUST_KEYWORD | |
%token NAMESPACE_KEYWORD | |
%token NOTIFICATION_KEYWORD | |
%token ORDERED_BY_KEYWORD | |
%token ORGANIZATION_KEYWORD | |
%token OUTPUT_KEYWORD | |
%token PATH_KEYWORD | |
%token PATTERN_KEYWORD | |
%token POSITION_KEYWORD | |
%token PREFIX_KEYWORD | |
%token PRESENCE_KEYWORD | |
%token RANGE_KEYWORD | |
%token REFERENCE_KEYWORD | |
%token REFINE_KEYWORD | |
%token REQUIRE_INSTANCE_KEYWORD | |
%token REVISION_KEYWORD | |
%token REVISION_DATE_KEYWORD | |
%token RPC_KEYWORD | |
%token STATUS_KEYWORD | |
%token SUBMODULE_KEYWORD | |
%token TYPE_KEYWORD | |
%token TYPEDEF_KEYWORD | |
%token UNIQUE_KEYWORD | |
%token UNITS_KEYWORD | |
%token USES_KEYWORD | |
%token VALUE_KEYWORD | |
%token WHEN_KEYWORD | |
%token YANG_VERSION_KEYWORD | |
%token YIN_ELEMENT_KEYWORD | |
%token ADD_KEYWORD | |
%token CURRENT_KEYWORD | |
%token DELETE_KEYWORD | |
%token DEPRECATED_KEYWORD | |
%token FALSE_KEYWORD | |
%token NOT_SUPPORTED_KEYWORD | |
%token OBSOLETE_KEYWORD | |
%token REPLACE_KEYWORD | |
%token SYSTEM_KEYWORD | |
%token TRUE_KEYWORD | |
%token UNBOUNDED_KEYWORD | |
%token USER_KEYWORD | |
%token ACTION_KEYWORD | |
%token MODIFIER_KEYWORD | |
%token ANYDATA_KEYWORD | |
%token NODE | |
%token NODE_PRINT | |
%type <uint> positive_integer_value | |
%type <uint> non_negative_integer_value | |
%type <uint> max_value_arg_str | |
%type <uint> max_value_arg | |
%type <uint> max_elements_stmt | |
%type <uint> min_value_arg_str | |
%type <uint> min_value_arg | |
%type <uint> min_elements_stmt | |
%type <uint> fraction_digits_arg_str | |
%type <uint> fraction_digits_arg | |
%type <uint> position_value_arg_str | |
%type <uint> position_value_arg | |
%type <uint> yin_element_arg_str | |
%type <uint> yin_element_arg | |
%type <i> require_instance_stmt | |
%type <i> require_instance_arg_str | |
%type <i> require_instance_arg | |
%type <i> import_opt_stmt | |
%type <i> include_opt_stmt | |
%type <i> module_header_stmt | |
%type <i> submodule_header_stmt | |
%type <str> message_opt_stmt | |
%type <i> status_stmt | |
%type <i> status_arg_str | |
%type <i> status_arg | |
%type <i> config_stmt | |
%type <i> config_arg_str | |
%type <i> config_arg | |
%type <i> mandatory_stmt | |
%type <i> mandatory_arg_str | |
%type <i> mandatory_arg | |
%type <i> ordered_by_stmt | |
%type <i> ordered_by_arg_str | |
%type <i> ordered_by_arg | |
%type <i> integer_value_arg_str | |
%type <i> value_arg | |
%type <i> integer_value | |
%type <str> pattern_arg_str | |
%type <nodes> container_opt_stmt | |
%type <nodes> anyxml_opt_stmt | |
%type <nodes> choice_opt_stmt | |
%type <nodes> case_opt_stmt | |
%type <nodes> grouping_opt_stmt | |
%type <nodes> leaf_opt_stmt | |
%type <nodes> leaf_list_opt_stmt | |
%type <nodes> list_opt_stmt | |
%type <nodes> type_opt_stmt | |
%type <nodes> uses_opt_stmt | |
%type <nodes> refine_body_opt_stmts | |
%type <nodes> augment_opt_stmt | |
%type <nodes> rpc_opt_stmt | |
%type <nodes> input_output_opt_stmt | |
%type <nodes> notification_opt_stmt | |
%type <dev> deviation_opt_stmt | |
%type <deviate> deviate_add_opt_stmt | |
%type <deviate> deviate_delete_opt_stmt | |
%type <deviate> deviate_replace_opt_stmt | |
%type <ch> pattern_opt_stmt | |
%type <ch> pattern_end | |
%type <ch> modifier_stmt | |
%type <p_str> tmp_string | |
%type <str> string_opt_part1 | |
%type <str> semicolom | |
%type <str> curly_bracket_open | |
%type <token> import_arg_str | |
%type <token> include_arg_str | |
%type <token> revision_arg_stmt | |
%type <token> argument_str | |
%type <token> belongs_to_arg_str | |
%type <backup_token> grouping_arg_str | |
%type <backup_token> container_arg_str | |
%type <backup_token> leaf_arg_str | |
%type <backup_token> leaf_list_arg_str | |
%type <backup_token> list_arg_str | |
%type <backup_token> choice_arg_str | |
%type <backup_token> case_arg_str | |
%type <backup_token> anyxml_arg_str | |
%type <backup_token> anydata_arg_str | |
%type <backup_token> uses_arg_str | |
%type <backup_token> uses_augment_arg | |
%type <backup_token> augment_arg | |
%type <backup_token> action_arg_str | |
%type <backup_token> rpc_arg_str | |
%type <backup_token> input_arg | |
%type <backup_token> output_arg | |
%type <backup_token> notification_arg_str | |
%type <backup_token> extension_arg_str | |
%type <backup_token> feature_arg_str | |
%type <backup_token> identity_arg_str | |
%type <backup_token> if_feature_arg | |
%type <backup_token> typedef_arg_str | |
%type <backup_token> type_arg_str | |
%type <backup_token> length_arg_str | |
%type <backup_token> pattern_sep | |
%type <backup_token> range_arg_str | |
%type <backup_token> union_spec | |
%type <backup_token> enum_arg_str | |
%type <backup_token> bit_arg_str | |
%type <backup_token> when_arg_str | |
%type <backup_token> must_agr_str | |
%destructor { free($$); } pattern_arg_str string_opt_part1 semicolom curly_bracket_open | |
%destructor { free(($$) ? *$$ : NULL); } tmp_string | |
%initial-action { yylloc.last_column = 0; | |
param->value = &s; | |
param->data_node = (void **)&data_node; | |
param->actual_node = &actual; | |
backup_type = NODE; | |
} | |
%% | |
/* to simplify code, store the module/submodule being processed as trg */ | |
start: module_stmt | |
| submodule_stmt | |
tmp_string: STRING { if (yyget_text(scanner)[0] == '"') { | |
char *tmp; | |
s = malloc(yyget_leng(scanner) - 1 + 7 * yylval.i); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
if (!(tmp = yang_read_string(yyget_text(scanner) + 1, s, yyget_leng(scanner) - 2, 0, yylloc.first_column))) { | |
YYABORT; | |
} | |
s = tmp; | |
} else { | |
s = calloc(1, yyget_leng(scanner) - 1); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
memcpy(s, yyget_text(scanner) + 1, yyget_leng(scanner) - 2); | |
} | |
$$ = &s; | |
} | |
string_1: tmp_string optsep string_2 | |
string_2: @EMPTYDIR@ | |
| string_2 '+' optsep | |
STRING { if (yyget_leng(scanner) > 2) { | |
int length_s = strlen(s), length_tmp = yyget_leng(scanner); | |
char *tmp; | |
tmp = realloc(s, length_s + length_tmp - 1); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
s = tmp; | |
if (yyget_text(scanner)[0] == '"') { | |
if (!(tmp = yang_read_string(yyget_text(scanner) + 1, s, length_tmp - 2, length_s, yylloc.first_column))) { | |
YYABORT; | |
} | |
s = tmp; | |
} else { | |
memcpy(s + length_s, yyget_text(scanner) + 1, length_tmp - 2); | |
s[length_s + length_tmp - 2] = '\0'; | |
} | |
} | |
} | |
optsep; | |
module_arg_str: identifier_arg_str { if (param->submodule) { | |
free(s); | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "module"); | |
YYABORT; | |
} | |
trg = param->module; | |
yang_read_common(trg,s,MODULE_KEYWORD); | |
s = NULL; | |
actual_type = MODULE_KEYWORD; | |
} | |
module_stmt: optsep MODULE_KEYWORD sep module_arg_str | |
'{' stmtsep | |
module_header_stmts | |
linkage_stmt | |
meta_stmts | |
revision_stmts | |
body_stmts_end | |
'}' optsep | |
module_header_stmts: module_header_stmt { if (!param->module->ns) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "namespace", "module"); | |
YYABORT; | |
} | |
if (!param->module->prefix) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "prefix", "module"); | |
YYABORT; | |
} | |
} | |
module_header_stmt: @EMPTYDIR@ { $$ = 0; } | |
| module_header_stmt yang_version_stmt { if (yang_check_version(param->module, param->submodule, s, $1)) { | |
YYABORT; | |
} | |
$$ = 1; | |
s = NULL; | |
} | |
| module_header_stmt namespace_stmt { if (yang_read_common(param->module, s, NAMESPACE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| module_header_stmt prefix_stmt | |
; | |
submodule_arg_str: identifier_arg_str { if (!param->submodule) { | |
free(s); | |
LOGVAL(LYE_SUBMODULE, LY_VLOG_NONE, NULL); | |
YYABORT; | |
} | |
trg = (struct lys_module *)param->submodule; | |
yang_read_common(trg,s,MODULE_KEYWORD); | |
s = NULL; | |
actual_type = SUBMODULE_KEYWORD; | |
} | |
submodule_stmt: optsep SUBMODULE_KEYWORD sep submodule_arg_str | |
'{' stmtsep | |
submodule_header_stmts | |
linkage_stmt | |
meta_stmts | |
revision_stmts | |
body_stmts_end | |
'}' optsep | |
submodule_header_stmts: submodule_header_stmt { if (!param->submodule->prefix) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "belongs-to", "submodule"); | |
YYABORT; | |
} | |
if (!$1) { | |
/* check version compatibility with the main module */ | |
if (param->module->version > 1) { | |
LOGVAL(LYE_INVER, LY_VLOG_NONE, NULL); | |
YYABORT; | |
} | |
} | |
} | |
submodule_header_stmt: @EMPTYDIR@ { $$ = 0; } | |
| submodule_header_stmt yang_version_stmt { if (yang_check_version(param->module, param->submodule, s, $1)) { | |
YYABORT; | |
} | |
$$ = 1; | |
s = NULL; | |
} | |
| submodule_header_stmt belongs_to_stmt stmtsep | |
yang_version_arg: string { backup_type = actual_type; | |
actual_type = YANG_VERSION_KEYWORD; | |
} | |
yang_version_stmt: YANG_VERSION_KEYWORD sep yang_version_arg stmtend | |
namespace_arg_str: string { backup_type = actual_type; | |
actual_type = NAMESPACE_KEYWORD; | |
} | |
namespace_stmt: NAMESPACE_KEYWORD sep namespace_arg_str stmtend | |
linkage_stmt: linkage_stmts { *param->remove_import = 0; | |
if (yang_check_imports(trg, param->unres)) { | |
YYABORT; | |
} | |
} | |
linkage_stmts: @EMPTYDIR@ | |
| linkage_stmts import_stmt stmtsep | |
| linkage_stmts include_stmt stmtsep | |
import_stmt: IMPORT_KEYWORD sep import_arg_str | |
'{' stmtsep | |
import_opt_stmt | |
'}' { actual_type = $3; | |
backup_type = NODE; | |
actual = NULL; | |
} | |
import_arg_str: identifier_arg_str { YANG_ADDELEM(trg->imp, trg->imp_size); | |
/* HACK for unres */ | |
((struct lys_import *)actual)->module = (struct lys_module *)s; | |
s = NULL; | |
$$ = actual_type; | |
actual_type = IMPORT_KEYWORD; | |
} | |
import_opt_stmt: @EMPTYDIR@ { $$ = 0; } | |
| import_opt_stmt prefix_stmt | |
| import_opt_stmt description_stmt { if (trg->version != 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "description"); | |
free(s); | |
YYABORT; | |
} | |
if (yang_read_description(trg, actual, s, "import", IMPORT_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| import_opt_stmt reference_stmt { if (trg->version != 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "reference"); | |
free(s); | |
YYABORT; | |
} | |
if (yang_read_reference(trg, actual, s, "import", IMPORT_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| import_opt_stmt revision_date_stmt { if ($1) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "revision-date", "import"); | |
free(s); | |
YYABORT; | |
} | |
memcpy(((struct lys_import *)actual)->rev, s, LY_REV_SIZE-1); | |
free(s); | |
s = NULL; | |
$$ = 1; | |
} | |
include_arg_str: identifier_arg_str { YANG_ADDELEM(trg->inc, trg->inc_size); | |
/* HACK for unres */ | |
((struct lys_include *)actual)->submodule = (struct lys_submodule *)s; | |
s = NULL; | |
$$ = actual_type; | |
actual_type = INCLUDE_KEYWORD; | |
} | |
include_stmt: INCLUDE_KEYWORD sep include_arg_str include_end { actual_type = $3; | |
backup_type = NODE; | |
actual = NULL; | |
} | |
include_end: ';' | |
| '{' stmtsep | |
include_opt_stmt | |
'}' | |
include_opt_stmt: @EMPTYDIR@ { $$ = 0; } | |
| include_opt_stmt description_stmt { if (trg->version != 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "description"); | |
free(s); | |
YYABORT; | |
} | |
if (yang_read_description(trg, actual, s, "include", INCLUDE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| include_opt_stmt reference_stmt { if (trg->version != 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "reference"); | |
free(s); | |
YYABORT; | |
} | |
if (yang_read_reference(trg, actual, s, "include", INCLUDE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| include_opt_stmt revision_date_stmt { if ($1) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "revision-date", "include"); | |
free(s); | |
YYABORT; | |
} | |
memcpy(((struct lys_include *)actual)->rev, s, LY_REV_SIZE-1); | |
free(s); | |
s = NULL; | |
$$ = 1; | |
} | |
revision_date_arg: date_arg_str { backup_type = actual_type; | |
actual_type = REVISION_DATE_KEYWORD; | |
} | |
revision_date_stmt: REVISION_DATE_KEYWORD sep revision_date_arg stmtend | |
belongs_to_arg_str: identifier_arg_str { $$ = actual_type; | |
if (param->submodule->prefix) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "belongs-to", "submodule"); | |
free(s); | |
YYABORT; | |
} | |
if (!ly_strequal(s, param->submodule->belongsto->name, 0)) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "belongs-to"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
actual_type = BELONGS_TO_KEYWORD; | |
} | |
belongs_to_stmt: BELONGS_TO_KEYWORD sep belongs_to_arg_str | |
'{' stmtsep | |
prefix_stmt | |
'}' { actual_type = $3; } | |
prefix_arg: prefix_arg_str { backup_type = actual_type; | |
actual_type = PREFIX_KEYWORD; | |
} | |
prefix_stmt: PREFIX_KEYWORD sep prefix_arg stmtend { if (yang_read_prefix(trg, actual, s)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
meta_stmts: @EMPTYDIR@ | |
| meta_stmts organization_stmt { if (yang_read_common(trg, s, ORGANIZATION_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| meta_stmts contact_stmt { if (yang_read_common(trg, s, CONTACT_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| meta_stmts description_stmt { if (yang_read_description(trg, NULL, s, NULL, MODULE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| meta_stmts reference_stmt { if (yang_read_reference(trg, NULL, s, NULL, MODULE_KEYWORD)) { | |
YYABORT; | |
} | |
s=NULL; | |
} | |
organization_arg: string { backup_type = actual_type; | |
actual_type = ORGANIZATION_KEYWORD; | |
} | |
organization_stmt: ORGANIZATION_KEYWORD sep organization_arg stmtend | |
contact_arg: string { backup_type = actual_type; | |
actual_type = CONTACT_KEYWORD; | |
} | |
contact_stmt: CONTACT_KEYWORD sep contact_arg stmtend | |
description_arg: string { backup_type = actual_type; | |
actual_type = DESCRIPTION_KEYWORD; | |
} | |
description_stmt: DESCRIPTION_KEYWORD sep description_arg stmtend | |
reference_arg: string { backup_type = actual_type; | |
actual_type = REFERENCE_KEYWORD; | |
} | |
reference_stmt: REFERENCE_KEYWORD sep reference_arg stmtend | |
revision_stmts: revision_stmts_opt { if (trg->rev_size) { | |
struct lys_revision *tmp; | |
tmp = realloc(trg->rev, trg->rev_size * sizeof *trg->rev); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->rev = tmp; | |
} | |
} | |
revision_arg_stmt: date_arg_str { YANG_ADDELEM(trg->rev, trg->rev_size); | |
actual = yang_read_revision(trg, s, actual); | |
$$ = actual_type; | |
actual_type = REVISION_KEYWORD; | |
} | |
revision_stmts_opt: @EMPTYDIR@ | |
| revision_stmts_opt revision_stmt stmtsep | |
revision_stmt: REVISION_KEYWORD sep revision_arg_stmt revision_end { actual_type = $3; | |
actual = NULL; | |
} | |
revision_end: ';' | |
| '{' stmtsep | |
revision_opt_stmt | |
'}' | |
revision_opt_stmt: @EMPTYDIR@ | |
| revision_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "revision",REVISION_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| revision_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "revision", REVISION_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
; | |
date_arg_str: REVISION_DATE { s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
optsep | |
| string_1 { if (lyp_check_date(s)) { | |
free(s); | |
YYABORT; | |
} | |
} | |
body_stmts_end: body_stmts { void *tmp; | |
if (trg->tpdf_size) { | |
tmp = realloc(trg->tpdf, trg->tpdf_size * sizeof *trg->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->tpdf = tmp; | |
} | |
if (trg->features_size) { | |
tmp = realloc(trg->features, trg->features_size * sizeof *trg->features); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->features = tmp; | |
} | |
if (trg->ident_size) { | |
tmp = realloc(trg->ident, trg->ident_size * sizeof *trg->ident); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->ident = tmp; | |
} | |
if (trg->augment_size) { | |
tmp = realloc(trg->augment, trg->augment_size * sizeof *trg->augment); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->augment = tmp; | |
} | |
if (trg->extensions_size) { | |
tmp = realloc(trg->extensions, trg->extensions_size * sizeof *trg->extensions); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
trg->extensions = tmp; | |
} | |
} | |
body_stmts: @EMPTYDIR@ { actual = NULL; } | |
| body_stmts body_stmt stmtsep { actual = NULL; } | |
body_stmt: extension_stmt | |
| feature_stmt | |
| identity_stmt | |
| typedef_stmt | |
| grouping_stmt | |
| data_def_stmt | |
| augment_stmt | |
| rpc_stmt | |
| notification_stmt | |
| deviation_stmt | |
extension_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
YANG_ADDELEM(trg->extensions, trg->extensions_size); | |
trg->extensions_size--; | |
((struct lys_ext *)actual)->name = lydict_insert_zc(param->module->ctx, s); | |
((struct lys_ext *)actual)->module = trg; | |
if (lyp_check_identifier(((struct lys_ext *)actual)->name, LY_IDENT_EXTENSION, trg, NULL)) { | |
trg->extensions_size++; | |
YYABORT; | |
} | |
trg->extensions_size++; | |
s = NULL; | |
actual_type = EXTENSION_KEYWORD; | |
} | |
extension_stmt: EXTENSION_KEYWORD sep extension_arg_str extension_end | |
{ struct lys_ext *ext = actual; | |
ext->plugin = ext_get_plugin(ext->name, ext->module->name, ext->module->rev ? ext->module->rev[0].date : NULL); | |
actual_type = $3.token; | |
actual = $3.actual; | |
} | |
extension_end: ';' | |
| '{' stmtsep | |
extension_opt_stmt | |
'}' | |
extension_opt_stmt: @EMPTYDIR@ | |
| extension_opt_stmt argument_stmt stmtsep | |
| extension_opt_stmt status_stmt { if (((struct lys_ext *)actual)->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "status", "extension"); | |
YYABORT; | |
} | |
((struct lys_ext *)actual)->flags |= $2; | |
} | |
| extension_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "extension", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| extension_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "extension", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
argument_str: identifier_arg_str { $$ = actual_type; | |
if (((struct lys_ext *)actual)->argument) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "argument", "extension"); | |
free(s); | |
YYABORT; | |
} | |
((struct lys_ext *)actual)->argument = lydict_insert_zc(param->module->ctx, s); | |
s = NULL; | |
actual_type = ARGUMENT_KEYWORD; | |
} | |
argument_stmt: ARGUMENT_KEYWORD sep argument_str argument_end { actual_type = $3; } | |
argument_end: ';' | |
| '{' stmtsep | |
yin_element_stmt | |
'}' | |
yin_element_arg: yin_element_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = YIN_ELEMENT_KEYWORD; | |
} | |
yin_element_stmt: @EMPTYDIR@ | |
| YIN_ELEMENT_KEYWORD sep yin_element_arg stmtend { ((struct lys_ext *)actual)->flags |= $3; } | |
yin_element_arg_str: TRUE_KEYWORD optsep { $$ = LYS_YINELEM; } | |
| FALSE_KEYWORD optsep { $$ = 0; } | |
| string_1 { if (!strcmp(s, "true")) { | |
$$ = LYS_YINELEM; | |
} else if (!strcmp(s, "false")) { | |
$$ = 0; | |
} else { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, s); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
} | |
status_arg: status_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = STATUS_KEYWORD; | |
} | |
status_stmt: STATUS_KEYWORD sep status_arg stmtend { $$ = $3; } | |
status_arg_str: CURRENT_KEYWORD optsep { $$ = LYS_STATUS_CURR; } | |
| OBSOLETE_KEYWORD optsep { $$ = LYS_STATUS_OBSLT; } | |
| DEPRECATED_KEYWORD optsep { $$ = LYS_STATUS_DEPRC; } | |
| string_1 { if (!strcmp(s, "current")) { | |
$$ = LYS_STATUS_CURR; | |
} else if (!strcmp(s, "obsolete")) { | |
$$ = LYS_STATUS_OBSLT; | |
} else if (!strcmp(s, "deprecated")) { | |
$$ = LYS_STATUS_DEPRC; | |
} else { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, s); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
} | |
feature_arg_str: identifier_arg_str { /* check uniqueness of feature's names */ | |
if (lyp_check_identifier(s, LY_IDENT_FEATURE, trg, NULL)) { | |
free(s); | |
YYABORT; | |
} | |
$$.token = actual_type; | |
$$.actual = actual; | |
YANG_ADDELEM(trg->features, trg->features_size); | |
((struct lys_feature *)actual)->name = lydict_insert_zc(trg->ctx, s); | |
((struct lys_feature *)actual)->module = trg; | |
s = NULL; | |
actual_type = FEATURE_KEYWORD; | |
} | |
feature_stmt: FEATURE_KEYWORD sep feature_arg_str feature_end | |
{ actual = $3.actual; | |
actual_type = $3.token; | |
} | |
feature_end: ';' | |
| '{' stmtsep | |
feature_opt_stmt | |
'}' { struct lys_iffeature *tmp; | |
if (((struct lys_feature *)actual)->iffeature_size) { | |
tmp = realloc(((struct lys_feature *)actual)->iffeature, | |
((struct lys_feature *)actual)->iffeature_size * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct lys_feature *)actual)->iffeature = tmp; | |
} | |
} | |
feature_opt_stmt: @EMPTYDIR@ | |
| feature_opt_stmt if_feature_stmt stmtsep | |
| feature_opt_stmt status_stmt { if (((struct lys_feature *)actual)->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "status", "feature"); | |
YYABORT; | |
} | |
((struct lys_feature *)actual)->flags |= $2; | |
} | |
| feature_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "feature", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| feature_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "feature", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
if_feature_arg: string { $$.token = actual_type; | |
$$.actual = actual; | |
switch (actual_type) { | |
case FEATURE_KEYWORD: | |
YANG_ADDELEM(((struct lys_feature *)actual)->iffeature, | |
((struct lys_feature *)actual)->iffeature_size); | |
break; | |
case IDENTITY_KEYWORD: | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "if-feature", "identity"); | |
free(s); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_ident *)actual)->iffeature, | |
((struct lys_ident *)actual)->iffeature_size); | |
break; | |
case ENUM_KEYWORD: | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "if-feature"); | |
free(s); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_type_enum *)actual)->iffeature, | |
((struct lys_type_enum *)actual)->iffeature_size); | |
break; | |
case BIT_KEYWORD: | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "if-feature", "bit"); | |
free(s); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_type_bit *)actual)->iffeature, | |
((struct lys_type_bit *)actual)->iffeature_size); | |
break; | |
case REFINE_KEYWORD: | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "if-feature"); | |
free(s); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_refine *)actual)->iffeature, | |
((struct lys_refine *)actual)->iffeature_size); | |
break; | |
default: | |
/* lys_node_* */ | |
YANG_ADDELEM(((struct lys_node *)actual)->iffeature, | |
((struct lys_node *)actual)->iffeature_size); | |
break; | |
} | |
((struct lys_iffeature *)actual)->features = (struct lys_feature **)s; | |
s = NULL; | |
actual_type = IF_FEATURE_KEYWORD; | |
} | |
if_feature_stmt: IF_FEATURE_KEYWORD sep if_feature_arg if_feature_end | |
{ actual = $3.actual; | |
actual_type = $3.token; | |
} | |
if_feature_end: ';' | |
| '{' stmtsep '}' | |
identity_arg_str: identifier_arg_str { const char *tmp; | |
tmp = lydict_insert_zc(trg->ctx, s); | |
s = NULL; | |
if (dup_identities_check(tmp, trg)) { | |
lydict_remove(trg->ctx, tmp); | |
YYABORT; | |
} | |
$$.token = actual_type; | |
$$.actual = actual; | |
YANG_ADDELEM(trg->ident, trg->ident_size); | |
((struct lys_ident *)actual)->name = tmp; | |
((struct lys_ident *)actual)->module = trg; | |
actual_type = IDENTITY_KEYWORD; | |
} | |
identity_stmt: IDENTITY_KEYWORD sep identity_arg_str identity_end | |
{ actual = $3.actual; | |
actual_type = $3.token; | |
} | |
identity_end: ';' | |
| '{' stmtsep | |
identity_opt_stmt | |
'}' { void *tmp; | |
if (((struct lys_ident *)actual)->base_size) { | |
tmp = realloc(((struct lys_ident *)actual)->base, | |
((struct lys_ident *)actual)->base_size * sizeof *((struct lys_ident *)actual)->base); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct lys_ident *)actual)->base = tmp; | |
} | |
if (((struct lys_ident *)actual)->iffeature_size) { | |
tmp = realloc(((struct lys_ident *)actual)->iffeature, | |
((struct lys_ident *)actual)->iffeature_size * sizeof *((struct lys_ident *)actual)->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct lys_ident *)actual)->iffeature = tmp; | |
} | |
} | |
identity_opt_stmt: @EMPTYDIR@ | |
| identity_opt_stmt base_stmt { void *identity; | |
if ((trg->version < 2) && ((struct lys_ident *)actual)->base_size) { | |
free(s); | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "base", "identity"); | |
YYABORT; | |
} | |
identity = actual; | |
YANG_ADDELEM(((struct lys_ident *)actual)->base, | |
((struct lys_ident *)actual)->base_size); | |
*((struct lys_ident **)actual) = (struct lys_ident *)s; | |
s = NULL; | |
actual = identity; | |
} | |
| identity_opt_stmt if_feature_stmt stmtsep | |
| identity_opt_stmt status_stmt { if (((struct lys_ident *)actual)->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "status", "identity"); | |
YYABORT; | |
} | |
((struct lys_ident *)actual)->flags |= $2; | |
} | |
| identity_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "identity", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| identity_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "identity", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
base_arg: identifier_ref_arg_str { backup_type = actual_type; | |
actual_type = BASE_KEYWORD; | |
} | |
base_stmt: BASE_KEYWORD sep base_arg stmtend | |
typedef_arg_str: identifier_arg_str { tpdf_parent = actual; | |
$$.token = actual_type; | |
$$.actual = actual; | |
if (lyp_check_identifier(s, LY_IDENT_TYPE, trg, tpdf_parent)) { | |
free(s); | |
YYABORT; | |
} | |
if (!tpdf_parent) { | |
YANG_ADDELEM(trg->tpdf, trg->tpdf_size); | |
} else { | |
switch (tpdf_parent->nodetype) { | |
case LYS_GROUPING: | |
YANG_ADDELEM(((struct lys_node_grp *)tpdf_parent)->tpdf, | |
((struct lys_node_grp *)tpdf_parent)->tpdf_size); | |
break; | |
case LYS_CONTAINER: | |
YANG_ADDELEM(((struct lys_node_container *)tpdf_parent)->tpdf, | |
((struct lys_node_container *)tpdf_parent)->tpdf_size); | |
break; | |
case LYS_LIST: | |
YANG_ADDELEM(((struct lys_node_list *)tpdf_parent)->tpdf, | |
((struct lys_node_list *)tpdf_parent)->tpdf_size); | |
break; | |
case LYS_RPC: | |
case LYS_ACTION: | |
YANG_ADDELEM(((struct lys_node_rpc_action *)tpdf_parent)->tpdf, | |
((struct lys_node_rpc_action *)tpdf_parent)->tpdf_size); | |
break; | |
case LYS_INPUT: | |
case LYS_OUTPUT: | |
YANG_ADDELEM(((struct lys_node_inout *)tpdf_parent)->tpdf, | |
((struct lys_node_inout *)tpdf_parent)->tpdf_size); | |
break; | |
case LYS_NOTIF: | |
YANG_ADDELEM(((struct lys_node_notif *)tpdf_parent)->tpdf, | |
((struct lys_node_notif *)tpdf_parent)->tpdf_size); | |
break; | |
default: | |
/* another type of nodetype is error*/ | |
LOGINT; | |
free(s); | |
YYABORT; | |
} | |
} | |
((struct lys_tpdf *)actual)->name = lydict_insert_zc(param->module->ctx, s); | |
((struct lys_tpdf *)actual)->module = trg; | |
s = NULL; | |
actual_type = TYPEDEF_KEYWORD; | |
} | |
typedef_stmt: TYPEDEF_KEYWORD sep typedef_arg_str | |
'{' stmtsep | |
type_opt_stmt | |
'}' { if (!($6.node.flag & LYS_TYPE_DEF)) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "type", "typedef"); | |
YYABORT; | |
} | |
actual_type = $3.token; | |
actual = $3.actual; | |
} | |
type_opt_stmt: @EMPTYDIR@ { $$.node.ptr_tpdf = actual; | |
$$.node.flag = 0; | |
} | |
| type_opt_stmt type_stmt stmtsep { $1.node.flag |= LYS_TYPE_DEF; | |
$$ = $1; | |
} | |
| type_opt_stmt units_stmt { if (yang_read_units(trg, $1.node.ptr_tpdf, s, TYPEDEF_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| type_opt_stmt default_stmt { if (yang_read_default(trg, $1.node.ptr_tpdf, s, TYPEDEF_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| type_opt_stmt status_stmt { if ($1.node.ptr_tpdf->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "status", "typedef"); | |
YYABORT; | |
} | |
$1.node.ptr_tpdf->flags |= $2; | |
} | |
| type_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_tpdf, s, "typedef", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| type_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_tpdf, s, "typedef", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
type_stmt: TYPE_KEYWORD sep type_arg_str type_end | |
{ actual_type = $3.token; | |
actual = $3.actual; | |
} | |
type_arg_str: identifier_ref_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_type(trg, actual, s, actual_type))) { | |
YYABORT; | |
} | |
s = NULL; | |
actual_type = TYPE_KEYWORD; | |
} | |
type_end: ';' | |
| '{' stmtsep | |
type_body_stmts | |
'}' | |
type_body_stmts: some_restrictions { if (((struct yang_type *)actual)->base == LY_TYPE_STRING && | |
((struct yang_type *)actual)->type->info.str.pat_count) { | |
struct lys_restr *tmp; | |
tmp = realloc(((struct yang_type *)actual)->type->info.str.patterns, | |
((struct yang_type *)actual)->type->info.str.pat_count * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct yang_type *)actual)->type->info.str.patterns = tmp; | |
} | |
if (((struct yang_type *)actual)->base == LY_TYPE_UNION) { | |
struct lys_type *tmp; | |
tmp = realloc(((struct yang_type *)actual)->type->info.uni.types, | |
((struct yang_type *)actual)->type->info.uni.count * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct yang_type *)actual)->type->info.uni.types = tmp; | |
} | |
if (((struct yang_type *)actual)->base == LY_TYPE_IDENT) { | |
struct lys_ident **tmp; | |
tmp = realloc(((struct yang_type *)actual)->type->info.ident.ref, | |
((struct yang_type *)actual)->type->info.ident.count* sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct yang_type *)actual)->type->info.ident.ref = tmp; | |
} | |
} | |
| enum_specification | |
| bits_specification | |
some_restrictions: @EMPTYDIR@ | |
| some_restrictions require_instance_stmt { if (yang_read_require_instance(actual, $2)) { | |
YYABORT; | |
} | |
} | |
| some_restrictions path_stmt { /* leafref_specification */ | |
if (yang_read_leafref_path(trg, actual, s)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| some_restrictions base_stmt { /* identityref_specification */ | |
if (((struct yang_type *)actual)->base && ((struct yang_type *)actual)->base != LY_TYPE_IDENT) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "base"); | |
return EXIT_FAILURE; | |
} | |
((struct yang_type *)actual)->base = LY_TYPE_IDENT; | |
yang_type = actual; | |
YANG_ADDELEM(((struct yang_type *)actual)->type->info.ident.ref, | |
((struct yang_type *)actual)->type->info.ident.count); | |
*((struct lys_ident **)actual) = (struct lys_ident *)s; | |
actual = yang_type; | |
s = NULL; | |
} | |
| some_restrictions length_stmt stmtsep | |
| some_restrictions pattern_stmt stmtsep | |
| some_restrictions fraction_digits_stmt | |
| some_restrictions range_stmt stmtsep | |
| some_restrictions union_stmt stmtsep | |
union_stmt: union_spec type_stmt { actual_type = $1.token; | |
actual = $1.actual; | |
} | |
union_spec: @EMPTYDIR@ { struct yang_type *stype = (struct yang_type *)actual; | |
$$.token = actual_type; | |
$$.actual = actual; | |
if (stype->base != 0 && stype->base != LY_TYPE_UNION) { | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Unexpected type statement."); | |
YYABORT; | |
} | |
stype->base = LY_TYPE_UNION; | |
if (strcmp(stype->name, "union")) { | |
/* type can be a substatement only in "union" type, not in derived types */ | |
LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "type", "derived type"); | |
YYABORT; | |
} | |
YANG_ADDELEM(stype->type->info.uni.types, stype->type->info.uni.count) | |
actual_type = UNION_KEYWORD; | |
} | |
fraction_digits_arg: fraction_digits_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = FRACTION_DIGITS_KEYWORD; | |
} | |
fraction_digits_stmt: FRACTION_DIGITS_KEYWORD sep fraction_digits_arg | |
stmtend { if (yang_read_fraction(actual, $3)) { | |
YYABORT; | |
} | |
} | |
fraction_digits_arg_str: positive_integer_value optsep { $$ = $1; } | |
| string_1 { char *endptr = NULL; | |
unsigned long val; | |
errno = 0; | |
val = strtoul(s, &endptr, 10); | |
if (*endptr || s[0] == '-' || errno || val == 0 || val > UINT32_MAX) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "fraction-digits"); | |
free(s); | |
s = NULL; | |
YYABORT; | |
} | |
$$ = (uint32_t) val; | |
free(s); | |
s =NULL; | |
} | |
length_stmt: LENGTH_KEYWORD sep length_arg_str length_end | |
{ actual = $3.actual; | |
actual_type = $3.token; | |
} | |
length_arg_str: string { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_length(trg, actual, s))) { | |
YYABORT; | |
} | |
actual_type = LENGTH_KEYWORD; | |
s = NULL; | |
} | |
length_end: ';' | |
| '{' stmtsep | |
message_opt_stmt | |
'}' | |
message_opt_stmt: @EMPTYDIR@ { switch (actual_type) { | |
case MUST_KEYWORD: | |
$$ = "must"; | |
break; | |
case LENGTH_KEYWORD: | |
$$ = "length"; | |
break; | |
case RANGE_KEYWORD: | |
$$ = "range"; | |
break; | |
default: | |
LOGINT; | |
YYABORT; | |
break; | |
} | |
} | |
| message_opt_stmt error_message_stmt { if (yang_read_message(trg, actual, s, $1, ERROR_MESSAGE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| message_opt_stmt error_app_tag_stmt { if (yang_read_message(trg, actual, s, $1, ERROR_APP_TAG_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| message_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, $1, NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| message_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, $1, NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
pattern_sep: sep { $$.token = actual_type; | |
$$.actual = actual; | |
actual_type = PATTERN_KEYWORD; | |
} | |
pattern_stmt: PATTERN_KEYWORD pattern_sep pattern_arg_str pattern_end { if (yang_read_pattern(trg, actual, $3, $4)) { | |
YYABORT; | |
} | |
actual_type = $2.token; | |
actual = $2.actual; | |
} | |
pattern_arg_str: string { if (((struct yang_type *)actual)->base != 0 && ((struct yang_type *)actual)->base != LY_TYPE_STRING) { | |
free(s); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Unexpected pattern statement."); | |
YYABORT; | |
} | |
((struct yang_type *)actual)->base = LY_TYPE_STRING; | |
yang_type = actual; | |
YANG_ADDELEM(((struct yang_type *)actual)->type->info.str.patterns, | |
((struct yang_type *)actual)->type->info.str.pat_count); | |
$$ = s; | |
s = NULL; | |
} | |
pattern_end: ';' { $$ = 0x06; } | |
| '{' stmtsep | |
pattern_opt_stmt | |
'}' { $$ = $3; } | |
pattern_opt_stmt: @EMPTYDIR@ { $$ = 0x06; /* ACK */ } | |
| pattern_opt_stmt modifier_stmt { if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, "modifier"); | |
YYABORT; | |
} | |
if ($1 != 0x06) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "modifier", "pattern"); | |
YYABORT; | |
} | |
$$ = $2; | |
} | |
| pattern_opt_stmt error_message_stmt { if (yang_read_message(trg, actual, s, "pattern", ERROR_MESSAGE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| pattern_opt_stmt error_app_tag_stmt { if (yang_read_message(trg, actual, s, "pattern", ERROR_APP_TAG_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| pattern_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "pattern", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| pattern_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "pattern", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
modifier_arg: string { backup_type = actual_type; | |
actual_type = MODIFIER_KEYWORD; | |
} | |
modifier_stmt: MODIFIER_KEYWORD sep modifier_arg stmtend { if (!strcmp(s, "invert-match")) { | |
$$ = 0x15; | |
free(s); | |
s = NULL; | |
} else { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, s); | |
free(s); | |
YYABORT; | |
} | |
} | |
enum_specification: enum_stmt stmtsep enum_stmts { struct lys_type_enum * tmp; | |
cnt_val = 0; | |
tmp = realloc(((struct yang_type *)actual)->type->info.enums.enm, | |
((struct yang_type *)actual)->type->info.enums.count * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct yang_type *)actual)->type->info.enums.enm = tmp; | |
} | |
enum_stmts: @EMPTYDIR@ | |
| enum_stmts enum_stmt stmtsep; | |
enum_stmt: ENUM_KEYWORD sep enum_arg_str enum_end | |
{ if (yang_check_enum(yang_type, actual, &cnt_val, is_value)) { | |
YYABORT; | |
} | |
actual = $3.actual; | |
actual_type = $3.token; | |
} | |
enum_arg_str: string { $$.token = actual_type; | |
$$.actual = yang_type = actual; | |
YANG_ADDELEM(((struct yang_type *)actual)->type->info.enums.enm, ((struct yang_type *)actual)->type->info.enums.count); | |
if (yang_read_enum(trg, yang_type, actual, s)) { | |
YYABORT; | |
} | |
s = NULL; | |
is_value = 0; | |
actual_type = ENUM_KEYWORD; | |
} | |
enum_end: ';' | |
| '{' stmtsep | |
enum_opt_stmt | |
'}' { if (((struct lys_type_enum *)actual)->iffeature_size) { | |
struct lys_iffeature *tmp; | |
tmp = realloc(((struct lys_type_enum *)actual)->iffeature, | |
((struct lys_type_enum *)actual)->iffeature_size * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct lys_type_enum *)actual)->iffeature = tmp; | |
} | |
} | |
enum_opt_stmt: @EMPTYDIR@ | |
| enum_opt_stmt if_feature_stmt stmtsep | |
| enum_opt_stmt value_stmt { if (is_value) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "value", "enum"); | |
YYABORT; | |
} | |
is_value = 1; | |
} | |
| enum_opt_stmt status_stmt { if (yang_check_flags((uint16_t*)&((struct lys_type_enum *)actual)->flags, LYS_STATUS_MASK, "status", "enum", $2, 1)) { | |
YYABORT; | |
} | |
} | |
| enum_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "enum", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| enum_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "enum", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
value_arg: integer_value_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = VALUE_KEYWORD; | |
} | |
value_stmt: VALUE_KEYWORD sep value_arg | |
stmtend { ((struct lys_type_enum *)actual)->value = $3; | |
/* keep the highest enum value for automatic increment */ | |
if ($3 >= cnt_val) { | |
cnt_val = $3; | |
cnt_val++; | |
} | |
} | |
integer_value_arg_str: integer_value optsep { $$ = $1; } | |
| string_1 { /* convert it to int32_t */ | |
int64_t val; | |
char *endptr; | |
val = strtoll(s, &endptr, 10); | |
if (val < INT32_MIN || val > INT32_MAX || *endptr) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "value"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
$$ = (int32_t) val; | |
} | |
range_stmt: RANGE_KEYWORD sep range_arg_str range_end { actual_type = $3.token; | |
actual = $3.actual; | |
} | |
range_end: ';' | |
| '{' stmtsep | |
message_opt_stmt | |
'}' | |
; | |
path_arg: path_arg_str { backup_type = actual_type; | |
actual_type = PATH_KEYWORD; | |
} | |
path_stmt: PATH_KEYWORD sep path_arg stmtend | |
require_instance_arg: require_instance_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = REQUIRE_INSTANCE_KEYWORD; | |
} | |
require_instance_stmt: REQUIRE_INSTANCE_KEYWORD sep require_instance_arg stmtend { $$ = $3; } | |
require_instance_arg_str: TRUE_KEYWORD optsep { $$ = 1; } | |
| FALSE_KEYWORD optsep { $$ = -1; } | |
| string_1 { if (!strcmp(s,"true")) { | |
$$ = 1; | |
} else if (!strcmp(s,"false")) { | |
$$ = -1; | |
} else { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "require-instance"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
} | |
bits_specification: bit_stmt bit_stmts { struct lys_type_bit * tmp; | |
cnt_val = 0; | |
tmp = realloc(((struct yang_type *)actual)->type->info.bits.bit, | |
((struct yang_type *)actual)->type->info.bits.count * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct yang_type *)actual)->type->info.bits.bit = tmp; | |
} | |
bit_stmts: @EMPTYDIR@ | |
| bit_stmts bit_stmt; | |
bit_stmt: BIT_KEYWORD sep bit_arg_str bit_end | |
stmtsep { if (yang_check_bit(yang_type, actual, &cnt_val, is_value)) { | |
YYABORT; | |
} | |
actual = $3.actual; | |
actual_type = $3.token; | |
} | |
bit_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = yang_type = actual; | |
YANG_ADDELEM(((struct yang_type *)actual)->type->info.bits.bit, | |
((struct yang_type *)actual)->type->info.bits.count); | |
if (yang_read_bit(trg, yang_type, actual, s)) { | |
YYABORT; | |
} | |
s = NULL; | |
is_value = 0; | |
actual_type = BIT_KEYWORD; | |
} | |
bit_end: ';' | |
| '{' stmtsep | |
bit_opt_stmt | |
'}' { if (((struct lys_type_bit *)actual)->iffeature_size) { | |
struct lys_iffeature *tmp; | |
tmp = realloc(((struct lys_type_bit *)actual)->iffeature, | |
((struct lys_type_bit *)actual)->iffeature_size * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
((struct lys_type_bit *)actual)->iffeature = tmp; | |
} | |
} | |
bit_opt_stmt: @EMPTYDIR@ | |
| bit_opt_stmt if_feature_stmt stmtsep | |
| bit_opt_stmt position_stmt { if (is_value) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "position", "bit"); | |
YYABORT; | |
} | |
is_value = 1; | |
} | |
| bit_opt_stmt status_stmt { if (yang_check_flags((uint16_t*)&((struct lys_type_bit *)actual)->flags, | |
LYS_STATUS_MASK, "status", "bit", $2, 1)) { | |
YYABORT; | |
} | |
} | |
| bit_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "bit", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| bit_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "bit", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
position_value_arg: position_value_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = POSITION_KEYWORD; | |
} | |
position_stmt: POSITION_KEYWORD sep position_value_arg | |
stmtend { ((struct lys_type_bit *)actual)->pos = $3; | |
/* keep the highest position value for automatic increment */ | |
if ($3 >= cnt_val) { | |
cnt_val = $3; | |
cnt_val++; | |
} | |
} | |
position_value_arg_str: non_negative_integer_value optsep { $$ = $1; } | |
| string_1 { /* convert it to uint32_t */ | |
unsigned long val; | |
char *endptr = NULL; | |
errno = 0; | |
val = strtoul(s, &endptr, 10); | |
if (s[0] == '-' || *endptr || errno || val > UINT32_MAX) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "position"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
$$ = (uint32_t) val; | |
} | |
error_message_arg: string { backup_type = actual_type; | |
actual_type = ERROR_MESSAGE_KEYWORD; | |
} | |
error_message_stmt: ERROR_MESSAGE_KEYWORD sep error_message_arg stmtend | |
error_app_tag_arg: string { backup_type = actual_type; | |
actual_type = ERROR_APP_TAG_KEYWORD; | |
} | |
error_app_tag_stmt: ERROR_APP_TAG_KEYWORD sep error_app_tag_arg stmtend | |
units_arg: string { backup_type = actual_type; | |
actual_type = UNITS_KEYWORD; | |
} | |
units_stmt: UNITS_KEYWORD sep units_arg stmtend | |
default_arg: string { backup_type = actual_type; | |
actual_type = DEFAULT_KEYWORD; | |
} | |
default_stmt: DEFAULT_KEYWORD sep default_arg stmtend | |
grouping_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_GROUPING, sizeof(struct lys_node_grp)))) { | |
YYABORT; | |
} | |
s = NULL; | |
data_node = actual; | |
actual_type = GROUPING_KEYWORD; | |
} | |
grouping_stmt: GROUPING_KEYWORD sep grouping_arg_str grouping_end | |
{ LOGDBG("YANG: finished parsing grouping statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
grouping_end: ';' | |
| '{' stmtsep | |
grouping_opt_stmt | |
'}' | |
grouping_opt_stmt: @EMPTYDIR@ { $$.grouping = actual; } | |
| grouping_opt_stmt status_stmt { if ($1.grouping->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.grouping, "status", "grouping"); | |
YYABORT; | |
} | |
$1.grouping->flags |= $2; | |
} | |
| grouping_opt_stmt description_stmt { if (yang_read_description(trg, $1.grouping, s, "grouping", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| grouping_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.grouping, s, "grouping", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| grouping_opt_stmt grouping_stmt stmtsep | |
| grouping_opt_stmt typedef_stmt stmtsep | |
| grouping_opt_stmt data_def_stmt stmtsep | |
| grouping_opt_stmt action_stmt stmtsep | |
| grouping_opt_stmt notification_stmt stmtsep { if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, $1.grouping, "notification"); | |
YYABORT; | |
} | |
} | |
data_def_stmt: container_stmt | |
| leaf_stmt | |
| leaf_list_stmt | |
| list_stmt | |
| choice_stmt | |
| anyxml_stmt | |
| anydata_stmt | |
| uses_stmt | |
; | |
container_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_CONTAINER, sizeof(struct lys_node_container)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = CONTAINER_KEYWORD; | |
} | |
container_stmt: CONTAINER_KEYWORD sep container_arg_str container_end | |
{ LOGDBG("YANG: finished parsing container statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
container_end: ';' | |
| '{' stmtsep | |
container_opt_stmt | |
'}' { void *tmp; | |
if ($3.container->iffeature_size) { | |
tmp = realloc($3.container->iffeature, $3.container->iffeature_size * sizeof *$3.container->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.container->iffeature = tmp; | |
} | |
if ($3.container->must_size) { | |
tmp = realloc($3.container->must, $3.container->must_size * sizeof *$3.container->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.container->must = tmp; | |
} | |
} | |
container_opt_stmt: @EMPTYDIR@ { $$.container = actual; } | |
| container_opt_stmt when_stmt stmtsep | |
| container_opt_stmt if_feature_stmt stmtsep | |
| container_opt_stmt must_stmt stmtsep | |
| container_opt_stmt presence_stmt { if (yang_read_presence(trg, $1.container, s)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| container_opt_stmt config_stmt { if ($1.container->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.container, "config", "container"); | |
YYABORT; | |
} | |
$1.container->flags |= $2; | |
} | |
| container_opt_stmt status_stmt { if ($1.container->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.container, "status", "container"); | |
YYABORT; | |
} | |
$1.container->flags |= $2; | |
} | |
| container_opt_stmt description_stmt { if (yang_read_description(trg, $1.container, s, "container", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| container_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.container, s, "container", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| container_opt_stmt grouping_stmt stmtsep | |
| container_opt_stmt action_stmt stmtsep | |
| container_opt_stmt notification_stmt stmtsep { if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, $1.container, "notification"); | |
YYABORT; | |
} | |
} | |
| container_opt_stmt typedef_stmt stmtsep | |
| container_opt_stmt data_def_stmt stmtsep | |
leaf_stmt: LEAF_KEYWORD sep leaf_arg_str | |
'{' stmtsep | |
leaf_opt_stmt | |
'}' { void *tmp; | |
if (!($6.node.flag & LYS_TYPE_DEF)) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, $6.node.ptr_leaf, "type", "leaf"); | |
YYABORT; | |
} | |
if ($6.node.ptr_leaf->dflt && ($6.node.ptr_leaf->flags & LYS_MAND_TRUE)) { | |
/* RFC 6020, 7.6.4 - default statement must not with mandatory true */ | |
LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, $6.node.ptr_leaf, "mandatory", "leaf"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $6.node.ptr_leaf, "The \"mandatory\" statement is forbidden on leaf with \"default\"."); | |
YYABORT; | |
} | |
if ($6.node.ptr_leaf->iffeature_size) { | |
tmp = realloc($6.node.ptr_leaf->iffeature, $6.node.ptr_leaf->iffeature_size * sizeof *$6.node.ptr_leaf->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_leaf->iffeature = tmp; | |
} | |
if ($6.node.ptr_leaf->must_size) { | |
tmp = realloc($6.node.ptr_leaf->must, $6.node.ptr_leaf->must_size * sizeof *$6.node.ptr_leaf->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_leaf->must = tmp; | |
} | |
LOGDBG("YANG: finished parsing leaf statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
leaf_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_LEAF, sizeof(struct lys_node_leaf)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = LEAF_KEYWORD; | |
} | |
leaf_opt_stmt: @EMPTYDIR@ { $$.node.ptr_leaf = actual; | |
$$.node.flag = 0; | |
} | |
| leaf_opt_stmt when_stmt { actual = $1.node.ptr_leaf; | |
actual_type = LEAF_KEYWORD; | |
} | |
stmtsep | |
| leaf_opt_stmt if_feature_stmt stmtsep | |
| leaf_opt_stmt type_stmt { actual = $1.node.ptr_leaf; | |
actual_type = LEAF_KEYWORD; | |
$1.node.flag |= LYS_TYPE_DEF; | |
} | |
stmtsep { $$ = $1;} | |
| leaf_opt_stmt units_stmt { if (yang_read_units(trg, $1.node.ptr_leaf, s, LEAF_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| leaf_opt_stmt must_stmt { actual = $1.node.ptr_leaf; | |
actual_type = LEAF_KEYWORD; | |
} | |
stmtsep | |
| leaf_opt_stmt default_stmt { if (yang_read_default(trg, $1.node.ptr_leaf, s, LEAF_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| leaf_opt_stmt config_stmt { if ($1.node.ptr_leaf->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaf, "config", "leaf"); | |
YYABORT; | |
} | |
$1.node.ptr_leaf->flags |= $2; | |
} | |
| leaf_opt_stmt mandatory_stmt { if ($1.node.ptr_leaf->flags & LYS_MAND_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaf, "mandatory", "leaf"); | |
YYABORT; | |
} | |
$1.node.ptr_leaf->flags |= $2; | |
} | |
| leaf_opt_stmt status_stmt { if ($1.node.ptr_leaf->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaf, "status", "leaf"); | |
YYABORT; | |
} | |
$1.node.ptr_leaf->flags |= $2; | |
} | |
| leaf_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_leaf, s, "leaf", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| leaf_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_leaf, s, "leaf", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
leaf_list_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_LEAFLIST, sizeof(struct lys_node_leaflist)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = LEAF_LIST_KEYWORD; | |
} | |
leaf_list_stmt: LEAF_LIST_KEYWORD sep leaf_list_arg_str | |
'{' stmtsep | |
leaf_list_opt_stmt | |
'}' { void *tmp; | |
if ($6.node.ptr_leaflist->flags & LYS_CONFIG_R) { | |
/* RFC 6020, 7.7.5 - ignore ordering when the list represents state data | |
* ignore oredering MASK - 0x7F | |
*/ | |
$6.node.ptr_leaflist->flags &= 0x7F; | |
} | |
if (!($6.node.flag & LYS_TYPE_DEF)) { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, $6.node.ptr_leaflist, "type", "leaf-list"); | |
YYABORT; | |
} | |
if ($6.node.ptr_leaflist->dflt_size && $6.node.ptr_leaflist->min) { | |
LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, $6.node.ptr_leaflist, "min-elements", "leaf-list"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $6.node.ptr_leaflist, | |
"The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement."); | |
YYABORT; | |
} | |
if ($6.node.ptr_leaflist->iffeature_size) { | |
tmp = realloc($6.node.ptr_leaflist->iffeature, $6.node.ptr_leaflist->iffeature_size * sizeof *$6.node.ptr_leaflist->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_leaflist->iffeature = tmp; | |
} | |
if ($6.node.ptr_leaflist->must_size) { | |
tmp = realloc($6.node.ptr_leaflist->must, $6.node.ptr_leaflist->must_size * sizeof *$6.node.ptr_leaflist->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_leaflist->must = tmp; | |
} | |
if ($6.node.ptr_leaflist->dflt_size) { | |
tmp = realloc($6.node.ptr_leaflist->dflt, $6.node.ptr_leaflist->dflt_size * sizeof *$6.node.ptr_leaflist->dflt); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_leaflist->dflt = tmp; | |
} | |
LOGDBG("YANG: finished parsing leaf-list statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
leaf_list_opt_stmt: @EMPTYDIR@ { $$.node.ptr_leaflist = actual; | |
$$.node.flag = 0; | |
} | |
| leaf_list_opt_stmt when_stmt { actual = $1.node.ptr_leaflist; | |
actual_type = LEAF_LIST_KEYWORD; | |
} | |
stmtsep | |
| leaf_list_opt_stmt if_feature_stmt stmtsep | |
| leaf_list_opt_stmt type_stmt { actual = $1.node.ptr_leaflist; | |
actual_type = LEAF_LIST_KEYWORD; | |
$1.node.flag |= LYS_TYPE_DEF; | |
} | |
stmtsep { $$ = $1; } | |
| leaf_list_opt_stmt default_stmt { if (trg->version < 2) { | |
free(s); | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, $1.node.ptr_leaflist, "default"); | |
YYABORT; | |
} | |
YANG_ADDELEM($1.node.ptr_leaflist->dflt, | |
$1.node.ptr_leaflist->dflt_size); | |
(*(const char **)actual) = lydict_insert_zc(param->module->ctx, s); | |
s = NULL; | |
actual = $1.node.ptr_leaflist; | |
} | |
| leaf_list_opt_stmt units_stmt { if (yang_read_units(trg, $1.node.ptr_leaflist, s, LEAF_LIST_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| leaf_list_opt_stmt must_stmt { actual = $1.node.ptr_leaflist; | |
actual_type = LEAF_LIST_KEYWORD; | |
} | |
stmtsep | |
| leaf_list_opt_stmt config_stmt { if ($1.node.ptr_leaflist->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaflist, "config", "leaf-list"); | |
YYABORT; | |
} | |
$1.node.ptr_leaflist->flags |= $2; | |
} | |
| leaf_list_opt_stmt min_elements_stmt { if ($1.node.flag & LYS_MIN_ELEMENTS) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaflist, "min-elements", "leaf-list"); | |
YYABORT; | |
} | |
$1.node.ptr_leaflist->min = $2; | |
$1.node.flag |= LYS_MIN_ELEMENTS; | |
$$ = $1; | |
if ($1.node.ptr_leaflist->max && ($1.node.ptr_leaflist->min > $1.node.ptr_leaflist->max)) { | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_leaflist, "Invalid value \"%d\" of \"%s\".", $2, "min-elements"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_leaflist, "\"min-elements\" is bigger than \"max-elements\"."); | |
YYABORT; | |
} | |
} | |
| leaf_list_opt_stmt max_elements_stmt { if ($1.node.flag & LYS_MAX_ELEMENTS) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaflist, "max-elements", "leaf-list"); | |
YYABORT; | |
} | |
$1.node.ptr_leaflist->max = $2; | |
$1.node.flag |= LYS_MAX_ELEMENTS; | |
$$ = $1; | |
if ($1.node.ptr_leaflist->min > $1.node.ptr_leaflist->max) { | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_leaflist, "Invalid value \"%d\" of \"%s\".", $2, "max-elements"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_leaflist, "\"max-elements\" is smaller than \"min-elements\"."); | |
YYABORT; | |
} | |
} | |
| leaf_list_opt_stmt ordered_by_stmt { if ($1.node.flag & LYS_ORDERED_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaflist, "ordered by", "leaf-list"); | |
YYABORT; | |
} | |
if ($2 & LYS_USERORDERED) { | |
$1.node.ptr_leaflist->flags |= LYS_USERORDERED; | |
} | |
$1.node.flag |= $2; | |
$$ = $1; | |
} | |
| leaf_list_opt_stmt status_stmt { if ($1.node.ptr_leaflist->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_leaflist, "status", "leaf-list"); | |
YYABORT; | |
} | |
$1.node.ptr_leaflist->flags |= $2; | |
} | |
| leaf_list_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_leaflist, s, "leaf-list", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| leaf_list_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_leaflist, s, "leaf-list", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
list_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_LIST, sizeof(struct lys_node_list)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = LIST_KEYWORD; | |
} | |
list_stmt: LIST_KEYWORD sep list_arg_str | |
'{' stmtsep | |
list_opt_stmt | |
'}' { void *tmp; | |
if ($6.node.ptr_list->iffeature_size) { | |
tmp = realloc($6.node.ptr_list->iffeature, $6.node.ptr_list->iffeature_size * sizeof *$6.node.ptr_list->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_list->iffeature = tmp; | |
} | |
if ($6.node.ptr_list->must_size) { | |
tmp = realloc($6.node.ptr_list->must, $6.node.ptr_list->must_size * sizeof *$6.node.ptr_list->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_list->must = tmp; | |
} | |
if ($6.node.ptr_list->tpdf_size) { | |
tmp = realloc($6.node.ptr_list->tpdf, $6.node.ptr_list->tpdf_size * sizeof *$6.node.ptr_list->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_list->tpdf = tmp; | |
} | |
if ($6.node.ptr_list->unique_size) { | |
tmp = realloc($6.node.ptr_list->unique, $6.node.ptr_list->unique_size * sizeof *$6.node.ptr_list->unique); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$6.node.ptr_list->unique = tmp; | |
} | |
LOGDBG("YANG: finished parsing list statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
list_opt_stmt: @EMPTYDIR@ { $$.node.ptr_list = actual; | |
$$.node.flag = 0; | |
} | |
| list_opt_stmt when_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
} | |
stmtsep | |
| list_opt_stmt if_feature_stmt stmtsep | |
| list_opt_stmt must_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
} | |
stmtsep | |
| list_opt_stmt key_stmt { if ($1.node.ptr_list->keys) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "key", "list"); | |
free(s); | |
YYABORT; | |
} | |
$1.node.ptr_list->keys = (struct lys_node_leaf **)s; | |
$$ = $1; | |
s = NULL; | |
} | |
| list_opt_stmt unique_stmt { YANG_ADDELEM($1.node.ptr_list->unique, $1.node.ptr_list->unique_size); | |
((struct lys_unique *)actual)->expr = (const char **)s; | |
$$ = $1; | |
s = NULL; | |
actual = $1.node.ptr_list; | |
} | |
| list_opt_stmt config_stmt { if ($1.node.ptr_list->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "config", "list"); | |
YYABORT; | |
} | |
$1.node.ptr_list->flags |= $2; | |
} | |
| list_opt_stmt min_elements_stmt { if ($1.node.flag & LYS_MIN_ELEMENTS) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "min-elements", "list"); | |
YYABORT; | |
} | |
$1.node.ptr_list->min = $2; | |
$1.node.flag |= LYS_MIN_ELEMENTS; | |
$$ = $1; | |
if ($1.node.ptr_list->max && ($1.node.ptr_list->min > $1.node.ptr_list->max)) { | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_list, "Invalid value \"%d\" of \"%s\".", $2, "min-elements"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_list, "\"min-elements\" is bigger than \"max-elements\"."); | |
YYABORT; | |
} | |
} | |
| list_opt_stmt max_elements_stmt { if ($1.node.flag & LYS_MAX_ELEMENTS) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "max-elements", "list"); | |
YYABORT; | |
} | |
$1.node.ptr_list->max = $2; | |
$1.node.flag |= LYS_MAX_ELEMENTS; | |
$$ = $1; | |
if ($1.node.ptr_list->min > $1.node.ptr_list->max) { | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_list, "Invalid value \"%d\" of \"%s\".", $2, "min-elements"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $1.node.ptr_list, "\"max-elements\" is smaller than \"min-elements\"."); | |
YYABORT; | |
} | |
} | |
| list_opt_stmt ordered_by_stmt { if ($1.node.flag & LYS_ORDERED_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "ordered by", "list"); | |
YYABORT; | |
} | |
if ($2 & LYS_USERORDERED) { | |
$1.node.ptr_list->flags |= LYS_USERORDERED; | |
} | |
$1.node.flag |= $2; | |
$$ = $1; | |
} | |
| list_opt_stmt status_stmt { if ($1.node.ptr_list->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_list, "status", "list"); | |
YYABORT; | |
} | |
$1.node.ptr_list->flags |= $2; | |
} | |
| list_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_list, s, "list", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| list_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_list, s, "list", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| list_opt_stmt typedef_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
} | |
stmtsep | |
| list_opt_stmt grouping_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| list_opt_stmt action_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| list_opt_stmt notification_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
data_node = actual; | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, $1.node.ptr_list, "notification"); | |
YYABORT; | |
} | |
} | |
stmtsep | |
| list_opt_stmt data_def_stmt { actual = $1.node.ptr_list; | |
actual_type = LIST_KEYWORD; | |
$1.node.flag |= LYS_DATADEF; | |
data_node = actual; | |
} | |
stmtsep { $$ = $1; } | |
choice_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_CHOICE, sizeof(struct lys_node_choice)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = CHOICE_KEYWORD; | |
} | |
choice_stmt: CHOICE_KEYWORD sep choice_arg_str choice_end | |
{ LOGDBG("YANG: finished parsing choice statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
choice_end: ';' | |
| '{' stmtsep | |
choice_opt_stmt | |
'}' { struct lys_iffeature *tmp; | |
if (($3.node.ptr_choice->flags & LYS_MAND_TRUE) && $3.node.ptr_choice->dflt) { | |
LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, $3.node.ptr_choice, "default", "choice"); | |
LOGVAL(LYE_SPEC, LY_VLOG_LYS, $3.node.ptr_choice, "The \"default\" statement is forbidden on choices with \"mandatory\"."); | |
YYABORT; | |
} | |
if ($3.node.ptr_choice->iffeature_size) { | |
tmp = realloc($3.node.ptr_choice->iffeature, $3.node.ptr_choice->iffeature_size * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.node.ptr_choice->iffeature = tmp; | |
} | |
} | |
choice_opt_stmt: @EMPTYDIR@ { $$.node.ptr_choice = actual; | |
$$.node.flag = 0; | |
} | |
| choice_opt_stmt when_stmt { actual = $1.node.ptr_choice; | |
actual_type = CHOICE_KEYWORD; | |
} | |
stmtsep { $$ = $1; } | |
| choice_opt_stmt if_feature_stmt stmtsep | |
| choice_opt_stmt default_stmt { if ($1.node.flag & LYS_CHOICE_DEFAULT) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_choice, "default", "choice"); | |
free(s); | |
YYABORT; | |
} | |
$1.node.ptr_choice->dflt = (struct lys_node *) s; | |
s = NULL; | |
$$ = $1; | |
$$.node.flag |= LYS_CHOICE_DEFAULT; | |
} | |
| choice_opt_stmt config_stmt { if ($1.node.ptr_choice->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_choice, "config", "choice"); | |
YYABORT; | |
} | |
$1.node.ptr_choice->flags |= $2; | |
$$ = $1; | |
} | |
| choice_opt_stmt mandatory_stmt { if ($1.node.ptr_choice->flags & LYS_MAND_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_choice, "mandatory", "choice"); | |
YYABORT; | |
} | |
$1.node.ptr_choice->flags |= $2; | |
$$ = $1; | |
} | |
| choice_opt_stmt status_stmt { if ($1.node.ptr_choice->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_choice, "status", "choice"); | |
YYABORT; | |
} | |
$1.node.ptr_choice->flags |= $2; | |
$$ = $1; | |
} | |
| choice_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_choice, s, "choice", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| choice_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_choice, s, "choice", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| choice_opt_stmt short_case_case_stmt { actual = $1.node.ptr_choice; | |
actual_type = CHOICE_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep { $$ = $1; } | |
short_case_case_stmt: short_case_stmt | |
| case_stmt | |
; | |
short_case_stmt: container_stmt | |
| leaf_stmt | |
| leaf_list_stmt | |
| list_stmt | |
| anyxml_stmt | |
| anydata_stmt | |
| choice_stmt { if (trg->version < 2 ) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, actual, "choice"); | |
YYABORT; | |
} | |
} | |
; | |
case_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_CASE, sizeof(struct lys_node_case)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = CASE_KEYWORD; | |
} | |
case_stmt: CASE_KEYWORD sep case_arg_str case_end | |
{ LOGDBG("YANG: finished parsing case statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
case_end: ';' | |
| '{' stmtsep | |
case_opt_stmt | |
'}' { struct lys_iffeature *tmp; | |
if ($3.cs->iffeature_size) { | |
tmp = realloc($3.cs->iffeature, $3.cs->iffeature_size * sizeof *tmp); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.cs->iffeature = tmp; | |
} | |
} | |
case_opt_stmt: @EMPTYDIR@ { $$.cs = actual; } | |
| case_opt_stmt when_stmt { actual = $1.cs; | |
actual_type = CASE_KEYWORD; | |
} | |
stmtsep | |
| case_opt_stmt if_feature_stmt stmtsep | |
| case_opt_stmt status_stmt { if ($1.cs->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.cs, "status", "case"); | |
YYABORT; | |
} | |
$1.cs->flags |= $2; | |
} | |
| case_opt_stmt description_stmt { if (yang_read_description(trg, $1.cs, s, "case", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| case_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.cs, s, "case", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| case_opt_stmt data_def_stmt { actual = $1.cs; | |
actual_type = CASE_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
anyxml_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_ANYXML, sizeof(struct lys_node_anydata)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = ANYXML_KEYWORD; | |
} | |
anyxml_stmt: ANYXML_KEYWORD sep anyxml_arg_str anyxml_end | |
{ LOGDBG("YANG: finished parsing anyxml statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
anydata_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_ANYDATA, sizeof(struct lys_node_anydata)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = ANYDATA_KEYWORD; | |
} | |
anydata_stmt: ANYDATA_KEYWORD sep anydata_arg_str anyxml_end | |
{ LOGDBG("YANG: finished parsing anydata statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
anyxml_end: ';' | |
| '{' stmtsep | |
anyxml_opt_stmt | |
'}' { void *tmp; | |
if ($3.node.ptr_anydata->iffeature_size) { | |
tmp = realloc($3.node.ptr_anydata->iffeature, $3.node.ptr_anydata->iffeature_size * sizeof *$3.node.ptr_anydata->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.node.ptr_anydata->iffeature = tmp; | |
} | |
if ($3.node.ptr_anydata->must_size) { | |
tmp = realloc($3.node.ptr_anydata->must, $3.node.ptr_anydata->must_size * sizeof *$3.node.ptr_anydata->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.node.ptr_anydata->must = tmp; | |
} | |
} | |
anyxml_opt_stmt: @EMPTYDIR@ { $$.node.ptr_anydata = actual; | |
$$.node.flag = actual_type; | |
} | |
| anyxml_opt_stmt when_stmt { actual = $1.node.ptr_anydata; | |
actual_type = $1.node.flag; | |
} | |
stmtsep | |
| anyxml_opt_stmt if_feature_stmt stmtsep | |
| anyxml_opt_stmt must_stmt { actual = $1.node.ptr_anydata; | |
actual_type = $1.node.flag; | |
} | |
stmtsep | |
| anyxml_opt_stmt config_stmt { if ($1.node.ptr_anydata->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_anydata, "config", | |
($1.node.flag == ANYXML_KEYWORD) ? "anyxml" : "anydata"); | |
YYABORT; | |
} | |
$1.node.ptr_anydata->flags |= $2; | |
} | |
| anyxml_opt_stmt mandatory_stmt { if ($1.node.ptr_anydata->flags & LYS_MAND_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_anydata, "mandatory", | |
($1.node.flag == ANYXML_KEYWORD) ? "anyxml" : "anydata"); | |
YYABORT; | |
} | |
$1.node.ptr_anydata->flags |= $2; | |
} | |
| anyxml_opt_stmt status_stmt { if ($1.node.ptr_anydata->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_anydata, "status", | |
($1.node.flag == ANYXML_KEYWORD) ? "anyxml" : "anydata"); | |
YYABORT; | |
} | |
$1.node.ptr_anydata->flags |= $2; | |
} | |
| anyxml_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_anydata, s, ($1.node.flag == ANYXML_KEYWORD) ? "anyxml" : "anydata", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| anyxml_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_anydata, s, ($1.node.flag == ANYXML_KEYWORD) ? "anyxml" : "anydata", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
uses_arg_str: identifier_ref_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_USES, sizeof(struct lys_node_uses)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = USES_KEYWORD; | |
} | |
uses_stmt: USES_KEYWORD sep uses_arg_str uses_end | |
{ LOGDBG("YANG: finished parsing uses statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
uses_end: ';' | |
| '{' stmtsep | |
uses_opt_stmt | |
'}' { void *tmp; | |
if ($3.uses->iffeature_size) { | |
tmp = realloc($3.uses->iffeature, $3.uses->iffeature_size * sizeof *$3.uses->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.uses->iffeature = tmp; | |
} | |
if ($3.uses->refine_size) { | |
tmp = realloc($3.uses->refine, $3.uses->refine_size * sizeof *$3.uses->refine); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.uses->refine = tmp; | |
} | |
if ($3.uses->augment_size) { | |
tmp = realloc($3.uses->augment, $3.uses->augment_size * sizeof *$3.uses->augment); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.uses->augment = tmp; | |
} | |
} | |
uses_opt_stmt: @EMPTYDIR@ { $$.uses = actual; } | |
| uses_opt_stmt when_stmt { actual = $1.uses; | |
actual_type = USES_KEYWORD; | |
} | |
stmtsep | |
| uses_opt_stmt if_feature_stmt stmtsep | |
| uses_opt_stmt status_stmt { if ($1.uses->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.uses, "status", "uses"); | |
YYABORT; | |
} | |
$1.uses->flags |= $2; | |
} | |
| uses_opt_stmt description_stmt { if (yang_read_description(trg, $1.uses, s, "uses", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| uses_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.uses, s, "uses", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| uses_opt_stmt refine_stmt { actual = $1.uses; | |
actual_type = USES_KEYWORD; | |
} | |
stmtsep | |
| uses_opt_stmt uses_augment_stmt { actual = $1.uses; | |
actual_type = USES_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
refine_args_str: descendant_schema_nodeid optsep | |
| string_1 | |
refine_arg_str: refine_args_str { YANG_ADDELEM(((struct lys_node_uses *)actual)->refine, | |
((struct lys_node_uses *)actual)->refine_size); | |
((struct lys_refine *)actual)->target_name = transform_schema2json(trg, s); | |
free(s); | |
s = NULL; | |
if (!((struct lys_refine *)actual)->target_name) { | |
YYABORT; | |
} | |
} | |
refine_stmt: REFINE_KEYWORD sep refine_arg_str refine_end | |
refine_end: ';' | |
| '{' stmtsep | |
refine_body_opt_stmts | |
'}' { void *tmp; | |
if ($3.refine->iffeature_size) { | |
tmp = realloc($3.refine->iffeature, $3.refine->iffeature_size * sizeof *$3.refine->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.refine->iffeature = tmp; | |
} | |
if ($3.refine->must_size) { | |
tmp = realloc($3.refine->must, $3.refine->must_size * sizeof *$3.refine->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.refine->must = tmp; | |
} | |
if ($3.refine->dflt_size) { | |
tmp = realloc($3.refine->dflt, $3.refine->dflt_size * sizeof *$3.refine->dflt); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.refine->dflt = tmp; | |
} | |
} | |
refine_body_opt_stmts: @EMPTYDIR@ { $$.refine = actual; | |
actual_type = REFINE_KEYWORD; | |
} | |
| refine_body_opt_stmts must_stmt stmtsep { actual = $1.refine; | |
actual_type = REFINE_KEYWORD; | |
if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYXML)) { | |
$1.refine->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYXML); | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "must", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYXML; | |
} | |
} | |
| refine_body_opt_stmts if_feature_stmt | |
stmtsep { /* leaf, leaf-list, list, container or anyxml */ | |
/* check possibility of statements combination */ | |
if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA)) { | |
$1.refine->target_type &= (LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA); | |
} else { | |
free(s); | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "if-feature", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_CONTAINER | LYS_ANYDATA; | |
} | |
} | |
| refine_body_opt_stmts presence_stmt { if ($1.refine->target_type) { | |
if ($1.refine->target_type & LYS_CONTAINER) { | |
if ($1.refine->mod.presence) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "presence", "refine"); | |
free(s); | |
YYABORT; | |
} | |
$1.refine->target_type = LYS_CONTAINER; | |
$1.refine->mod.presence = lydict_insert_zc(trg->ctx, s); | |
} else { | |
free(s); | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "presence", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_CONTAINER; | |
$1.refine->mod.presence = lydict_insert_zc(trg->ctx, s); | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| refine_body_opt_stmts default_stmt { int i; | |
if ($1.refine->dflt_size) { | |
if (trg->version < 2) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "default", "refine"); | |
YYABORT; | |
} | |
if ($1.refine->target_type & LYS_LEAFLIST) { | |
$1.refine->target_type = LYS_LEAFLIST; | |
} else { | |
free(s); | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "default", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
if ($1.refine->target_type) { | |
if (trg->version < 2 && ($1.refine->target_type & (LYS_LEAF | LYS_CHOICE))) { | |
$1.refine->target_type &= (LYS_LEAF | LYS_CHOICE); | |
} if (trg->version > 1 && ($1.refine->target_type & (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE))) { | |
/* YANG 1.1 */ | |
$1.refine->target_type &= (LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE); | |
} else { | |
free(s); | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "default", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
if (trg->version < 2) { | |
$1.refine->target_type = LYS_LEAF | LYS_CHOICE; | |
} else { | |
/* YANG 1.1 */ | |
$1.refine->target_type = LYS_LEAF | LYS_LEAFLIST | LYS_CHOICE; | |
} | |
} | |
} | |
/* check for duplicity */ | |
for (i = 0; i < $1.refine->dflt_size; ++i) { | |
if (ly_strequal($1.refine->dflt[i], s, 0)) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "default"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Duplicated default value \"%s\".", s); | |
YYABORT; | |
} | |
} | |
YANG_ADDELEM($1.refine->dflt, $1.refine->dflt_size); | |
*((const char **)actual) = lydict_insert_zc(trg->ctx, s); | |
actual = $1.refine; | |
s = NULL; | |
$$ = $1; | |
} | |
| refine_body_opt_stmts config_stmt { if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LEAF | LYS_CHOICE | LYS_LIST | LYS_CONTAINER | LYS_LEAFLIST)) { | |
$1.refine->target_type &= (LYS_LEAF | LYS_CHOICE | LYS_LIST | LYS_CONTAINER | LYS_LEAFLIST); | |
if (yang_check_flags((uint16_t*)&$1.refine->flags, LYS_CONFIG_MASK, "config", "refine", $2, 1)) { | |
YYABORT; | |
} | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "config", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LEAF | LYS_CHOICE | LYS_LIST | LYS_CONTAINER | LYS_LEAFLIST; | |
$1.refine->flags |= $2; | |
} | |
$$ = $1; | |
} | |
| refine_body_opt_stmts mandatory_stmt { if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LEAF | LYS_CHOICE | LYS_ANYXML)) { | |
$1.refine->target_type &= (LYS_LEAF | LYS_CHOICE | LYS_ANYXML); | |
if (yang_check_flags((uint16_t*)&$1.refine->flags, LYS_MAND_MASK, "mandatory", "refine", $2, 1)) { | |
YYABORT; | |
} | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "mandatory", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LEAF | LYS_CHOICE | LYS_ANYXML; | |
$1.refine->flags |= $2; | |
} | |
$$ = $1; | |
} | |
| refine_body_opt_stmts min_elements_stmt { if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LIST | LYS_LEAFLIST)) { | |
$1.refine->target_type &= (LYS_LIST | LYS_LEAFLIST); | |
if ($1.refine->flags & LYS_RFN_MINSET) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "min-elements", "refine"); | |
YYABORT; | |
} | |
$1.refine->flags |= LYS_RFN_MINSET; | |
$1.refine->mod.list.min = $2; | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "min-elements", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LIST | LYS_LEAFLIST; | |
$1.refine->flags |= LYS_RFN_MINSET; | |
$1.refine->mod.list.min = $2; | |
} | |
$$ = $1; | |
} | |
| refine_body_opt_stmts max_elements_stmt { if ($1.refine->target_type) { | |
if ($1.refine->target_type & (LYS_LIST | LYS_LEAFLIST)) { | |
$1.refine->target_type &= (LYS_LIST | LYS_LEAFLIST); | |
if ($1.refine->flags & LYS_RFN_MAXSET) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "max-elements", "refine"); | |
YYABORT; | |
} | |
$1.refine->flags |= LYS_RFN_MAXSET; | |
$1.refine->mod.list.max = $2; | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "max-elements", "refine"); | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid refine target nodetype for the substatements."); | |
YYABORT; | |
} | |
} else { | |
$1.refine->target_type = LYS_LIST | LYS_LEAFLIST; | |
$1.refine->flags |= LYS_RFN_MAXSET; | |
$1.refine->mod.list.max = $2; | |
} | |
$$ = $1; | |
} | |
| refine_body_opt_stmts description_stmt { if (yang_read_description(trg, $1.refine, s, "refine", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| refine_body_opt_stmts reference_stmt { if (yang_read_reference(trg, $1.refine, s, "refine", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
uses_augment_arg_str: descendant_schema_nodeid optsep | |
| string_1 | |
; | |
uses_augment_arg: uses_augment_arg_str { void *parent; | |
$$.token = actual_type; | |
$$.actual = actual; | |
parent = actual; | |
YANG_ADDELEM(((struct lys_node_uses *)actual)->augment, | |
((struct lys_node_uses *)actual)->augment_size); | |
if (yang_read_augment(trg, parent, actual, s)) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = AUGMENT_KEYWORD; | |
} | |
uses_augment_stmt: AUGMENT_KEYWORD sep uses_augment_arg | |
'{' stmtsep | |
augment_opt_stmt | |
'}' { LOGDBG("YANG: finished parsing augment statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
augment_arg_str: absolute_schema_nodeids optsep | |
| string_1 | |
augment_arg: augment_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
YANG_ADDELEM(trg->augment, trg->augment_size); | |
if (yang_read_augment(trg, NULL, actual, s)) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = AUGMENT_KEYWORD; | |
} | |
augment_stmt: AUGMENT_KEYWORD sep augment_arg | |
'{' stmtsep | |
augment_opt_stmt | |
'}' { LOGDBG("YANG: finished parsing augment statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
augment_opt_stmt: @EMPTYDIR@ { $$.augment = actual; } | |
| augment_opt_stmt when_stmt { actual = $1.augment; | |
actual_type = AUGMENT_KEYWORD; | |
} | |
stmtsep | |
| augment_opt_stmt if_feature_stmt stmtsep | |
| augment_opt_stmt status_stmt { if ($1.augment->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.augment, "status", "augment"); | |
YYABORT; | |
} | |
$1.augment->flags |= $2; | |
} | |
| augment_opt_stmt description_stmt { if (yang_read_description(trg, $1.augment, s, "augment", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| augment_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.augment, s, "augment", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| augment_opt_stmt data_def_stmt { actual = $1.augment; | |
actual_type = AUGMENT_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| augment_opt_stmt action_stmt { actual = $1.augment; | |
actual_type = AUGMENT_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| augment_opt_stmt notification_stmt { actual = $1.augment; | |
actual_type = AUGMENT_KEYWORD; | |
data_node = actual; | |
if (trg->version < 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, $1.augment, "notification"); | |
YYABORT; | |
} | |
} | |
stmtsep | |
| augment_opt_stmt case_stmt { actual = $1.augment; | |
actual_type = AUGMENT_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
action_arg_str: identifier_arg_str { if (param->module->version != 2) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, actual, "action"); | |
free(s); | |
YYABORT; | |
} | |
$$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_ACTION, sizeof(struct lys_node_rpc_action)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = ACTION_KEYWORD; | |
} | |
action_stmt: ACTION_KEYWORD sep action_arg_str rpc_end | |
{ LOGDBG("YANG: finished parsing action statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
rpc_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, NULL, param->node, s, LYS_RPC, sizeof(struct lys_node_rpc_action)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = RPC_KEYWORD; | |
} | |
rpc_stmt: RPC_KEYWORD sep rpc_arg_str rpc_end | |
{ LOGDBG("YANG: finished parsing rpc statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
rpc_end: ';' | |
| '{' stmtsep | |
rpc_opt_stmt | |
'}' { void *tmp; | |
if ($3.node.ptr_rpc->iffeature_size) { | |
tmp = realloc($3.node.ptr_rpc->iffeature, $3.node.ptr_rpc->iffeature_size * sizeof *$3.node.ptr_rpc->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.node.ptr_rpc->iffeature = tmp; | |
} | |
if ($3.node.ptr_rpc->tpdf_size) { | |
tmp = realloc($3.node.ptr_rpc->tpdf, $3.node.ptr_rpc->tpdf_size * sizeof *$3.node.ptr_rpc->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.node.ptr_rpc->tpdf = tmp; | |
} | |
} | |
rpc_opt_stmt: @EMPTYDIR@ { $$.node.ptr_rpc = actual; | |
$$.node.flag = 0; | |
} | |
| rpc_opt_stmt if_feature_stmt stmtsep | |
| rpc_opt_stmt status_stmt { if ($1.node.ptr_rpc->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_rpc, "status", "rpc"); | |
YYABORT; | |
} | |
$1.node.ptr_rpc->flags |= $2; | |
} | |
| rpc_opt_stmt description_stmt { if (yang_read_description(trg, $1.node.ptr_rpc, s, "rpc", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| rpc_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.node.ptr_rpc, s, "rpc", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| rpc_opt_stmt typedef_stmt { actual = $1.node.ptr_rpc; | |
actual_type = RPC_KEYWORD; | |
} | |
stmtsep | |
| rpc_opt_stmt grouping_stmt { actual = $1.node.ptr_rpc; | |
actual_type = RPC_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| rpc_opt_stmt input_stmt { if ($1.node.flag & LYS_RPC_INPUT) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_rpc, "input", "rpc"); | |
YYABORT; | |
} | |
$1.node.flag |= LYS_RPC_INPUT; | |
actual = $1.node.ptr_rpc; | |
actual_type = RPC_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep { $$ = $1; } | |
| rpc_opt_stmt output_stmt { if ($1.node.flag & LYS_RPC_OUTPUT) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.node.ptr_rpc, "output", "rpc"); | |
YYABORT; | |
} | |
$1.node.flag |= LYS_RPC_OUTPUT; | |
actual = $1.node.ptr_rpc; | |
actual_type = RPC_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep { $$ = $1; } | |
input_arg: INPUT_KEYWORD optsep { $$.token = actual_type; | |
$$.actual = actual; | |
s = strdup("input"); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_INPUT, sizeof(struct lys_node_inout)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = INPUT_KEYWORD; | |
} | |
input_stmt: input_arg | |
'{' stmtsep | |
input_output_opt_stmt | |
'}' { void *tmp; | |
if ($4.inout->must_size) { | |
tmp = realloc($4.inout->must, $4.inout->must_size * sizeof *$4.inout->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$4.inout->must = tmp; | |
} | |
if ($4.inout->tpdf_size) { | |
tmp = realloc($4.inout->tpdf, $4.inout->tpdf_size * sizeof *$4.inout->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$4.inout->tpdf = tmp; | |
} | |
LOGDBG("YANG: finished parsing input statement \"%s\"", data_node->name); | |
actual_type = $1.token; | |
actual = $1.actual; | |
data_node = $1.actual; | |
} | |
input_output_opt_stmt: @EMPTYDIR@ { $$.inout = actual; | |
actual_type = INPUT_KEYWORD; | |
} | |
| input_output_opt_stmt must_stmt { actual = $1.inout; | |
actual_type = INPUT_KEYWORD; | |
} | |
stmtsep | |
| input_output_opt_stmt typedef_stmt { actual = $1.inout; | |
actual_type = INPUT_KEYWORD; | |
} | |
stmtsep | |
| input_output_opt_stmt grouping_stmt { actual = $1.inout; | |
actual_type = INPUT_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| input_output_opt_stmt data_def_stmt { actual = $1.inout; | |
actual_type = INPUT_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
output_arg: OUTPUT_KEYWORD optsep { $$.token = actual_type; | |
$$.actual = actual; | |
s = strdup("output"); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_OUTPUT, sizeof(struct lys_node_inout)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
s = NULL; | |
actual_type = OUTPUT_KEYWORD; | |
} | |
output_stmt: output_arg | |
'{' stmtsep | |
input_output_opt_stmt | |
'}' { void *tmp; | |
if ($4.inout->must_size) { | |
tmp = realloc($4.inout->must, $4.inout->must_size * sizeof *$4.inout->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$4.inout->must = tmp; | |
} | |
if ($4.inout->tpdf_size) { | |
tmp = realloc($4.inout->tpdf, $4.inout->tpdf_size * sizeof *$4.inout->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$4.inout->tpdf = tmp; | |
} | |
LOGDBG("YANG: finished parsing output statement \"%s\"", data_node->name); | |
actual_type = $1.token; | |
actual = $1.actual; | |
data_node = $1.actual; | |
} | |
notification_arg_str: identifier_arg_str { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_node(trg, actual, param->node, s, LYS_NOTIF, sizeof(struct lys_node_notif)))) { | |
YYABORT; | |
} | |
data_node = actual; | |
actual_type = NOTIFICATION_KEYWORD; | |
} | |
notification_stmt: NOTIFICATION_KEYWORD sep notification_arg_str notification_end | |
{ LOGDBG("YANG: finished parsing notification statement \"%s\"", data_node->name); | |
actual_type = $3.token; | |
actual = $3.actual; | |
data_node = $3.actual; | |
} | |
notification_end: ';' | |
| '{' stmtsep | |
notification_opt_stmt | |
'}' { void *tmp; | |
if ($3.notif->must_size) { | |
tmp = realloc($3.notif->must, $3.notif->must_size * sizeof *$3.notif->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.notif->must = tmp; | |
} | |
if ($3.notif->iffeature_size) { | |
tmp = realloc($3.notif->iffeature, $3.notif->iffeature_size * sizeof *$3.notif->iffeature); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.notif->iffeature = tmp; | |
} | |
if ($3.notif->tpdf_size) { | |
tmp = realloc($3.notif->tpdf, $3.notif->tpdf_size * sizeof *$3.notif->tpdf); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3.notif->tpdf = tmp; | |
} | |
} | |
notification_opt_stmt: @EMPTYDIR@ { $$.notif = actual; | |
actual_type = NOTIFICATION_KEYWORD; | |
} | |
| notification_opt_stmt must_stmt { actual = $1.notif; | |
actual_type = NOTIFICATION_KEYWORD; | |
} | |
stmtsep | |
| notification_opt_stmt if_feature_stmt stmtsep | |
| notification_opt_stmt status_stmt { if ($1.notif->flags & LYS_STATUS_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_LYS, $1.notif, "status", "notification"); | |
YYABORT; | |
} | |
$1.notif->flags |= $2; | |
} | |
| notification_opt_stmt description_stmt { if (yang_read_description(trg, $1.notif, s, "notification", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| notification_opt_stmt reference_stmt { if (yang_read_reference(trg, $1.notif, s, "notification", NODE_PRINT)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| notification_opt_stmt typedef_stmt { actual = $1.notif; | |
actual_type = NOTIFICATION_KEYWORD; | |
} | |
stmtsep | |
| notification_opt_stmt grouping_stmt { actual = $1.notif; | |
actual_type = NOTIFICATION_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
| notification_opt_stmt data_def_stmt { actual = $1.notif; | |
actual_type = NOTIFICATION_KEYWORD; | |
data_node = actual; | |
} | |
stmtsep | |
deviation_arg: deviation_arg_str { YANG_ADDELEM(trg->deviation, trg->deviation_size); | |
((struct lys_deviation *)actual)->target_name = transform_schema2json(trg, s); | |
free(s); | |
if (!((struct lys_deviation *)actual)->target_name) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
deviation_stmt: DEVIATION_KEYWORD sep deviation_arg | |
'{' stmtsep | |
deviation_opt_stmt | |
'}' { void *tmp; | |
if ($6->deviate_size) { | |
tmp = realloc($6->deviate, $6->deviate_size * sizeof *$6->deviate); | |
if (!tmp) { | |
LOGINT; | |
YYABORT; | |
} | |
$6->deviate = tmp; | |
} else { | |
LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_NONE, NULL, "deviate", "deviation"); | |
YYABORT; | |
} | |
} | |
deviation_opt_stmt: @EMPTYDIR@ { $$ = actual; | |
actual_type = DEVIATION_KEYWORD; | |
} | |
| deviation_opt_stmt description_stmt { if (yang_read_description(trg, $1, s, "deviation", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| deviation_opt_stmt reference_stmt { if (yang_read_reference(trg, $1, s, "deviation", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| deviation_opt_stmt DEVIATE_KEYWORD sep deviate_body_stmt { actual = $1; | |
actual_type = DEVIATION_KEYWORD; | |
$$ = $1; | |
} | |
deviation_arg_str: absolute_schema_nodeids optsep | |
| string_1 | |
deviate_body_stmt: deviate_not_supported_stmt | |
{ if (yang_read_deviate_unsupported(actual)) { | |
YYABORT; | |
} | |
} | |
| deviate_stmts optsep | |
deviate_not_supported: NOT_SUPPORTED_KEYWORD { backup_type = actual_type; | |
actual_type = NOT_SUPPORTED_KEYWORD; | |
} | |
deviate_not_supported_stmt: deviate_not_supported optsep stmtend | |
deviate_stmts: deviate_add_stmt | |
| deviate_replace_stmt | |
| deviate_delete_stmt | |
deviate_add_stmt: ADD_KEYWORD optsep { if (!(actual = yang_read_deviate(actual, LY_DEVIATE_ADD))) { | |
YYABORT; | |
} | |
} | |
deviate_add_end | |
deviate_add_end: ';' | |
| '{' stmtsep | |
deviate_add_opt_stmt | |
'}' { void *tmp; | |
if ($3->must_size) { | |
tmp = realloc($3->must, $3->must_size * sizeof *$3->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->must = tmp; | |
} | |
if ($3->unique_size) { | |
tmp = realloc($3->unique, $3->unique_size * sizeof *$3->unique); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->unique = tmp; | |
} | |
if ($3->dflt_size) { | |
tmp = realloc($3->dflt, $3->dflt_size * sizeof *$3->dflt); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->dflt = tmp; | |
} | |
} | |
deviate_add_opt_stmt: @EMPTYDIR@ { $$ = actual; | |
actual_type = ADD_KEYWORD; | |
} | |
| deviate_add_opt_stmt units_stmt { if (yang_read_units(trg, actual, s, ADD_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt must_stmt stmtsep { actual = $1; | |
actual_type = ADD_KEYWORD; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt unique_stmt { YANG_ADDELEM($1->unique, $1->unique_size); | |
((struct lys_unique *)actual)->expr = (const char **)s; | |
s = NULL; | |
actual = $1; | |
$$= $1; | |
} | |
| deviate_add_opt_stmt default_stmt { YANG_ADDELEM($1->dflt, $1->dflt_size); | |
*((const char **)actual) = lydict_insert_zc(trg->ctx, s); | |
s = NULL; | |
actual = $1; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt config_stmt { if ($1->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "config", "deviate"); | |
YYABORT; | |
} | |
$1->flags = $2; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt mandatory_stmt { if ($1->flags & LYS_MAND_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "mandatory", "deviate"); | |
YYABORT; | |
} | |
$1->flags = $2; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt min_elements_stmt { if ($1->min_set) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "min-elements", "deviation"); | |
YYABORT; | |
} | |
$1->min = $2; | |
$1->min_set = 1; | |
$$ = $1; | |
} | |
| deviate_add_opt_stmt max_elements_stmt { if ($1->max_set) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "max-elements", "deviation"); | |
YYABORT; | |
} | |
$1->max = $2; | |
$1->max_set = 1; | |
$$ = $1; | |
} | |
deviate_delete_stmt: DELETE_KEYWORD optsep { if (!(actual = yang_read_deviate(actual, LY_DEVIATE_DEL))) { | |
YYABORT; | |
} | |
} | |
deviate_delete_end | |
deviate_delete_end: ';' | |
| '{' stmtsep | |
deviate_delete_opt_stmt | |
'}' { void *tmp; | |
if ($3->must_size) { | |
tmp = realloc($3->must, $3->must_size * sizeof *$3->must); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->must = tmp; | |
} | |
if ($3->unique_size) { | |
tmp = realloc($3->unique, $3->unique_size * sizeof *$3->unique); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->unique = tmp; | |
} | |
if ($3->dflt_size) { | |
tmp = realloc($3->dflt, $3->dflt_size * sizeof *$3->dflt); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->dflt = tmp; | |
} | |
} | |
deviate_delete_opt_stmt: @EMPTYDIR@ { $$ = actual; | |
actual_type = DELETE_KEYWORD; | |
} | |
| deviate_delete_opt_stmt units_stmt { if (yang_read_units(trg, actual, s, DELETE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| deviate_delete_opt_stmt must_stmt stmtsep { actual = $1; | |
actual_type = DELETE_KEYWORD; | |
$$ = $1; | |
} | |
| deviate_delete_opt_stmt unique_stmt { YANG_ADDELEM($1->unique, $1->unique_size); | |
((struct lys_unique *)actual)->expr = (const char **)s; | |
s = NULL; | |
actual = $1; | |
$$ = $1; | |
} | |
| deviate_delete_opt_stmt default_stmt { YANG_ADDELEM($1->dflt, $1->dflt_size); | |
*((const char **)actual) = lydict_insert_zc(trg->ctx, s); | |
s = NULL; | |
actual = $1; | |
$$ = $1; | |
} | |
deviate_replace_stmt: REPLACE_KEYWORD optsep { if (!(actual = yang_read_deviate(actual, LY_DEVIATE_RPL))) { | |
YYABORT; | |
} | |
} | |
deviate_replace_end | |
deviate_replace_end: ';' | |
| '{' stmtsep | |
deviate_replace_opt_stmt | |
'}' { void *tmp; | |
if ($3->dflt_size) { | |
tmp = realloc($3->dflt, $3->dflt_size * sizeof *$3->dflt); | |
if (!tmp) { | |
LOGMEM; | |
YYABORT; | |
} | |
$3->dflt = tmp; | |
} | |
} | |
deviate_replace_opt_stmt: @EMPTYDIR@ { $$ = actual; | |
actual_type = REPLACE_KEYWORD; | |
} | |
| deviate_replace_opt_stmt type_stmt stmtsep { actual = $1; | |
actual_type = REPLACE_KEYWORD; | |
} | |
| deviate_replace_opt_stmt units_stmt { if (yang_read_units(trg, actual, s, DELETE_KEYWORD)) { | |
YYABORT; | |
} | |
s = NULL; | |
$$ = $1; | |
} | |
| deviate_replace_opt_stmt default_stmt { YANG_ADDELEM($1->dflt, $1->dflt_size); | |
*((const char **)actual) = lydict_insert_zc(trg->ctx, s); | |
s = NULL; | |
actual = $1; | |
$$ = $1; | |
} | |
| deviate_replace_opt_stmt config_stmt { if ($1->flags & LYS_CONFIG_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "config", "deviate"); | |
YYABORT; | |
} | |
$1->flags = $2; | |
$$ = $1; | |
} | |
| deviate_replace_opt_stmt mandatory_stmt { if ($1->flags & LYS_MAND_MASK) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "mandatory", "deviate"); | |
YYABORT; | |
} | |
$1->flags = $2; | |
$$ = $1; | |
} | |
| deviate_replace_opt_stmt min_elements_stmt { if ($1->min_set) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "min-elements", "deviation"); | |
YYABORT; | |
} | |
$1->min = $2; | |
$1->min_set = 1; | |
$$ = $1; | |
} | |
| deviate_replace_opt_stmt max_elements_stmt { if ($1->max_set) { | |
LOGVAL(LYE_TOOMANY, LY_VLOG_NONE, NULL, "max-elements", "deviation"); | |
YYABORT; | |
} | |
$1->max = $2; | |
$1->max_set = 1; | |
$$ = $1; | |
} | |
when_arg_str: string { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_when(trg, actual, actual_type, s))) { | |
YYABORT; | |
} | |
s = NULL; | |
actual_type = WHEN_KEYWORD; | |
} | |
when_stmt: WHEN_KEYWORD sep when_arg_str when_end | |
{ actual_type = $3.token; | |
actual = $3.actual; | |
} | |
when_end: ';' | |
| '{' stmtsep | |
when_opt_stmt | |
'}' | |
when_opt_stmt: @EMPTYDIR@ | |
| when_opt_stmt description_stmt { if (yang_read_description(trg, actual, s, "when", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
| when_opt_stmt reference_stmt { if (yang_read_reference(trg, actual, s, "when", NODE)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
config_arg: config_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = CONFIG_KEYWORD; | |
} | |
config_stmt: CONFIG_KEYWORD sep config_arg stmtend { $$ = $3; } | |
config_arg_str: TRUE_KEYWORD optsep { $$ = LYS_CONFIG_W | LYS_CONFIG_SET; } | |
| FALSE_KEYWORD optsep { $$ = LYS_CONFIG_R | LYS_CONFIG_SET; } | |
| string_1 { if (!strcmp(s, "true")) { | |
$$ = LYS_CONFIG_W | LYS_CONFIG_SET; | |
} else if (!strcmp(s, "false")) { | |
$$ = LYS_CONFIG_R | LYS_CONFIG_SET; | |
} else { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "config"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
} | |
mandatory_arg: mandatory_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = MANDATORY_KEYWORD; | |
} | |
mandatory_stmt: MANDATORY_KEYWORD sep mandatory_arg stmtend { $$ = $3; } | |
mandatory_arg_str: TRUE_KEYWORD optsep { $$ = LYS_MAND_TRUE; } | |
| FALSE_KEYWORD optsep { $$ = LYS_MAND_FALSE; } | |
| string_1 { if (!strcmp(s, "true")) { | |
$$ = LYS_MAND_TRUE; | |
} else if (!strcmp(s, "false")) { | |
$$ = LYS_MAND_FALSE; | |
} else { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "mandatory"); | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s = NULL; | |
} | |
presence_arg: string { backup_type = actual_type; | |
actual_type = PRESENCE_KEYWORD; | |
} | |
presence_stmt: PRESENCE_KEYWORD sep presence_arg stmtend | |
min_value_arg: min_value_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = MIN_ELEMENTS_KEYWORD; | |
} | |
min_elements_stmt: MIN_ELEMENTS_KEYWORD sep min_value_arg stmtend { $$ = $3; } | |
min_value_arg_str: non_negative_integer_value optsep { $$ = $1; } | |
| string_1 { if (strlen(s) == 1 && s[0] == '0') { | |
$$ = 0; | |
} else { | |
/* convert it to uint32_t */ | |
uint64_t val; | |
char *endptr = NULL; | |
errno = 0; | |
val = strtoul(s, &endptr, 10); | |
if (*endptr || s[0] == '-' || errno || val > UINT32_MAX) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "min-elements"); | |
free(s); | |
YYABORT; | |
} | |
$$ = (uint32_t) val; | |
} | |
free(s); | |
s = NULL; | |
} | |
max_value_arg: max_value_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = MAX_ELEMENTS_KEYWORD; | |
} | |
max_elements_stmt: MAX_ELEMENTS_KEYWORD sep max_value_arg stmtend { $$ = $3; } | |
max_value_arg_str: UNBOUNDED_KEYWORD optsep { $$ = 0; } | |
| positive_integer_value optsep { $$ = $1; } | |
| string_1 { if (!strcmp(s, "unbounded")) { | |
$$ = 0; | |
} else { | |
/* convert it to uint32_t */ | |
uint64_t val; | |
char *endptr = NULL; | |
errno = 0; | |
val = strtoul(s, &endptr, 10); | |
if (*endptr || s[0] == '-' || errno || val == 0 || val > UINT32_MAX) { | |
LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, s, "max-elements"); | |
free(s); | |
YYABORT; | |
} | |
$$ = (uint32_t) val; | |
} | |
free(s); | |
s = NULL; | |
} | |
ordered_by_arg: ordered_by_arg_str { $$ = $1; | |
backup_type = actual_type; | |
actual_type = ORDERED_BY_KEYWORD; | |
} | |
ordered_by_stmt: ORDERED_BY_KEYWORD sep ordered_by_arg stmtend { $$ = $3; } | |
ordered_by_arg_str: USER_KEYWORD optsep { $$ = LYS_USERORDERED; } | |
| SYSTEM_KEYWORD optsep { $$ = LYS_SYSTEMORDERED; } | |
| string_1 { if (!strcmp(s, "user")) { | |
$$ = LYS_USERORDERED; | |
} else if (!strcmp(s, "system")) { | |
$$ = LYS_SYSTEMORDERED; | |
} else { | |
free(s); | |
YYABORT; | |
} | |
free(s); | |
s=NULL; | |
} | |
must_agr_str: string { $$.token = actual_type; | |
$$.actual = actual; | |
switch (actual_type) { | |
case CONTAINER_KEYWORD: | |
YANG_ADDELEM(((struct lys_node_container *)actual)->must, | |
((struct lys_node_container *)actual)->must_size); | |
break; | |
case ANYDATA_KEYWORD: | |
case ANYXML_KEYWORD: | |
YANG_ADDELEM(((struct lys_node_anydata *)actual)->must, | |
((struct lys_node_anydata *)actual)->must_size); | |
break; | |
case LEAF_KEYWORD: | |
YANG_ADDELEM(((struct lys_node_leaf *)actual)->must, | |
((struct lys_node_leaf *)actual)->must_size); | |
break; | |
case LEAF_LIST_KEYWORD: | |
YANG_ADDELEM(((struct lys_node_leaflist *)actual)->must, | |
((struct lys_node_leaflist *)actual)->must_size); | |
break; | |
case LIST_KEYWORD: | |
YANG_ADDELEM(((struct lys_node_list *)actual)->must, | |
((struct lys_node_list *)actual)->must_size); | |
break; | |
case REFINE_KEYWORD: | |
YANG_ADDELEM(((struct lys_refine *)actual)->must, | |
((struct lys_refine *)actual)->must_size); | |
break; | |
case ADD_KEYWORD: | |
case DELETE_KEYWORD: | |
YANG_ADDELEM(((struct lys_deviate *)actual)->must, | |
((struct lys_deviate *)actual)->must_size); | |
break; | |
case NOTIFICATION_KEYWORD: | |
if (trg->version < 2) { | |
free(s); | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, actual, "must"); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_node_notif *)actual)->must, | |
((struct lys_node_notif *)actual)->must_size); | |
break; | |
case INPUT_KEYWORD: | |
if (trg->version < 2) { | |
free(s); | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, actual, "must"); | |
YYABORT; | |
} | |
YANG_ADDELEM(((struct lys_node_inout *)actual)->must, | |
((struct lys_node_inout *)actual)->must_size); | |
break; | |
default: | |
free(s); | |
LOGINT; | |
YYABORT; | |
} | |
((struct lys_restr *)actual)->expr = transform_schema2json(trg, s); | |
free(s); | |
if (!((struct lys_restr *)actual)->expr) { | |
YYABORT; | |
} | |
s = NULL; | |
actual_type = MUST_KEYWORD; | |
} | |
must_stmt: MUST_KEYWORD sep must_agr_str must_end | |
{ actual_type = $3.token; | |
actual = $3.actual; | |
} | |
must_end: ';' | |
| '{' stmtsep | |
message_opt_stmt | |
'}' | |
unique_arg: unique_arg_str { backup_type = actual_type; | |
actual_type = UNIQUE_KEYWORD; | |
} | |
unique_stmt: UNIQUE_KEYWORD sep unique_arg stmtend | |
unique_arg_str: descendant_schema_nodeid unique_arg_opt | |
| string_1 | |
unique_arg_opt: @EMPTYDIR@ | |
| unique_arg_opt sep descendant_schema_nodeid | |
key_arg: key_arg_str { backup_type = actual_type; | |
actual_type = KEY_KEYWORD; | |
} | |
key_stmt: KEY_KEYWORD sep key_arg stmtend; | |
key_arg_str: node_identifier { s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
optsep | |
| string_1 | |
; | |
range_arg_str: string { $$.token = actual_type; | |
$$.actual = actual; | |
if (!(actual = yang_read_range(trg, actual, s))) { | |
YYABORT; | |
} | |
actual_type = RANGE_KEYWORD; | |
s = NULL; | |
} | |
absolute_schema_nodeid: '/' node_identifier { if (s) { | |
s = ly_realloc(s,strlen(s) + yyget_leng(scanner) + 2); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
strcat(s,"/"); | |
strcat(s, yyget_text(scanner)); | |
} else { | |
s = malloc(yyget_leng(scanner) + 2); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
s[0]='/'; | |
memcpy(s + 1, yyget_text(scanner), yyget_leng(scanner) + 1); | |
} | |
} | |
absolute_schema_nodeids: absolute_schema_nodeid absolute_schema_nodeid_opt; | |
absolute_schema_nodeid_opt: @EMPTYDIR@ | |
| absolute_schema_nodeid_opt absolute_schema_nodeid | |
; | |
descendant_schema_nodeid: node_identifier { if (s) { | |
s = ly_realloc(s,strlen(s) + yyget_leng(scanner) + 1); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
strcat(s, yyget_text(scanner)); | |
} else { | |
s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
} | |
absolute_schema_nodeid_opt; | |
path_arg_str: { tmp_s = yyget_text(scanner); } absolute_paths { s = strdup(tmp_s); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
s[strlen(s) - 1] = '\0'; | |
} | |
| { tmp_s = yyget_text(scanner); } relative_path { s = strdup(tmp_s); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
s[strlen(s) - 1] = '\0'; | |
} | |
| string_1 | |
; | |
absolute_path: '/' node_identifier path_predicate | |
absolute_paths: absolute_path absolute_path_opt | |
absolute_path_opt: @EMPTYDIR@ | |
| absolute_path_opt absolute_path; | |
relative_path: relative_path_part1 relative_path_part1_opt descendant_path | |
relative_path_part1: DOUBLEDOT '/'; | |
relative_path_part1_opt: @EMPTYDIR@ | |
| relative_path_part1_opt relative_path_part1; | |
descendant_path: node_identifier descendant_path_opt | |
descendant_path_opt: @EMPTYDIR@ | |
| path_predicate absolute_paths; | |
path_predicate: @EMPTYDIR@ | |
| path_predicate '[' whitespace_opt path_equality_expr whitespace_opt ']' | |
path_equality_expr: node_identifier whitespace_opt '=' whitespace_opt path_key_expr | |
path_key_expr: current_function_invocation whitespace_opt '/' whitespace_opt | |
rel_path_keyexpr | |
rel_path_keyexpr: rel_path_keyexpr_part1 rel_path_keyexpr_part1_opt | |
node_identifier rel_path_keyexpr_part2 | |
node_identifier | |
rel_path_keyexpr_part1: DOUBLEDOT whitespace_opt '/' whitespace_opt; | |
rel_path_keyexpr_part1_opt: @EMPTYDIR@ | |
| rel_path_keyexpr_part1_opt rel_path_keyexpr_part1; | |
rel_path_keyexpr_part2: @EMPTYDIR@ | |
| rel_path_keyexpr_part2 whitespace_opt '/' whitespace_opt node_identifier; | |
current_function_invocation: CURRENT_KEYWORD whitespace_opt '(' whitespace_opt ')' | |
positive_integer_value: NON_NEGATIVE_INTEGER { /* convert it to uint32_t */ | |
unsigned long val; | |
val = strtoul(yyget_text(scanner), NULL, 10); | |
if (val > UINT32_MAX) { | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Converted number is very long."); | |
YYABORT; | |
} | |
$$ = (uint32_t) val; | |
} | |
non_negative_integer_value: ZERO { $$ = 0; } | |
| positive_integer_value { $$ = $1; } | |
; | |
integer_value: ZERO { $$ = 0; } | |
| integer_value_convert { /* convert it to int32_t */ | |
int64_t val; | |
val = strtoll(yyget_text(scanner), NULL, 10); | |
if (val < INT32_MIN || val > INT32_MAX) { | |
LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The number is not in the correct range (INT32_MIN..INT32_MAX): \"%d\"",val); | |
YYABORT; | |
} | |
$$ = (int32_t) val; | |
} | |
integer_value_convert: INTEGER | |
| NON_NEGATIVE_INTEGER | |
prefix_arg_str: string_1 | |
| identifiers optsep; | |
identifier_arg_str: identifiers optsep | |
| string_1 { if (lyp_check_identifier(s, LY_IDENT_SIMPLE, trg, NULL)) { | |
free(s); | |
YYABORT; | |
} | |
} | |
node_identifier: identifier | |
| IDENTIFIERPREFIX | |
; | |
identifier_ref_arg_str: identifiers optsep | |
| identifiers_ref optsep | |
| string_1 { char *tmp; | |
if ((tmp = strchr(s, ':'))) { | |
*tmp = '\0'; | |
/* check prefix */ | |
if (lyp_check_identifier(s, LY_IDENT_SIMPLE, trg, NULL)) { | |
free(s); | |
YYABORT; | |
} | |
/* check identifier */ | |
if (lyp_check_identifier(tmp + 1, LY_IDENT_SIMPLE, trg, NULL)) { | |
free(s); | |
YYABORT; | |
} | |
*tmp = ':'; | |
} else { | |
/* check identifier */ | |
if (lyp_check_identifier(s, LY_IDENT_SIMPLE, trg, NULL)) { | |
free(s); | |
YYABORT; | |
} | |
} | |
} | |
stmtend: semicolom stmtsep { s = $1; } | |
| curly_bracket_open stmtsep curly_bracket_close stmtsep { s = $1; } | |
semicolom: ';' { actual_type = backup_type; | |
backup_type = NODE; | |
$$ = s; | |
s = NULL; | |
} | |
curly_bracket_close: '}' { actual_type = backup_type; | |
backup_type = NODE; | |
} | |
curly_bracket_open: '{' { $$ = s; | |
s = NULL; | |
} | |
stmtsep: @EMPTYDIR@ | |
| stmtsep sep_stmt | |
| stmtsep unknown_statement | |
; | |
unknown_statement: identifiers_ref string_opt unknown_statement_end | |
string_opt: string_opt_part1 string_opt_part2 { if (!yang_read_ext(trg, actual, $1, s, actual_type, backup_type)) { | |
YYABORT; | |
} | |
s = NULL; | |
} | |
string_opt_part1: optsep { $$ = s; s = NULL; } | |
string_opt_part2: @EMPTYDIR@ | |
| string | |
unknown_statement_end: ';' | |
| '{' optsep unknown_statement2_opt '}' | |
unknown_statement2_opt: @EMPTYDIR@ | |
| unknown_statement2_opt node_identifier string_opt unknown_statement2_end; | |
unknown_statement2_end: ';' optsep | |
| '{' optsep unknown_statement2_opt '}' optsep | |
sep_stmt: WHITESPACE | |
| EOL | |
; | |
optsep: @EMPTYDIR@ | |
| optsep sep_stmt | |
; | |
sep: sep_stmt optsep; | |
whitespace_opt: @EMPTYDIR@ | |
| WHITESPACE | |
; | |
string: strings { s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
optsep | |
| string_1 | |
strings: STRINGS | |
| REVISION_DATE | |
| identifier | |
| IDENTIFIERPREFIX | |
| ZERO | |
| INTEGER | |
| NON_NEGATIVE_INTEGER | |
identifier: IDENTIFIER | |
| ANYXML_KEYWORD | |
| ARGUMENT_KEYWORD | |
| AUGMENT_KEYWORD | |
| BASE_KEYWORD | |
| BELONGS_TO_KEYWORD | |
| BIT_KEYWORD | |
| CASE_KEYWORD | |
| CHOICE_KEYWORD | |
| CONFIG_KEYWORD | |
| CONTACT_KEYWORD | |
| CONTAINER_KEYWORD | |
| DEFAULT_KEYWORD | |
| DESCRIPTION_KEYWORD | |
| ENUM_KEYWORD | |
| ERROR_APP_TAG_KEYWORD | |
| ERROR_MESSAGE_KEYWORD | |
| EXTENSION_KEYWORD | |
| DEVIATION_KEYWORD | |
| DEVIATE_KEYWORD | |
| FEATURE_KEYWORD | |
| FRACTION_DIGITS_KEYWORD | |
| GROUPING_KEYWORD | |
| IDENTITY_KEYWORD | |
| IF_FEATURE_KEYWORD | |
| IMPORT_KEYWORD | |
| INCLUDE_KEYWORD | |
| INPUT_KEYWORD | |
| KEY_KEYWORD | |
| LEAF_KEYWORD | |
| LEAF_LIST_KEYWORD | |
| LENGTH_KEYWORD | |
| LIST_KEYWORD | |
| MANDATORY_KEYWORD | |
| MAX_ELEMENTS_KEYWORD | |
| MIN_ELEMENTS_KEYWORD | |
| MODULE_KEYWORD | |
| MUST_KEYWORD | |
| NAMESPACE_KEYWORD | |
| NOTIFICATION_KEYWORD | |
| ORDERED_BY_KEYWORD | |
| ORGANIZATION_KEYWORD | |
| OUTPUT_KEYWORD | |
| PATH_KEYWORD | |
| PATTERN_KEYWORD | |
| POSITION_KEYWORD | |
| PREFIX_KEYWORD | |
| PRESENCE_KEYWORD | |
| RANGE_KEYWORD | |
| REFERENCE_KEYWORD | |
| REFINE_KEYWORD | |
| REQUIRE_INSTANCE_KEYWORD | |
| REVISION_KEYWORD | |
| REVISION_DATE_KEYWORD | |
| RPC_KEYWORD | |
| STATUS_KEYWORD | |
| SUBMODULE_KEYWORD | |
| TYPE_KEYWORD | |
| TYPEDEF_KEYWORD | |
| UNIQUE_KEYWORD | |
| UNITS_KEYWORD | |
| USES_KEYWORD | |
| VALUE_KEYWORD | |
| WHEN_KEYWORD | |
| YANG_VERSION_KEYWORD | |
| YIN_ELEMENT_KEYWORD | |
| ADD_KEYWORD | |
| CURRENT_KEYWORD | |
| DELETE_KEYWORD | |
| DEPRECATED_KEYWORD | |
| FALSE_KEYWORD | |
| NOT_SUPPORTED_KEYWORD | |
| OBSOLETE_KEYWORD | |
| REPLACE_KEYWORD | |
| SYSTEM_KEYWORD | |
| TRUE_KEYWORD | |
| UNBOUNDED_KEYWORD | |
| USER_KEYWORD | |
| ACTION_KEYWORD | |
| MODIFIER_KEYWORD | |
| ANYDATA_KEYWORD | |
; | |
identifiers: identifier { s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
identifiers_ref: IDENTIFIERPREFIX { s = strdup(yyget_text(scanner)); | |
if (!s) { | |
LOGMEM; | |
YYABORT; | |
} | |
} | |
%% | |
void yyerror(YYLTYPE *yylloc, void *scanner, struct yang_parameter *param, ...){ | |
free(*param->value); | |
if (yylloc->first_line != -1) { | |
if (*param->data_node && (*param->data_node) == (*param->actual_node)) { | |
LOGVAL(LYE_INSTMT, LY_VLOG_LYS, *param->data_node, yyget_text(scanner)); | |
} else { | |
LOGVAL(LYE_INSTMT, LY_VLOG_NONE, NULL, yyget_text(scanner)); | |
} | |
} | |
} |