Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 Cisco and/or its affiliates. |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at: |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
| 14 | */ |
| 15 | #include <vlib/parse.h> |
| 16 | |
| 17 | #define PARSE_DEBUG 0 |
| 18 | |
| 19 | u16 word_type_index, number_type_index, eof_type_index, rule_eof_type_index, |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 20 | plus_type_index, minus_type_index, star_type_index, slash_type_index, |
| 21 | lpar_type_index, rpar_type_index; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 22 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 23 | u8 * |
| 24 | format_vlib_parse_value (u8 * s, va_list * args) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 25 | { |
| 26 | vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); |
| 27 | vlib_parse_type_t *type; |
| 28 | vlib_parse_value_t *v; |
| 29 | u16 type_index; |
| 30 | |
| 31 | s = format (s, "%d items:\n", vec_len (pm->parse_value)); |
| 32 | vec_foreach (v, pm->parse_value) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 33 | { |
| 34 | type_index = v->type; |
| 35 | type = pool_elt_at_index (pm->parse_types, type_index); |
| 36 | if (type->format_value) |
| 37 | s = format (s, "[%d]: %U\n", v - pm->parse_value, |
| 38 | type->format_value, v); |
| 39 | else |
| 40 | s = format (s, "[%d]: (nofun)\n", v - pm->parse_value); |
| 41 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 42 | return s; |
| 43 | } |
| 44 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 45 | static u8 * |
| 46 | format_vlib_parse_match (u8 * s, va_list * args) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 47 | { |
| 48 | vlib_parse_match_t m = va_arg (*args, vlib_parse_match_t); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 49 | char *t = 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 50 | switch (m) |
| 51 | { |
| 52 | #define _(a) case VLIB_PARSE_##a: t = #a; break; |
| 53 | foreach_parse_match_type |
| 54 | #undef _ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 55 | default: |
| 56 | t = 0; |
| 57 | break; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 58 | } |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 59 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 60 | if (t) |
| 61 | return format (s, "%s", t); |
| 62 | else |
| 63 | return format (s, "unknown 0x%x", m); |
| 64 | } |
| 65 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 66 | static u8 * |
| 67 | format_vlib_parse_item (u8 * s, va_list * args) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 68 | { |
| 69 | vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); |
| 70 | vlib_parse_item_t *item = va_arg (*args, vlib_parse_item_t *); |
| 71 | vlib_parse_type_t *type = pool_elt_at_index (pm->parse_types, item->type); |
| 72 | |
| 73 | if (item->type == word_type_index) |
| 74 | s = format (s, "%s", item->value.as_pointer); |
| 75 | else |
| 76 | s = format (s, "<%s>", type->name); |
| 77 | return s; |
| 78 | } |
| 79 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 80 | static u8 * |
| 81 | format_vlib_parse_graph (u8 * s, va_list * args) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 82 | { |
| 83 | vlib_parse_main_t *pm = va_arg (*args, vlib_parse_main_t *); |
| 84 | vlib_parse_graph_t *node = va_arg (*args, vlib_parse_graph_t *); |
| 85 | vlib_parse_item_t *item; |
| 86 | vlib_parse_type_t *type; |
| 87 | |
| 88 | /* $$$ hash table */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 89 | /* *INDENT-OFF* */ |
| 90 | pool_foreach (type, pm->parse_types, |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 91 | ({ |
| 92 | if (type->rule_index == node - pm->parse_graph) |
| 93 | s = format (s, "\n<%s>\n", type->name); |
| 94 | })); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 95 | /* *INDENT-ON* */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 96 | |
| 97 | if (pm->root_index == (node - pm->parse_graph)) |
| 98 | s = format (s, "\n<root>\n"); |
| 99 | |
| 100 | item = pool_elt_at_index (pm->parse_items, node->item); |
| 101 | |
| 102 | s = format (s, "[%d] %U ", node - pm->parse_graph, |
| 103 | format_vlib_parse_item, pm, item); |
| 104 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 105 | if (node->peer == (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 106 | s = format (s, "peer nil "); |
| 107 | else |
| 108 | s = format (s, "peer %4u ", node->peer); |
| 109 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 110 | if (node->deeper == (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 111 | s = format (s, "deeper nil "); |
| 112 | else |
| 113 | s = format (s, "deeper %4u ", node->deeper); |
| 114 | |
| 115 | return s; |
| 116 | } |
| 117 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 118 | void |
| 119 | dump_parse_graph (void) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 120 | { |
| 121 | vlib_parse_main_t *pm = &vlib_parse_main; |
| 122 | vlib_parse_graph_t *node; |
| 123 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 124 | /* *INDENT-OFF* */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 125 | pool_foreach (node, pm->parse_graph, ({ |
| 126 | fformat(stdout, "%U\n", format_vlib_parse_graph, pm, node); |
| 127 | })); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 128 | /* *INDENT-ON* */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | always_inline void |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 132 | parse_cleanup_value (vlib_parse_main_t * pm, vlib_parse_value_t * pv) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 133 | { |
| 134 | vlib_parse_type_t *type = pool_elt_at_index (pm->parse_types, pv->type); |
| 135 | if (type->value_cleanup_function) |
| 136 | type->value_cleanup_function (pv); |
| 137 | } |
| 138 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 139 | static void |
| 140 | parse_reset (vlib_parse_main_t * pm, u8 * input) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 141 | { |
| 142 | vlib_lex_token_t *t; |
| 143 | vlib_parse_value_t *pv; |
| 144 | |
| 145 | vlib_lex_reset (pm->lex_main, input); |
| 146 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 147 | vec_foreach (t, pm->tokens) vlib_lex_cleanup_token (t); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 148 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 149 | vec_foreach (pv, pm->parse_value) parse_cleanup_value (pm, pv); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 150 | |
| 151 | _vec_len (pm->parse_value) = 0; |
| 152 | _vec_len (pm->tokens) = 0; |
| 153 | pm->current_token_index = 0; |
| 154 | } |
| 155 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 156 | static void |
| 157 | parse_help (vlib_parse_main_t * pm, u32 index) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 158 | { |
| 159 | vlib_parse_graph_t *node; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 160 | vlib_parse_item_t *item; |
| 161 | vlib_parse_type_t *type; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 162 | vlib_main_t *vm = pm->vlib_main; |
| 163 | u8 *help_input; |
| 164 | int i; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 165 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 166 | help_input = vec_dup (pm->lex_main->input_vector); |
| 167 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 168 | for (i = vec_len (help_input) - 1; i >= 0; i--) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 169 | if (help_input[i] == '?') |
| 170 | { |
| 171 | help_input[i] = 0; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 172 | _vec_len (help_input) = i; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 173 | break; |
| 174 | } |
| 175 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 176 | for (i = vec_len (help_input) - 1; i >= 0; i--) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 177 | { |
| 178 | if (help_input[i] != ' ' && help_input[i] != '\t') |
| 179 | break; |
| 180 | help_input[i] = 0; |
| 181 | break; |
| 182 | } |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 183 | _vec_len (help_input) = i + 1; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 184 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 185 | while (index != (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 186 | { |
| 187 | node = pool_elt_at_index (pm->parse_graph, index); |
| 188 | item = pool_elt_at_index (pm->parse_items, node->item); |
| 189 | type = pool_elt_at_index (pm->parse_types, item->type); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 190 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 191 | if (item->type == eof_type_index && vec_len (pm->match_items) == 0) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 192 | /* do nothing */ ; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 193 | else if (item->type == word_type_index) |
| 194 | vlib_cli_output (vm, "%s %s\n", help_input, item->value.as_pointer); |
| 195 | else |
| 196 | vlib_cli_output (vm, "%s <%s>\n", help_input, type->name); |
| 197 | index = node->peer; |
| 198 | } |
| 199 | vec_free (help_input); |
| 200 | } |
| 201 | |
| 202 | static vlib_parse_match_t |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 203 | parse_eval_internal (vlib_parse_main_t * pm, u32 index) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 204 | { |
| 205 | vlib_parse_graph_t *node; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 206 | vlib_parse_item_t *item; |
| 207 | vlib_parse_type_t *type; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 208 | vlib_parse_value_t value, *pv; |
| 209 | vlib_parse_match_t rv; |
| 210 | u32 *partial_matches = 0; |
| 211 | vlib_lex_token_t *t; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 212 | u32 save_token_index = (u32) ~ 0, save_match_items = 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 213 | int had_value = 0; |
| 214 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 215 | if (pm->current_token_index >= vec_len (pm->tokens)) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 216 | return VLIB_PARSE_MATCH_FAIL; |
| 217 | |
| 218 | /* current token */ |
| 219 | t = vec_elt_at_index (pm->tokens, pm->current_token_index); |
| 220 | |
| 221 | /* Help ? */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 222 | if (PREDICT_FALSE (t->token == VLIB_LEX_qmark)) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 223 | { |
| 224 | parse_help (pm, index); |
| 225 | _vec_len (pm->match_items) = 0; |
| 226 | return VLIB_PARSE_MATCH_DONE; |
| 227 | } |
| 228 | |
| 229 | /* Across all peers at this level of the parse graph */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 230 | while (index != (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 231 | { |
| 232 | node = pool_elt_at_index (pm->parse_graph, index); |
| 233 | item = pool_elt_at_index (pm->parse_items, node->item); |
| 234 | type = pool_elt_at_index (pm->parse_types, item->type); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 235 | |
| 236 | /* |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 237 | * Save the token index. We may have to back up several |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 238 | * trie plies. Type-specific match functions can consume |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 239 | * multiple tokens, and they may not be optimally careful |
| 240 | */ |
| 241 | save_token_index = pm->current_token_index; |
| 242 | save_match_items = vec_len (pm->match_items); |
| 243 | vec_add1 (pm->match_items, node->item); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 244 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 245 | if (PARSE_DEBUG > 1) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 246 | clib_warning ("Try to match token %U against node %d", |
| 247 | format_vlib_lex_token, pm->lex_main, t, index); |
| 248 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 249 | /* Call the type-specific match function */ |
| 250 | rv = type->match_function (pm, type, t, &value); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 251 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 252 | if (PARSE_DEBUG > 1) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 253 | clib_warning ("returned %U", format_vlib_parse_match, rv); |
| 254 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 255 | switch (rv) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 256 | { |
| 257 | case VLIB_PARSE_MATCH_VALUE: |
| 258 | /* |
| 259 | * Matched, and returned a value to append to the |
| 260 | * set of args passed to the action function |
| 261 | */ |
| 262 | value.type = item->type; |
| 263 | vec_add1 (pm->parse_value, value); |
| 264 | had_value = 1; |
| 265 | /* fallthrough */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 266 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 267 | case VLIB_PARSE_MATCH_FULL: |
| 268 | unambiguous_partial_match: |
| 269 | /* Consume the matched token */ |
| 270 | pm->current_token_index++; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 271 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 272 | /* continue matching along this path */ |
| 273 | rv = parse_eval_internal (pm, node->deeper); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 274 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 275 | /* this is not the right path */ |
| 276 | if (rv == VLIB_PARSE_MATCH_FAIL) |
| 277 | { |
| 278 | if (had_value) |
| 279 | { |
| 280 | /* Delete the value */ |
| 281 | value = pm->parse_value[vec_len (pm->parse_value) - 1]; |
| 282 | parse_cleanup_value (pm, &value); |
| 283 | _vec_len (pm->parse_value) -= 1; |
| 284 | } |
| 285 | /* Continue with the next sibling */ |
| 286 | pm->current_token_index = save_token_index; |
| 287 | _vec_len (pm->match_items) = save_match_items; |
| 288 | index = node->peer; |
| 289 | break; |
| 290 | } |
| 291 | return rv; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 292 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 293 | case VLIB_PARSE_MATCH_PARTIAL: |
| 294 | /* Partial (substring) match, remember it but keep going */ |
| 295 | vec_add1 (partial_matches, node - pm->parse_graph); |
| 296 | index = node->peer; |
| 297 | break; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 298 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 299 | case VLIB_PARSE_MATCH_FAIL: |
| 300 | /* Continue with the next sibling */ |
| 301 | index = node->peer; |
| 302 | _vec_len (pm->match_items) = save_match_items; |
| 303 | break; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 304 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 305 | case VLIB_PARSE_MATCH_DONE: |
| 306 | /* Parse complete, invoke the action function */ |
| 307 | if (PARSE_DEBUG > 0) |
| 308 | clib_warning ("parse_value: %U", format_vlib_parse_value, pm); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 309 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 310 | { |
| 311 | vlib_parse_eval_function_t *f = item->value.as_pointer; |
| 312 | if (f) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 313 | rv = f (pm, item, pm->parse_value); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 314 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 315 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 316 | vec_foreach (pv, pm->parse_value) parse_cleanup_value (pm, pv); |
| 317 | _vec_len (pm->parse_value) = 0; |
| 318 | _vec_len (pm->match_items) = 0; |
| 319 | return rv; |
| 320 | |
| 321 | case VLIB_PARSE_MATCH_AMBIGUOUS: |
| 322 | case VLIB_PARSE_MATCH_EVAL_FAIL: |
| 323 | case VLIB_PARSE_MATCH_RULE: |
| 324 | _vec_len (pm->match_items) = save_match_items; |
| 325 | return rv; |
| 326 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 327 | } |
| 328 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 329 | /* |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 330 | * Out of siblings. If we have exactly one partial match |
| 331 | * we win |
| 332 | */ |
| 333 | if (vec_len (partial_matches) == 1) |
| 334 | { |
| 335 | index = partial_matches[0]; |
| 336 | node = pool_elt_at_index (pm->parse_graph, index); |
| 337 | vec_free (partial_matches); |
| 338 | goto unambiguous_partial_match; |
| 339 | } |
| 340 | |
| 341 | /* Ordinary loser */ |
| 342 | rv = VLIB_PARSE_MATCH_FAIL; |
| 343 | |
| 344 | /* Ambiguous loser */ |
| 345 | if (vec_len (partial_matches) > 1) |
| 346 | { |
| 347 | vec_free (partial_matches); |
| 348 | rv = VLIB_PARSE_MATCH_AMBIGUOUS; |
| 349 | } |
| 350 | |
| 351 | _vec_len (pm->match_items) = save_match_items; |
| 352 | return rv; |
| 353 | } |
| 354 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 355 | vlib_parse_match_t |
| 356 | rule_match (vlib_parse_main_t * pm, vlib_parse_type_t * type, |
| 357 | vlib_lex_token_t * t, vlib_parse_value_t * valuep) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 358 | { |
| 359 | vlib_parse_match_t rv; |
| 360 | static int recursion_level; |
| 361 | |
| 362 | if (PARSE_DEBUG > 1) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 363 | clib_warning ("[%d]: try to match type %s graph index %d", |
| 364 | recursion_level, type->name, type->rule_index); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 365 | recursion_level++; |
| 366 | rv = parse_eval_internal (pm, type->rule_index); |
| 367 | recursion_level--; |
| 368 | |
| 369 | /* Break the recusive unwind here... */ |
| 370 | if (rv == VLIB_PARSE_MATCH_RULE) |
| 371 | { |
| 372 | if (PARSE_DEBUG > 1) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 373 | clib_warning ("[%d]: type %s matched", recursion_level, type->name); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 374 | |
| 375 | return VLIB_PARSE_MATCH_FULL; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 376 | } |
| 377 | else |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 378 | { |
| 379 | if (PARSE_DEBUG > 1) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 380 | clib_warning ("[%d]: type %s returns %U", recursion_level, type->name, |
| 381 | format_vlib_parse_match, rv); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 382 | } |
| 383 | return rv; |
| 384 | } |
| 385 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 386 | static int |
| 387 | parse_eval (vlib_parse_main_t * pm, u8 * input) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 388 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 389 | vlib_lex_token_t *t; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 390 | |
| 391 | parse_reset (pm, input); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 392 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 393 | /* Tokenize the entire input vector */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 394 | do |
| 395 | { |
| 396 | vec_add2 (pm->tokens, t, 1); |
| 397 | vlib_lex_get_token (pm->lex_main, t); |
| 398 | } |
| 399 | while (t->token != VLIB_LEX_eof); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 400 | |
| 401 | /* Feed it to the parser */ |
| 402 | return parse_eval_internal (pm, pm->root_index); |
| 403 | } |
| 404 | |
| 405 | /* Temporary vlib stub */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 406 | vlib_parse_match_t |
| 407 | vlib_parse_eval (u8 * input) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 408 | { |
| 409 | return parse_eval (&vlib_parse_main, input); |
| 410 | } |
| 411 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 412 | u16 |
| 413 | parse_type_find_or_create (vlib_parse_main_t * pm, vlib_parse_type_t * t) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 414 | { |
| 415 | uword *p; |
| 416 | vlib_parse_type_t *n; |
| 417 | u8 *name_copy; |
| 418 | |
| 419 | p = hash_get_mem (pm->parse_type_by_name_hash, t->name); |
| 420 | if (p) |
| 421 | return p[0]; |
| 422 | |
| 423 | pool_get (pm->parse_types, n); |
| 424 | *n = *t; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 425 | n->rule_index = (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 426 | |
| 427 | name_copy = format (0, "%s%c", n->name, 0); |
| 428 | |
| 429 | hash_set_mem (pm->parse_type_by_name_hash, name_copy, n - pm->parse_types); |
| 430 | return n - pm->parse_types; |
| 431 | } |
| 432 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 433 | u16 |
| 434 | parse_type_find_by_name (vlib_parse_main_t * pm, char *name) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 435 | { |
| 436 | uword *p; |
| 437 | |
| 438 | p = hash_get_mem (pm->parse_type_by_name_hash, name); |
| 439 | if (p) |
| 440 | return p[0]; |
| 441 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 442 | return (u16) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 443 | } |
| 444 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 445 | u32 |
| 446 | parse_item_find_or_create (vlib_parse_main_t * pm, vlib_parse_item_t * item) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 447 | { |
| 448 | uword *p; |
| 449 | vlib_parse_item_t *i; |
| 450 | |
| 451 | /* Exact match the entire item */ |
| 452 | p = mhash_get (&pm->parse_item_hash, item); |
| 453 | if (p) |
| 454 | return p[0]; |
| 455 | |
| 456 | pool_get (pm->parse_items, i); |
| 457 | *i = *item; |
| 458 | |
| 459 | mhash_set (&pm->parse_item_hash, i, i - pm->parse_items, 0); |
| 460 | return i - pm->parse_items; |
| 461 | } |
| 462 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 463 | static void |
| 464 | parse_type_and_graph_init (vlib_parse_main_t * pm) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 465 | { |
| 466 | u32 eof_index; |
| 467 | vlib_parse_type_t type; |
| 468 | vlib_parse_item_t item; |
| 469 | |
| 470 | memset (&type, 0, sizeof (type)); |
| 471 | |
| 472 | #define foreach_token_type \ |
| 473 | _ (eof) \ |
| 474 | _ (rule_eof) \ |
| 475 | _ (word) \ |
| 476 | _ (number) \ |
| 477 | _ (plus) \ |
| 478 | _ (minus) \ |
| 479 | _ (star) \ |
| 480 | _ (slash) \ |
| 481 | _ (lpar) \ |
| 482 | _ (rpar) |
| 483 | |
| 484 | #define _(a) a##_type_index = parse_type_find_by_name (pm, #a); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 485 | foreach_token_type |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 486 | #undef _ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 487 | memset (&item, 0, sizeof (item)); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 488 | item.type = eof_type_index; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 489 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 490 | eof_index = parse_item_find_or_create (pm, &item); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 491 | pm->root_index = (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 492 | |
| 493 | #if 0 |
| 494 | pool_get (pm->parse_graph, g); |
| 495 | memset (g, 0xff, sizeof (*g)); |
| 496 | g->item = eof_index; |
| 497 | pm->root_index = 0; |
| 498 | #endif |
| 499 | } |
| 500 | |
| 501 | |
| 502 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 503 | static void |
| 504 | tokenize (vlib_parse_main_t * pm, parse_registration_t * pr) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 505 | { |
| 506 | vlib_lex_token_t *t; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 507 | pm->register_input = format (pm->register_input, |
| 508 | "%s%c", pr->initializer, 0); |
| 509 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 510 | parse_reset (pm, pm->register_input); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 511 | |
| 512 | do |
| 513 | { |
| 514 | vec_add2 (pm->tokens, t, 1); |
| 515 | vlib_lex_get_token (pm->lex_main, t); |
| 516 | } |
| 517 | while (t->token != VLIB_LEX_eof); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 518 | _vec_len (pm->register_input) = 0; |
| 519 | } |
| 520 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 521 | static int |
| 522 | is_typed_rule (vlib_parse_main_t * pm) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 523 | { |
| 524 | vlib_lex_token_t *t = vec_elt_at_index (pm->tokens, 0); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 525 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 526 | /* <mytype> = blah blah blah */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 527 | if (vec_len (pm->tokens) >= 4 |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 528 | && t[0].token == VLIB_LEX_lt |
| 529 | && t[1].token == VLIB_LEX_word |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 530 | && t[2].token == VLIB_LEX_gt && t[3].token == VLIB_LEX_equals) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 531 | return 1; |
| 532 | return 0; |
| 533 | } |
| 534 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 535 | static int |
| 536 | token_matches_graph_node (vlib_parse_main_t * pm, |
| 537 | vlib_lex_token_t * t, |
| 538 | vlib_parse_graph_t * node, |
| 539 | vlib_parse_item_t * item, |
| 540 | vlib_parse_type_t * type, u32 * token_increment) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 541 | { |
| 542 | /* EOFs don't match */ |
| 543 | if (t->token == VLIB_LEX_eof) |
| 544 | return 0; |
| 545 | |
| 546 | /* New chain element is a word */ |
| 547 | if (t->token == VLIB_LEX_word) |
| 548 | { |
| 549 | /* but the item in hand is not a word */ |
| 550 | if (item->type != word_type_index) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 551 | return 0; |
| 552 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 553 | /* Or it's not this particular word */ |
| 554 | if (strcmp (t->value.as_pointer, item->value.as_pointer)) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 555 | return 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 556 | *token_increment = 1; |
| 557 | return 1; |
| 558 | } |
| 559 | /* New chain element is a type-name: < TYPE-NAME > */ |
| 560 | if (t->token == VLIB_LEX_lt) |
| 561 | { |
| 562 | u16 token_type_index; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 563 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 564 | /* < TYPE > */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 565 | if (t[1].token != VLIB_LEX_word || t[2].token != VLIB_LEX_gt) |
| 566 | { |
| 567 | clib_warning (0, "broken type name in '%s'", pm->register_input); |
| 568 | return 0; |
| 569 | } |
| 570 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 571 | token_type_index = parse_type_find_by_name (pm, t[1].value.as_pointer); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 572 | if (token_type_index == (u16) ~ 0) |
| 573 | { |
| 574 | clib_warning (0, "unknown type '%s'", t[1].value.as_pointer); |
| 575 | return 0; |
| 576 | } |
| 577 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 578 | /* Its a known type but does not match. */ |
| 579 | if (item->type != token_type_index) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 580 | return 0; |
| 581 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 582 | *token_increment = 3; |
| 583 | return 1; |
| 584 | } |
| 585 | clib_warning ("BUG: t->token = %d", t->token); |
| 586 | return 0; |
| 587 | } |
| 588 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 589 | u32 |
| 590 | generate_subgraph_from_tokens (vlib_parse_main_t * pm, |
| 591 | vlib_lex_token_t * t, |
| 592 | u32 * new_subgraph_depth, |
| 593 | parse_registration_t * pr, int not_a_rule) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 594 | { |
| 595 | vlib_parse_graph_t *g, *last_g; |
| 596 | vlib_parse_item_t new_item; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 597 | u32 rv = (u32) ~ 0, new_item_index, last_index = (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 598 | u16 token_type_index; |
| 599 | u32 depth = 0; |
| 600 | |
| 601 | while (t < pm->tokens + vec_len (pm->tokens)) |
| 602 | { |
| 603 | memset (&new_item, 0, sizeof (new_item)); |
| 604 | |
| 605 | if (t->token == VLIB_LEX_word) |
| 606 | { |
| 607 | new_item.type = word_type_index; |
| 608 | new_item.value.as_pointer = vec_dup ((u8 *) t->value.as_pointer); |
| 609 | new_item_index = parse_item_find_or_create (pm, &new_item); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 610 | t++; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 611 | } |
| 612 | else if (t->token == VLIB_LEX_lt) |
| 613 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 614 | if (t[1].token != VLIB_LEX_word || t[2].token != VLIB_LEX_gt) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 615 | { |
| 616 | clib_warning ("broken type name in '%s'", pm->register_input); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 617 | goto screwed; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 618 | } |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 619 | token_type_index = parse_type_find_by_name (pm, |
| 620 | t[1].value.as_pointer); |
| 621 | if (token_type_index == (u16) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 622 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 623 | clib_warning ("unknown type 2 '%s'", t[1].value.as_pointer); |
| 624 | goto screwed; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 625 | } |
| 626 | |
| 627 | new_item.type = token_type_index; |
| 628 | new_item.value.as_pointer = 0; |
| 629 | new_item_index = parse_item_find_or_create (pm, &new_item); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 630 | t += 3; /* skip < <type-name> and > */ |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 631 | } |
| 632 | else if (t->token == VLIB_LEX_eof) |
| 633 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 634 | screwed: |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 635 | new_item.type = not_a_rule ? eof_type_index : rule_eof_type_index; |
| 636 | new_item.value.as_pointer = pr->eof_match; |
| 637 | new_item_index = parse_item_find_or_create (pm, &new_item); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 638 | t++; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 639 | } |
| 640 | else |
| 641 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 642 | clib_warning ("unexpected token %U index %d in '%s'", |
| 643 | format_vlib_lex_token, pm->lex_main, t, |
| 644 | t - pm->tokens, pm->register_input); |
| 645 | goto screwed; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 646 | } |
| 647 | |
| 648 | pool_get (pm->parse_graph, g); |
| 649 | memset (g, 0xff, sizeof (*g)); |
| 650 | g->item = new_item_index; |
| 651 | depth++; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 652 | |
| 653 | if (rv == (u32) ~ 0) |
| 654 | { |
| 655 | rv = g - pm->parse_graph; |
| 656 | last_index = rv; |
| 657 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 658 | else |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 659 | { |
| 660 | last_g = pool_elt_at_index (pm->parse_graph, last_index); |
| 661 | last_index = last_g->deeper = g - pm->parse_graph; |
| 662 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 663 | } |
| 664 | *new_subgraph_depth = depth; |
| 665 | return rv; |
| 666 | } |
| 667 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 668 | static u32 |
| 669 | measure_depth (vlib_parse_main_t * pm, u32 index) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 670 | { |
| 671 | vlib_parse_graph_t *node; |
| 672 | vlib_parse_item_t *item; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 673 | u32 max = 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 674 | u32 depth; |
| 675 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 676 | if (index == (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 677 | return 0; |
| 678 | |
| 679 | node = pool_elt_at_index (pm->parse_graph, index); |
| 680 | item = pool_elt_at_index (pm->parse_items, node->item); |
| 681 | |
| 682 | if (item->type == eof_type_index) |
| 683 | return 1; |
| 684 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 685 | while (index != (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 686 | { |
| 687 | node = pool_elt_at_index (pm->parse_graph, index); |
| 688 | depth = measure_depth (pm, node->deeper); |
| 689 | if (max < depth) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 690 | max = depth; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 691 | index = node->peer; |
| 692 | } |
| 693 | |
| 694 | return max + 1; |
| 695 | } |
| 696 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 697 | static void |
| 698 | add_subgraph_to_graph (vlib_parse_main_t * pm, |
| 699 | u32 last_matching_index, |
| 700 | u32 graph_root_index, |
| 701 | u32 new_subgraph_index, u32 new_subgraph_depth) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 702 | { |
| 703 | vlib_parse_graph_t *parent_node; |
| 704 | int new_subgraph_longest = 1; |
| 705 | u32 current_peer_index; |
| 706 | u32 current_depth; |
| 707 | vlib_parse_graph_t *current_peer = 0; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 708 | vlib_parse_graph_t *new_subgraph_node = |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 709 | pool_elt_at_index (pm->parse_graph, new_subgraph_index); |
| 710 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 711 | /* |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 712 | * Case 1: top-level peer. Splice into the top-level |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 713 | * peer chain according to rule depth |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 714 | */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 715 | if (last_matching_index == (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 716 | { |
| 717 | u32 index = graph_root_index; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 718 | while (1) |
| 719 | { |
| 720 | current_peer = pool_elt_at_index (pm->parse_graph, index); |
| 721 | current_depth = measure_depth (pm, index); |
| 722 | if (current_depth < new_subgraph_depth |
| 723 | || current_peer->peer == (u32) ~ 0) |
| 724 | break; |
| 725 | index = current_peer->peer; |
| 726 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 727 | new_subgraph_node->peer = current_peer->peer; |
| 728 | current_peer->peer = new_subgraph_index; |
| 729 | return; |
| 730 | } |
| 731 | |
| 732 | parent_node = pool_elt_at_index (pm->parse_graph, last_matching_index); |
| 733 | current_peer_index = parent_node->deeper; |
| 734 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 735 | while (current_peer_index != (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 736 | { |
| 737 | current_peer = pool_elt_at_index (pm->parse_graph, current_peer_index); |
| 738 | current_depth = measure_depth (pm, current_peer_index); |
| 739 | if (current_depth < new_subgraph_depth) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 740 | break; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 741 | new_subgraph_longest = 0; |
| 742 | current_peer_index = current_peer->peer; |
| 743 | } |
| 744 | |
| 745 | ASSERT (current_peer); |
| 746 | |
| 747 | if (new_subgraph_longest) |
| 748 | { |
| 749 | new_subgraph_node->peer = parent_node->deeper; |
| 750 | parent_node->deeper = new_subgraph_index; |
| 751 | } |
| 752 | else |
| 753 | { |
| 754 | new_subgraph_node->peer = current_peer->peer; |
| 755 | current_peer->peer = new_subgraph_index; |
| 756 | } |
| 757 | } |
| 758 | |
| 759 | static clib_error_t * |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 760 | parse_register_one (vlib_parse_main_t * pm, parse_registration_t * pr) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 761 | { |
| 762 | u32 graph_root_index; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 763 | u16 subgraph_type_index = (u16) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 764 | vlib_parse_type_t *subgraph_type = 0; |
| 765 | vlib_lex_token_t *t; |
| 766 | vlib_parse_graph_t *node; |
| 767 | u32 node_index, last_index, token_increment, new_subgraph_index; |
| 768 | u32 new_subgraph_depth, last_matching_index; |
| 769 | vlib_parse_item_t *item; |
| 770 | vlib_parse_type_t *type; |
| 771 | |
| 772 | int use_main_graph = 1; |
| 773 | |
| 774 | tokenize (pm, pr); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 775 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 776 | /* A typed rule? */ |
| 777 | if (is_typed_rule (pm)) |
| 778 | { |
| 779 | /* Get the type and its current subgraph root, if any */ |
| 780 | t = vec_elt_at_index (pm->tokens, 1); |
| 781 | subgraph_type_index = parse_type_find_by_name (pm, t->value.as_pointer); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 782 | if (subgraph_type_index == (u16) ~ 0) |
| 783 | return clib_error_return (0, "undeclared type '%s'", |
| 784 | t->value.as_pointer); |
| 785 | subgraph_type = |
| 786 | pool_elt_at_index (pm->parse_types, subgraph_type_index); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 787 | graph_root_index = subgraph_type->rule_index; |
| 788 | /* Skip "mytype> = */ |
| 789 | t += 3; |
| 790 | use_main_graph = 0; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 791 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 792 | else |
| 793 | { |
| 794 | /* top-level graph */ |
| 795 | graph_root_index = pm->root_index; |
| 796 | t = vec_elt_at_index (pm->tokens, 0); |
| 797 | } |
| 798 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 799 | last_matching_index = (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 800 | last_index = node_index = graph_root_index; |
| 801 | |
| 802 | /* Find the first token which isn't already being parsed */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 803 | while (t < pm->tokens + vec_len (pm->tokens) && node_index != (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 804 | { |
| 805 | node = pool_elt_at_index (pm->parse_graph, node_index); |
| 806 | item = pool_elt_at_index (pm->parse_items, node->item); |
| 807 | type = pool_elt_at_index (pm->parse_types, item->type); |
| 808 | last_index = node_index; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 809 | |
| 810 | if (token_matches_graph_node |
| 811 | (pm, t, node, item, type, &token_increment)) |
| 812 | { |
| 813 | t += token_increment; |
| 814 | last_matching_index = node_index; |
| 815 | node_index = node->deeper; |
| 816 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 817 | else |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 818 | node_index = node->peer; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 819 | } |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 820 | |
| 821 | new_subgraph_index = |
| 822 | generate_subgraph_from_tokens (pm, t, &new_subgraph_depth, pr, |
| 823 | use_main_graph); |
| 824 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 825 | /* trivial cases: first graph node or first type rule */ |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 826 | if (graph_root_index == (u32) ~ 0) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 827 | { |
| 828 | if (use_main_graph) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 829 | pm->root_index = new_subgraph_index; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 830 | else |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 831 | subgraph_type->rule_index = new_subgraph_index; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 832 | return 0; |
| 833 | } |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 834 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 835 | add_subgraph_to_graph (pm, last_matching_index, graph_root_index, |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 836 | new_subgraph_index, new_subgraph_depth); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 837 | return 0; |
| 838 | } |
| 839 | |
| 840 | static clib_error_t * |
| 841 | parse_register (vlib_main_t * vm, |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 842 | parse_registration_t * lo, |
| 843 | parse_registration_t * hi, vlib_parse_main_t * pm) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 844 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 845 | parse_registration_t *pr; |
| 846 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 847 | for (pr = lo; pr < hi; pr = vlib_elf_section_data_next (pr, 0)) |
| 848 | vec_add1 (pm->parse_registrations, pr); |
| 849 | |
| 850 | return 0; |
| 851 | } |
| 852 | |
| 853 | static clib_error_t * |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 854 | parse_register_one_type (vlib_parse_main_t * pm, vlib_parse_type_t * rp) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 855 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 856 | (void) parse_type_find_or_create (pm, (vlib_parse_type_t *) rp); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 857 | return 0; |
| 858 | } |
| 859 | |
| 860 | static clib_error_t * |
| 861 | parse_type_register (vlib_main_t * vm, |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 862 | vlib_parse_type_t * lo, |
| 863 | vlib_parse_type_t * hi, vlib_parse_main_t * pm) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 864 | { |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 865 | clib_error_t *error = 0; |
| 866 | vlib_parse_type_t *ptr; |
| 867 | |
| 868 | for (ptr = lo; ptr < hi; ptr = vlib_elf_section_data_next (ptr, 0)) |
| 869 | { |
| 870 | error = parse_register_one_type (pm, ptr); |
| 871 | if (error) |
| 872 | goto done; |
| 873 | } |
| 874 | |
| 875 | done: |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 876 | return error; |
| 877 | } |
| 878 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 879 | clib_error_t *vlib_stdlex_init (vlib_main_t * vm) __attribute__ ((weak)); |
| 880 | clib_error_t * |
| 881 | vlib_stdlex_init (vlib_main_t * vm) |
| 882 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 883 | (void) vlib_lex_add_table ("ignore_everything"); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 884 | return 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 885 | } |
| 886 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 887 | static int |
| 888 | compute_rule_length (parse_registration_t * r) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 889 | { |
| 890 | int length, i; |
| 891 | vlib_parse_main_t *pm = &vlib_parse_main; |
| 892 | |
| 893 | if (r->rule_length) |
| 894 | return r->rule_length; |
| 895 | |
| 896 | length = 0; |
| 897 | |
| 898 | tokenize (pm, r); |
| 899 | length = vec_len (pm->tokens); |
| 900 | |
| 901 | /* Account for "<foo> = " in "<foo> = bar" etc. */ |
| 902 | if (is_typed_rule (pm)) |
| 903 | length -= 2; |
| 904 | |
| 905 | for (i = 0; i < vec_len (pm->tokens); i++) |
| 906 | { |
| 907 | switch (pm->tokens[i].token) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 908 | { |
| 909 | case VLIB_LEX_lt: |
| 910 | case VLIB_LEX_gt: |
| 911 | length -= 1; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 912 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 913 | default: |
| 914 | break; |
| 915 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 916 | } |
| 917 | |
| 918 | ASSERT (length > 0); |
| 919 | r->rule_length = length; |
| 920 | return length; |
| 921 | } |
| 922 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 923 | static int |
| 924 | rule_length_compare (parse_registration_t * r1, parse_registration_t * r2) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 925 | { |
| 926 | compute_rule_length (r1); |
| 927 | compute_rule_length (r2); |
| 928 | /* Descending sort */ |
| 929 | return r2->rule_length - r1->rule_length; |
| 930 | } |
| 931 | |
| 932 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 933 | static clib_error_t * |
| 934 | parse_init (vlib_main_t * vm) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 935 | { |
| 936 | vlib_parse_main_t *pm = &vlib_parse_main; |
| 937 | vlib_lex_main_t *lm = &vlib_lex_main; |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 938 | vlib_elf_section_bounds_t *b, *bounds; |
| 939 | clib_error_t *error = 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 940 | parse_registration_t *rule; |
| 941 | int i; |
| 942 | |
| 943 | if ((error = vlib_call_init_function (vm, lex_onetime_init))) |
| 944 | return error; |
| 945 | |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 946 | if ((error = vlib_stdlex_init (vm))) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 947 | return error; |
| 948 | |
| 949 | if ((error = vlib_call_init_function (vm, parse_builtin_init))) |
| 950 | return error; |
| 951 | |
| 952 | pm->vlib_main = vm; |
| 953 | pm->lex_main = lm; |
| 954 | |
| 955 | mhash_init (&pm->parse_item_hash, sizeof (u32), sizeof (vlib_parse_item_t)); |
| 956 | pm->parse_type_by_name_hash = hash_create_string (0, sizeof (u32)); |
| 957 | |
| 958 | vec_validate (pm->parse_value, 16); |
| 959 | vec_validate (pm->tokens, 16); |
| 960 | vec_validate (pm->register_input, 32); |
| 961 | vec_validate (pm->match_items, 16); |
| 962 | |
| 963 | _vec_len (pm->parse_value) = 0; |
| 964 | _vec_len (pm->tokens) = 0; |
| 965 | _vec_len (pm->register_input) = 0; |
| 966 | _vec_len (pm->match_items) = 0; |
| 967 | |
| 968 | bounds = vlib_get_elf_section_bounds (vm, "parse_type_registrations"); |
| 969 | vec_foreach (b, bounds) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 970 | { |
| 971 | error = parse_type_register (vm, b->lo, b->hi, pm); |
| 972 | if (error) |
| 973 | break; |
| 974 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 975 | vec_free (bounds); |
| 976 | |
| 977 | parse_type_and_graph_init (pm); |
| 978 | |
| 979 | bounds = vlib_get_elf_section_bounds (vm, "parse_registrations"); |
| 980 | vec_foreach (b, bounds) |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 981 | { |
| 982 | error = parse_register (vm, b->lo, b->hi, pm); |
| 983 | if (error) |
| 984 | break; |
| 985 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 986 | vec_free (bounds); |
| 987 | |
Matus Fabian | d2dc3df | 2015-12-14 10:31:33 -0500 | [diff] [blame] | 988 | vec_sort_with_function (pm->parse_registrations, rule_length_compare); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 989 | |
| 990 | for (i = 0; i < vec_len (pm->parse_registrations); i++) |
| 991 | { |
| 992 | rule = pm->parse_registrations[i]; |
| 993 | parse_register_one (pm, rule); |
| 994 | } |
| 995 | |
| 996 | return error; |
| 997 | } |
| 998 | |
| 999 | VLIB_INIT_FUNCTION (parse_init); |
Dave Barach | 9b8ffd9 | 2016-07-08 08:13:45 -0400 | [diff] [blame] | 1000 | |
| 1001 | /* |
| 1002 | * fd.io coding-style-patch-verification: ON |
| 1003 | * |
| 1004 | * Local Variables: |
| 1005 | * eval: (c-set-style "gnu") |
| 1006 | * End: |
| 1007 | */ |