4 * MATE's configuration language grammar
6 * Copyright 2005, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include "mate_grammar.h"
34 typedef struct _extraction {
36 header_field_info* hfi;
37 struct _extraction* next;
38 struct _extraction* last;
41 typedef struct _pdu_criteria_t {
43 avpl_match_mode criterium_match_mode;
44 accept_mode_t criterium_accept_mode;
47 typedef struct _gop_options {
48 gop_tree_mode_t pdu_tree_mode;
49 gboolean drop_unassigned;
59 typedef struct _gog_statements {
61 gop_tree_mode_t gop_tree_mode;
62 GPtrArray* transform_list;
64 LoAL* current_gogkeys;
67 typedef struct _transf_match_t {
68 avpl_match_mode match_mode;
72 typedef struct _transf_action_t {
73 avpl_replace_mode replace_mode;
77 static void configuration_error(mate_config* mc, const gchar* fmt, ...) {
78 static gchar error_buffer[256];
81 mate_config_frame* current_frame;
84 va_start( list, fmt );
85 g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list);
88 i = (gint) mc->config_stack->len;
93 incl = "\n included from: ";
98 current_frame = g_ptr_array_index(mc->config_stack,(guint)i);
100 g_string_sprintfa(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum);
103 g_string_sprintfa(mc->config_error,": %s\n",error_buffer);
105 THROW(MateConfigError);
109 static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
110 AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
114 t->replace = replace;
115 t->match_mode = match_mode;
116 t->replace_mode = replace_mode;
124 static gchar* recolonize(mate_config* mc, gchar* s) {
125 GString* str = g_string_new("");
131 vec = g_strsplit(s,":",0);
133 for (i = 0; vec[i]; i++) {
137 switch ( strlen(vec[i]) ) {
140 vec[i][1] = vec[i][0];
142 if (vec[i][0] >= '0' && vec[i][0] <= '9') {
143 v += (vec[i][1] - '0' )*16;
145 v += (vec[i][1] - 'a' + 10)*16;
148 if (vec[i][0] >= '0' && vec[i][0] <= '9') {
149 v += (vec[i][0] - '0' );
151 v += (vec[i][0] - 'a' + 10);
156 configuration_error(mc,"bad token %s",s);
159 g_string_sprintfa(str,":%.2X",v);
164 g_string_erase(str,0,1);
168 g_string_free(str,FALSE);
179 %token_type { gchar* }
180 %token_destructor { if ($$) g_free($$); }
182 %extra_argument { mate_config* mc }
185 configuration_error(mc,"Syntax Error before %s",yyminor);
189 configuration_error(mc,"Parse Error");
192 %type transform_decl { AVPL_Transf* }
193 %type transform_body { AVPL_Transf* }
194 %type transform_statements { AVPL_Transf* }
195 %type transform_statement { AVPL_Transf* }
196 %type transform_match { transf_match_t* }
197 %type transform_action { transf_action_t* }
198 %type match_mode { avpl_match_mode }
199 %type action_mode { avpl_replace_mode }
201 %type gop_name { gchar* }
202 %type time_value { float }
203 %type pdu_name { gchar* }
204 %type gop_tree_mode { gop_tree_mode_t }
205 %type true_false { gboolean }
207 %type criteria_statement { pdu_criteria_t* }
208 %type accept_mode { accept_mode_t }
209 %type pdu_drop_unassigned_statement { gboolean }
210 %type discard_pdu_data_statement { gboolean }
211 %type last_extracted_statement { gboolean }
213 %type extraction_statement {extraction_t*}
214 %type extraction_statements {extraction_t*}
216 %type gop_options { gop_options_t* }
218 %type gop_start_statement { AVPL* }
219 %type gop_stop_statement { AVPL* }
220 %type extra_statement { AVPL* }
221 %type gop_drop_unassigned_statement { gboolean }
222 %type show_goptree_statement { gop_tree_mode_t }
223 %type show_times_statement { gboolean }
224 %type gop_expiration_statement { float }
225 %type idle_timeout_statement { float }
226 %type lifetime_statement { float }
228 %type gog_statements { gog_statement_t* }
229 %type gog_expiration_statement { float }
230 %type gog_goptree_statement { gop_tree_mode_t }
231 %type gog_key_statements { LoAL* }
232 %type gog_key_statement { AVPL* }
233 %type transform_list_statement { GPtrArray* }
234 %type transform { AVPL_Transf* }
235 %type gop_tree_type { gop_tree_mode_t }
237 %type payload_statement { GPtrArray* }
238 %type proto_stack { GPtrArray* }
239 %type field { header_field_info* }
240 %type transform_list { GPtrArray* }
244 %type value { gchar* }
245 %type avp_oneoff { gchar* }
248 mate_config ::= decls.
250 decls ::= decls decl.
256 decl ::= transform_decl.
257 decl ::= defaults_decl.
259 decl ::= DONE_KW SEMICOLON.
264 debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON.
266 dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
267 dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
268 dbgfile_default ::= .
270 dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); }
271 dbglevel_default ::= .
273 pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); }
274 pdu_dbglevel_default ::= .
276 gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); }
277 gop_dbglevel_default ::= .
279 gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); }
280 gog_dbglevel_default ::= .
283 /************* DEFAULTS
286 defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON.
288 pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON.
291 pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; }
292 pdu_last_extracted_default ::= .
294 pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; }
295 pdu_drop_unassigned_default ::= .
297 pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; }
298 pdu_discard_default ::= .
300 gop_defaults ::= GOP_KW OPEN_BRACE gop_expiration_default gop_idle_timeout_default gop_lifetime_default gop_drop_unassigned_default gop_tree_mode_default gop_show_times_default CLOSE_BRACE SEMICOLON.
303 gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
304 gop_expiration_default ::= .
306 gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; }
307 gop_idle_timeout_default ::= .
309 gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; }
310 gop_lifetime_default ::= .
312 gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; }
313 gop_drop_unassigned_default ::= .
315 gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = B; }
316 gop_tree_mode_default ::= .
318 gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; }
319 gop_show_times_default ::= .
321 gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default CLOSE_BRACE SEMICOLON.
324 gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
325 gog_expiration_default ::= .
327 gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; }
328 gog_goptree_default ::= .
331 /******************************************* TRANSFORM
334 transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. {
337 if ( g_hash_table_lookup(mc->transfs,B) ) {
338 configuration_error(mc,"A transformation called '%s' exists already",B);
341 for ( c = C; c; c = c->next )
342 c->name = g_strdup(B);
344 g_hash_table_insert(mc->transfs,C->name,C);
349 transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; }
351 transform_statements(A) ::= transform_statements(C) transform_statement(B). {
354 for ( c = C; c->next; c = c->next ) ;
359 transform_statements(A) ::= transform_statement(B). { A = B; }
361 transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. {
362 A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode);
365 transform_match(A) ::= MATCH_KW match_mode(Mode) avpl(Avpl). {
366 A = g_malloc(sizeof(transf_match_t));
367 A->match_mode = Mode;
371 transform_match(A) ::= . {
372 A = g_malloc(sizeof(transf_match_t));
373 A->match_mode = AVPL_STRICT;
374 A->avpl = new_avpl("");
378 transform_action(A) ::= . {
379 A = g_malloc(sizeof(transf_action_t));
380 A->replace_mode = AVPL_INSERT;
381 A->avpl = new_avpl("");
383 transform_action(A) ::= action_mode(Mode) avpl(Avpl). {
384 A = g_malloc(sizeof(transf_action_t));
385 A->replace_mode = Mode;
389 match_mode(A) ::= . { A = AVPL_STRICT; }
390 match_mode(A) ::= STRICT_KW. { A = AVPL_STRICT; }
391 match_mode(A) ::= EVERY_KW. { A = AVPL_EVERY; }
392 match_mode(A) ::= LOOSE_KW. { A = AVPL_LOOSE; }
394 action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; }
395 action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; }
396 action_mode(A) ::= . { A = AVPL_INSERT; }
398 /******************************************* PDU
402 PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack)
404 payload_statement(Payload)
405 extraction_statements(Extraction)
406 transform_list_statement(Transform)
407 criteria_statement(Criteria)
408 pdu_drop_unassigned_statement(DropUnassigned)
409 discard_pdu_data_statement(DistcardPduData)
410 last_extracted_statement(LastExtracted)
411 CLOSE_BRACE SEMICOLON.
414 mate_cfg_pdu* cfg = new_pducfg(Name);
415 extraction_t *extraction, *next_extraction;
416 GPtrArray* transport_stack = g_ptr_array_new();
419 if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name);
421 cfg->hfid_proto = Field->id;
423 cfg->last_extracted = LastExtracted;
424 cfg->discard = DistcardPduData;
425 cfg->drop_unassigned = DropUnassigned;
427 g_string_sprintfa(mc->protos_filter,"||%s",Field->abbrev);
429 /* flip the transport_stack */
430 for (i = Stack->len - 1; Stack->len; i--) {
431 g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i));
434 g_ptr_array_free(Stack,FALSE);
436 cfg->transport_ranges = transport_stack;
437 cfg->payload_ranges = Payload;
440 cfg->criterium = Criteria->criterium_avpl;
441 cfg->criterium_match_mode = Criteria->criterium_match_mode;
442 cfg->criterium_accept_mode = Criteria->criterium_accept_mode;
445 cfg->transforms = Transform;
447 for (extraction = Extraction; extraction; extraction = next_extraction) {
448 next_extraction = extraction->next;
450 if ( ! add_hfid(extraction->hfi, extraction->as, cfg->hfids_attr) ) {
451 configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as);
458 payload_statement(A) ::= . { A = NULL; }
459 payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; }
461 criteria_statement(A) ::= . { A = NULL; }
462 criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. {
463 A = g_malloc(sizeof(pdu_criteria_t));
464 A->criterium_avpl = D;
465 A->criterium_match_mode = C;
466 A->criterium_accept_mode = B;
469 accept_mode(A) ::= . { A = ACCEPT_MODE; }
470 accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; }
471 accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; }
473 extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; }
474 extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; }
476 extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. {
477 A = g_malloc(sizeof(extraction_t));
480 A->next = A->last = NULL;
484 pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
485 pdu_drop_unassigned_statement(A) ::= . { A = mc->defaults.pdu.drop_unassigned; }
487 discard_pdu_data_statement(A) ::= DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; }
488 discard_pdu_data_statement(A) ::= . { A = mc->defaults.pdu.discard; }
490 last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; }
491 last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; }
493 proto_stack(A) ::= proto_stack(B) SLASH field(C). {
494 int* hfidp = g_malloc(sizeof(int));
496 g_string_sprintfa(mc->fields_filter,"||%s",C->abbrev);
499 g_ptr_array_add(B,hfidp);
503 proto_stack(A) ::= field(B). {
504 int* hfidp = g_malloc(sizeof(int));
507 g_string_sprintfa(mc->fields_filter,"||%s",B->abbrev);
509 A = g_ptr_array_new();
510 g_ptr_array_add(A,hfidp);
513 field(A) ::= NAME(B). {
514 A = proto_registrar_get_byname(B);
517 /******************************************* GOP
520 gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE
521 gop_start_statement(Start)
522 gop_stop_statement(Stop)
523 extra_statement(Extra)
524 transform_list_statement(Transform)
525 gop_expiration_statement(Expiration)
526 idle_timeout_statement(IdleTimeout)
527 lifetime_statement(Lifetime)
528 gop_drop_unassigned_statement(DropUnassigned)
529 show_goptree_statement(TreeMode)
530 show_times_statement(ShowTimes)
531 CLOSE_BRACE SEMICOLON. {
534 if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name);
535 if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName);
537 cfg = new_gopcfg(Name);
538 g_hash_table_insert(mc->gops_by_pduname,PduName,cfg);
539 g_hash_table_insert(mc->gopcfgs,cfg->name,cfg);
541 cfg->on_pdu = PduName;
543 cfg->drop_unassigned = DropUnassigned;
544 cfg->show_times = ShowTimes;
545 cfg->pdu_tree_mode = TreeMode;
546 cfg->expiration = Expiration;
547 cfg->idle_timeout = IdleTimeout;
548 cfg->lifetime = Lifetime;
551 cfg->transforms = Transform;
553 merge_avpl(cfg->extra,Extra,TRUE);
554 delete_avpl(Extra,TRUE);
557 gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
558 gop_drop_unassigned_statement(A) ::= . { A = mc->defaults.gop.drop_unassigned; }
560 gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; }
561 gop_start_statement(A) ::= . { A = NULL; }
563 gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; }
564 gop_stop_statement(A) ::= . { A = NULL; }
566 show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; }
567 show_goptree_statement(A) ::= . { A = mc->defaults.gop.pdu_tree_mode; }
569 show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; }
570 show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; }
572 gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
573 gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
575 idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; }
576 idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
578 lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; }
579 lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
581 gop_tree_mode(A) ::= NO_TREE_KW. { A = GOP_NO_TREE; }
582 gop_tree_mode(A) ::= PDU_TREE_KW. { A = GOP_PDU_TREE; }
583 gop_tree_mode(A) ::= FRAME_TREE_KW. { A = GOP_FRAME_TREE; }
584 gop_tree_mode(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_PDU_TREE; }
586 true_false(A) ::= TRUE_KW. { A = TRUE; }
587 true_false(A) ::= FALSE_KW. { A = FALSE; }
589 pdu_name(A) ::= NAME(B). {
591 if (( c = g_hash_table_lookup(mc->pducfgs,B) )) {
594 configuration_error(mc,"No such Pdu: '%s'",B);
599 time_value(A) ::= FLOATING(B). {
600 A = (float) strtod(B,NULL);
603 time_value(A) ::= INTEGER(B). {
604 A = (float) strtod(B,NULL);
610 gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE
611 gog_key_statements(Keys)
612 extra_statement(Extra)
613 transform_list_statement(Transforms)
614 gog_expiration_statement(Expiration)
615 gog_goptree_statement(Tree)
616 CLOSE_BRACE SEMICOLON. {
617 mate_cfg_gog* cfg = NULL;
619 if ( g_hash_table_lookup(mc->gogcfgs,Name) ) {
620 configuration_error(mc,"Gog '%s' exists already ",Name);
623 cfg = new_gogcfg(Name);
625 cfg->expiration = Expiration;
626 cfg->gop_tree_mode = Tree;
627 cfg->transforms = Transforms;
630 merge_avpl(cfg->extra,Extra,TRUE);
631 delete_avpl(Extra,TRUE);
634 gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; }
635 gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; }
637 gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
638 gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; }
640 gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; }
641 gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; }
642 gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; }
644 gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). {
649 gog_key_statements(A) ::= gog_key_statement(B). {
655 gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. {
660 gop_name(A) ::= NAME(B). {
662 if (( c = g_hash_table_lookup(mc->gopcfgs,B) )) {
665 configuration_error(mc,"No Gop called '%s' has been already declared",B);
668 /******************************************** GENERAL
672 extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; }
673 extra_statement(A) ::= . { A = new_avpl(""); }
675 transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; }
676 transform_list_statement(A) ::= . { A = g_ptr_array_new(); }
678 transform_list(A) ::= transform_list(B) COMMA transform(C). {
680 g_ptr_array_add(B,C);
683 transform_list(A) ::= transform(B). {
684 A = g_ptr_array_new();
685 g_ptr_array_add(A,B);
688 transform(A) ::= NAME(B). {
691 if (( t = g_hash_table_lookup(mc->transfs,B) )) {
694 configuration_error(mc,"There's no such Transformation: %s",B);
698 avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; }
699 avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); }
701 avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); }
702 avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); }
704 avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); }
705 avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); }
706 avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); }
708 avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); }
709 avp_oneoff(A) ::= value(B). { A = g_strdup(B); }
711 value(A) ::= QUOTED(B). { A = g_strdup(B); }
712 value(A) ::= NAME(B). { A = g_strdup(B); }
713 value(A) ::= FLOATING(B). { A = g_strdup(B); }
714 value(A) ::= INTEGER(B). { A = g_strdup(B); }
715 value(A) ::= DOTED_IP(B). { A = g_strdup(B); }
716 value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }