mate_grammar.lemon:
[obnox/wireshark/wip.git] / plugins / mate / mate_grammar.lemon
1 %include {
2
3 /* mate_grammar.lemon
4 * MATE's configuration language grammar
5 *
6 * Copyright 2005, Luis E. Garcia Ontanon <luis@ontanon.org>
7 *
8 * $Id$
9 *
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
13 *
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.
18 *
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.
23 *
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.
27 */
28
29 #include "mate.h"
30 #include "mate_grammar.h"
31 #include <wsutil/file_util.h>
32
33 #define DUMMY void*
34
35 typedef struct _extraction {
36         gchar* as;
37         header_field_info* hfi;
38         struct _extraction* next;
39         struct _extraction* last;
40 } extraction_t;
41
42 typedef struct _pdu_criteria_t {
43         AVPL* criterium_avpl;
44         avpl_match_mode criterium_match_mode;
45         accept_mode_t criterium_accept_mode;
46 } pdu_criteria_t;
47
48 typedef struct _gop_options {
49         gop_tree_mode_t pdu_tree_mode;
50         gboolean drop_unassigned;
51         gboolean show_times;
52         float expiration;
53         float idle_timeout;
54         float lifetime;
55         AVPL* start;
56         AVPL* stop;
57         AVPL* extras;
58 } gop_options_t;
59
60 typedef struct _gog_statements {
61         float expiration;
62         gop_tree_mode_t gop_tree_mode;
63         GPtrArray* transform_list;
64         AVPL* extras;
65         LoAL* current_gogkeys;
66 } gog_statement_t;
67
68 typedef struct _transf_match_t {
69     avpl_match_mode match_mode;
70     AVPL* avpl;
71 } transf_match_t;
72
73 typedef struct _transf_action_t {
74     avpl_replace_mode replace_mode;
75     AVPL* avpl;
76 } transf_action_t;
77
78 static void configuration_error(mate_config* mc, const gchar* fmt, ...) {
79         static gchar error_buffer[256];
80         const gchar* incl;
81         gint i;
82         mate_config_frame* current_frame;
83         va_list list;
84
85         va_start( list, fmt );
86         g_vsnprintf(error_buffer,sizeof(error_buffer),fmt,list);
87         va_end( list );
88
89         i = (gint) mc->config_stack->len;
90
91         while (i--) {
92
93                 if (i>0) {
94                         incl = "\n   included from: ";
95                 } else {
96                         incl = " ";
97                 }
98
99                 current_frame = g_ptr_array_index(mc->config_stack,(guint)i);
100
101                 g_string_append_printf(mc->config_error,"%s%s at line %u",incl, current_frame->filename, current_frame->linenum);
102         }
103
104         g_string_append_printf(mc->config_error,": %s\n",error_buffer);
105
106         THROW(MateConfigError);
107
108 }
109
110 static AVPL_Transf* new_transform_elem(AVPL* match, AVPL* replace, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
111          AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
112
113          t->name = NULL;
114          t->match = match;
115          t->replace = replace;
116          t->match_mode = match_mode;
117          t->replace_mode = replace_mode;
118
119          t->map = NULL;
120          t->next = NULL;
121
122          return t;
123 }
124
125 static gchar* recolonize(mate_config* mc, gchar* s) {
126         GString* str = g_string_new("");
127         gchar** vec;
128         gchar* r;
129         guint i,v;
130         gchar c;
131
132         vec = g_strsplit(s,":",0);
133
134         for (i = 0; vec[i]; i++) {
135                 g_ascii_strdown(vec[i], -1);
136
137                 v = 0;
138                 switch ( strlen(vec[i]) ) {
139                  case 2:
140                     c = vec[i][1];
141                         vec[i][1] = vec[i][0];
142                         vec[i][0] = c;
143                         if (vec[i][0] >= '0' && vec[i][0] <= '9') {
144                                 v += (vec[i][1] - '0' )*16;
145                         } else {
146                                 v += (vec[i][1] - 'a' + 10)*16;
147                         }
148                  case 1:
149                         if (vec[i][0] >= '0' && vec[i][0] <= '9') {
150                                 v += (vec[i][0] - '0' );
151                         } else {
152                                 v += (vec[i][0] - 'a' + 10);
153                         }
154                  case 0:
155                         break;
156                   default:
157                         configuration_error(mc,"bad token %s",s);
158                 }
159
160                 g_string_append_printf(str,":%.2X",v);
161         }
162
163         g_strfreev(vec);
164
165         g_string_erase(str,0,1);
166
167         r = str->str;
168
169         g_string_free(str,FALSE);
170
171         return r;
172 }
173
174 }
175
176 %name MateParser
177
178 %token_prefix TOKEN_
179
180 %token_type { gchar* }
181 %token_destructor { if ($$) g_free($$); }
182
183 %extra_argument { mate_config* mc }
184
185 %syntax_error {
186         configuration_error(mc,"Syntax Error before %s",yyminor);
187 }
188
189 %parse_failure {
190         configuration_error(mc,"Parse Error");
191 }
192
193 %type   transform_decl  { AVPL_Transf* }
194 %type   transform_body { AVPL_Transf* }
195 %type   transform_statements { AVPL_Transf* }
196 %type   transform_statement { AVPL_Transf* }
197 %type   transform_match { transf_match_t* }
198 %type   transform_action { transf_action_t* }
199 %type   match_mode { avpl_match_mode }
200 %type   action_mode { avpl_replace_mode }
201
202 %type gop_name { gchar* }
203 %type time_value { float }
204 %type pdu_name { gchar* }
205 %type gop_tree_mode { gop_tree_mode_t }
206 %type true_false { gboolean }
207
208 %type criteria_statement { pdu_criteria_t* }
209 %type accept_mode { accept_mode_t }
210 %type pdu_drop_unassigned_statement { gboolean }
211 %type discard_pdu_data_statement { gboolean }
212 %type last_extracted_statement { gboolean }
213
214 %type extraction_statement {extraction_t*}
215 %type extraction_statements {extraction_t*}
216
217 %type gop_options { gop_options_t* }
218
219 %type gop_start_statement { AVPL* }
220 %type gop_stop_statement { AVPL* }
221 %type extra_statement { AVPL* }
222 %type gop_drop_unassigned_statement { gboolean }
223 %type show_goptree_statement { gop_tree_mode_t }
224 %type show_times_statement { gboolean }
225 %type gop_expiration_statement { float }
226 %type idle_timeout_statement { float }
227 %type lifetime_statement { float }
228
229 %type gog_statements { gog_statement_t* }
230 %type gog_expiration_statement { float }
231 %type gog_goptree_statement { gop_tree_mode_t }
232 %type gog_key_statements { LoAL* }
233 %type gog_key_statement { AVPL* }
234 %type transform_list_statement { GPtrArray* }
235 %type transform { AVPL_Transf* }
236 %type gop_tree_type { gop_tree_mode_t }
237
238 %type payload_statement { GPtrArray* }
239 %type proto_stack { GPtrArray*  }
240 %type field { header_field_info* }
241 %type transform_list { GPtrArray* }
242 %type avpl { AVPL* }
243 %type avps { AVPL* }
244 %type avp { AVP* }
245 %type value { gchar* }
246 %type avp_oneoff { gchar* }
247
248
249 mate_config ::= decls.
250
251 decls ::= decls decl.
252 decls ::= .
253
254 decl ::= pdu_decl.
255 decl ::= gop_decl.
256 decl ::= gog_decl.
257 decl ::= transform_decl.
258 decl ::= defaults_decl.
259 decl ::= debug_decl.
260 decl ::= DONE_KW SEMICOLON.
261
262 /************* DEBUG
263 */
264
265 debug_decl ::= DEBUG_KW OPEN_BRACE dbgfile_default dbglevel_default pdu_dbglevel_default gop_dbglevel_default gog_dbglevel_default CLOSE_BRACE SEMICOLON.
266
267 dbgfile_default ::= FILENAME_KW QUOTED(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE); }
268 dbgfile_default ::= FILENAME_KW NAME(Filename) SEMICOLON. { mc->dbg_facility = ws_fopen(Filename,"w"); if (mc->dbg_facility == NULL) report_open_failure(Filename,errno,TRUE);  }
269 dbgfile_default ::= .
270
271 dbglevel_default ::= LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_lvl = (int) strtol(LevelString,NULL,10); }
272 dbglevel_default ::= .
273
274 pdu_dbglevel_default ::= PDU_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_pdu_lvl = (int) strtol(LevelString,NULL,10); }
275 pdu_dbglevel_default ::= .
276
277 gop_dbglevel_default ::= GOP_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gop_lvl = (int) strtol(LevelString,NULL,10); }
278 gop_dbglevel_default ::= .
279
280 gog_dbglevel_default ::= GOG_KW LEVEL_KW INTEGER(LevelString) SEMICOLON. { mc->dbg_gog_lvl = (int) strtol(LevelString,NULL,10); }
281 gog_dbglevel_default ::= .
282
283
284 /************* DEFAULTS
285 */
286
287 defaults_decl ::= DEFAULT_KW OPEN_BRACE pdu_defaults gop_defaults gog_defaults CLOSE_BRACE SEMICOLON.
288
289 pdu_defaults ::= PDU_KW OPEN_BRACE pdu_last_extracted_default pdu_drop_unassigned_default pdu_discard_default CLOSE_BRACE SEMICOLON.
290 pdu_defaults ::= .
291
292 pdu_last_extracted_default ::= LAST_EXTRACTED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.last_extracted = Flag; }
293 pdu_last_extracted_default ::= .
294
295 pdu_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.drop_unassigned = Flag; }
296 pdu_drop_unassigned_default ::= .
297
298 pdu_discard_default ::= DISCARD_PDU_DATA_KW true_false(Flag) SEMICOLON. { mc->defaults.pdu.discard = Flag; }
299 pdu_discard_default ::= .
300
301 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.
302 gop_defaults ::= .
303
304 gop_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
305 gop_expiration_default ::= .
306
307 gop_idle_timeout_default ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { mc->defaults.gop.idle_timeout = B; }
308 gop_idle_timeout_default ::= .
309
310 gop_lifetime_default ::= LIFETIME_KW time_value(B) SEMICOLON. { mc->defaults.gop.lifetime = B; }
311 gop_lifetime_default ::= .
312
313 gop_drop_unassigned_default ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { mc->defaults.gop.drop_unassigned = B; }
314 gop_drop_unassigned_default ::= .
315
316 gop_tree_mode_default ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { mc->defaults.gop.pdu_tree_mode = B; }
317 gop_tree_mode_default ::= .
318
319 gop_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gop.show_times = B; }
320 gop_show_times_default ::= .
321
322 gog_defaults ::= GOG_KW OPEN_BRACE gog_expiration_default gop_tree_mode_default gog_goptree_default gog_show_times_default CLOSE_BRACE SEMICOLON.
323 gog_defaults ::= .
324
325 gog_expiration_default ::= EXPIRATION_KW time_value(B) SEMICOLON. { mc->defaults.gop.expiration = B; }
326 gog_expiration_default ::= .
327
328 gog_goptree_default ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { mc->defaults.gog.gop_tree_mode = B; }
329 gog_goptree_default ::= .
330
331 gog_show_times_default ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { mc->defaults.gog.show_times = B; }
332 gog_show_times_default ::= .
333
334
335 /******************************************* TRANSFORM
336 */
337
338 transform_decl(A) ::= TRANSFORM_KW NAME(B) transform_body(C) SEMICOLON. {
339         AVPL_Transf* c;
340
341         if ( g_hash_table_lookup(mc->transfs,B) ) {
342                 configuration_error(mc,"A transformation called '%s' exists already",B);
343         }
344
345         for ( c = C; c; c = c->next )
346                 c->name = g_strdup(B);
347
348         g_hash_table_insert(mc->transfs,C->name,C);
349
350         A = NULL;
351 }
352
353 transform_body(A) ::= OPEN_BRACE transform_statements(B) CLOSE_BRACE. { A = B; }
354
355 transform_statements(A) ::= transform_statements(C) transform_statement(B). {
356     AVPL_Transf* c;
357
358         for ( c = C; c->next; c = c->next ) ;
359         c->next = B;
360         A = C;
361 }
362
363 transform_statements(A) ::= transform_statement(B). { A = B; }
364
365 transform_statement(A) ::= transform_match(Match) transform_action(Action) SEMICOLON. {
366         A = new_transform_elem(Match->avpl,Action->avpl,Match->match_mode,Action->replace_mode);
367 }
368
369 transform_match(A) ::= MATCH_KW  match_mode(Mode) avpl(Avpl). {
370     A = g_malloc(sizeof(transf_match_t));
371     A->match_mode = Mode;
372     A->avpl = Avpl;
373 }
374
375 transform_match(A) ::= . {
376     A = g_malloc(sizeof(transf_match_t));
377     A->match_mode = AVPL_STRICT;
378     A->avpl = new_avpl("");
379
380 }
381
382 transform_action(A) ::= . {
383     A = g_malloc(sizeof(transf_action_t));
384     A->replace_mode = AVPL_INSERT;
385     A->avpl = new_avpl("");
386 }
387 transform_action(A) ::= action_mode(Mode) avpl(Avpl). {
388     A = g_malloc(sizeof(transf_action_t));
389     A->replace_mode = Mode;
390     A->avpl = Avpl;
391 }
392
393 match_mode(A) ::=  . { A = AVPL_STRICT; }
394 match_mode(A) ::=  STRICT_KW. { A = AVPL_STRICT; }
395 match_mode(A) ::=  EVERY_KW. { A = AVPL_EVERY; }
396 match_mode(A) ::=  LOOSE_KW. { A = AVPL_LOOSE; }
397
398 action_mode(A) ::= REPLACE_KW. { A = AVPL_REPLACE; }
399 action_mode(A) ::= INSERT_KW. { A = AVPL_INSERT; }
400 action_mode(A) ::= . { A = AVPL_INSERT; }
401
402 /******************************************* PDU
403 */
404
405 pdu_decl ::=
406     PDU_KW NAME(Name) PROTO_KW field(Field) TRANSPORT_KW proto_stack(Stack)
407         OPEN_BRACE
408             payload_statement(Payload)
409             extraction_statements(Extraction)
410             transform_list_statement(Transform)
411             criteria_statement(Criteria)
412             pdu_drop_unassigned_statement(DropUnassigned)
413             discard_pdu_data_statement(DistcardPduData)
414             last_extracted_statement(LastExtracted)
415         CLOSE_BRACE SEMICOLON.
416 {
417
418         mate_cfg_pdu* cfg  = new_pducfg(Name);
419         extraction_t *extraction, *next_extraction;
420         GPtrArray* transport_stack = g_ptr_array_new();
421         int i;
422
423         if (! cfg ) configuration_error(mc,"could not create Pdu %s.",Name);
424
425         cfg->hfid_proto = Field->id;
426
427         cfg->last_extracted = LastExtracted;
428         cfg->discard = DistcardPduData;
429         cfg->drop_unassigned = DropUnassigned;
430
431         g_string_append_printf(mc->protos_filter,"||%s",Field->abbrev);
432
433         /* flip the transport_stack */
434         for (i = Stack->len - 1; Stack->len; i--) {
435                 g_ptr_array_add(transport_stack,g_ptr_array_remove_index(Stack,i));
436         }
437
438         g_ptr_array_free(Stack,FALSE);
439
440         cfg->transport_ranges = transport_stack;
441         cfg->payload_ranges = Payload;
442
443         if (Criteria) {
444                 cfg->criterium = Criteria->criterium_avpl;
445                 cfg->criterium_match_mode = Criteria->criterium_match_mode;
446                 cfg->criterium_accept_mode = Criteria->criterium_accept_mode;
447         }
448
449         cfg->transforms = Transform;
450
451         for (extraction = Extraction; extraction; extraction = next_extraction) {
452                 next_extraction = extraction->next;
453
454                 if ( ! add_hfid(extraction->hfi, extraction->as, cfg->hfids_attr) ) {
455                         configuration_error(mc,"MATE: failed to create extraction rule '%s'",extraction->as);
456                 }
457
458                 g_free(extraction);
459         }
460 }
461
462 payload_statement(A) ::= . { A = NULL; }
463 payload_statement(A) ::= PAYLOAD_KW proto_stack(B) SEMICOLON. { A = B; }
464
465 criteria_statement(A) ::= . { A = NULL; }
466 criteria_statement(A) ::= CRITERIA_KW accept_mode(B) match_mode(C) avpl(D) SEMICOLON. {
467         A = g_malloc(sizeof(pdu_criteria_t));
468         A->criterium_avpl = D;
469         A->criterium_match_mode = C;
470         A->criterium_accept_mode = B;
471 }
472
473 accept_mode(A) ::= . { A = ACCEPT_MODE; }
474 accept_mode(A) ::= ACCEPT_KW. { A = ACCEPT_MODE; }
475 accept_mode(A) ::= REJECT_KW. { A = REJECT_MODE; }
476
477 extraction_statements(A) ::= extraction_statements(B) extraction_statement(C). { A = B; A->last = A->last->next = C; }
478 extraction_statements(A) ::= extraction_statement(B). { A = B; A->last = A; }
479
480 extraction_statement(A) ::= EXTRACT_KW NAME(NAME) FROM_KW field(FIELD) SEMICOLON. {
481         A = g_malloc(sizeof(extraction_t));
482         A->as = NAME;
483         A->hfi = FIELD;
484         A->next = A->last = NULL;
485 }
486
487
488 pdu_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
489 pdu_drop_unassigned_statement(A) ::= . { A =  mc->defaults.pdu.drop_unassigned; }
490
491 discard_pdu_data_statement(A) ::=  DISCARD_PDU_DATA_KW true_false(B) SEMICOLON. { A = B; }
492 discard_pdu_data_statement(A) ::=  . { A =  mc->defaults.pdu.discard; }
493
494 last_extracted_statement(A) ::= LAST_PDU_KW true_false(B) SEMICOLON. { A = B; }
495 last_extracted_statement(A) ::= . { A = mc->defaults.pdu.last_extracted; }
496
497 proto_stack(A) ::= proto_stack(B) SLASH field(C). {
498         int* hfidp = g_malloc(sizeof(int));
499
500         g_string_append_printf(mc->fields_filter,"||%s",C->abbrev);
501
502         *hfidp = C->id;
503         g_ptr_array_add(B,hfidp);
504         A = B;
505 }
506
507 proto_stack(A) ::= field(B). {
508         int* hfidp = g_malloc(sizeof(int));
509         *hfidp = B->id;
510
511         g_string_append_printf(mc->fields_filter,"||%s",B->abbrev);
512
513         A = g_ptr_array_new();
514         g_ptr_array_add(A,hfidp);
515 }
516
517 field(A) ::= NAME(B). {
518         A = proto_registrar_get_byname(B);
519 }
520
521 /******************************************* GOP
522 */
523
524 gop_decl(A) ::= GOP_KW NAME(Name) ON_KW pdu_name(PduName) MATCH_KW avpl(Key) OPEN_BRACE
525         gop_start_statement(Start)
526         gop_stop_statement(Stop)
527         extra_statement(Extra)
528         transform_list_statement(Transform)
529         gop_expiration_statement(Expiration)
530         idle_timeout_statement(IdleTimeout)
531         lifetime_statement(Lifetime)
532         gop_drop_unassigned_statement(DropUnassigned)
533         show_goptree_statement(TreeMode)
534         show_times_statement(ShowTimes)
535     CLOSE_BRACE SEMICOLON. {
536         mate_cfg_gop* cfg;
537
538         if (g_hash_table_lookup(mc->gopcfgs,Name)) configuration_error(mc,"A Gop Named '%s' exists already.",Name);
539         if (g_hash_table_lookup(mc->gops_by_pduname,PduName) ) configuration_error(mc,"Gop for Pdu '%s' exists already",PduName);
540
541         cfg = new_gopcfg(Name);
542         g_hash_table_insert(mc->gops_by_pduname,PduName,cfg);
543         g_hash_table_insert(mc->gopcfgs,cfg->name,cfg);
544
545         cfg->on_pdu = PduName;
546         cfg->key = Key;
547         cfg->drop_unassigned = DropUnassigned;
548         cfg->show_times = ShowTimes;
549         cfg->pdu_tree_mode = TreeMode;
550         cfg->expiration = Expiration;
551         cfg->idle_timeout = IdleTimeout;
552         cfg->lifetime = Lifetime;
553         cfg->start = Start;
554         cfg->stop = Stop;
555         cfg->transforms = Transform;
556
557         merge_avpl(cfg->extra,Extra,TRUE);
558         delete_avpl(Extra,TRUE);
559     }
560
561 gop_drop_unassigned_statement(A) ::= DROP_UNASSIGNED_KW true_false(B) SEMICOLON. { A = B; }
562 gop_drop_unassigned_statement(A) ::= . { A =  mc->defaults.gop.drop_unassigned; }
563
564 gop_start_statement(A) ::= START_KW avpl(B) SEMICOLON. { A = B; }
565 gop_start_statement(A) ::= . { A = NULL; }
566
567 gop_stop_statement(A) ::= STOP_KW avpl(B) SEMICOLON. { A = B; }
568 gop_stop_statement(A) ::= . { A = NULL; }
569
570 show_goptree_statement(A) ::= SHOW_TREE_KW gop_tree_mode(B) SEMICOLON. { A = B; }
571 show_goptree_statement(A) ::= . { A = mc->defaults.gop.pdu_tree_mode; }
572
573 show_times_statement(A) ::= SHOW_TIMES_KW true_false(B) SEMICOLON. { A = B; }
574 show_times_statement(A) ::= . { A = mc->defaults.gop.show_times; }
575
576 gop_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
577 gop_expiration_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
578
579 idle_timeout_statement(A) ::= IDLE_TIMEOUT_KW time_value(B) SEMICOLON. { A = B; }
580 idle_timeout_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
581
582 lifetime_statement(A) ::= LIFETIME_KW time_value(B) SEMICOLON. { A = B; }
583 lifetime_statement(A) ::= . { A = mc->defaults.gop.lifetime; }
584
585 gop_tree_mode(A) ::= NO_TREE_KW.    { A = GOP_NO_TREE; }
586 gop_tree_mode(A) ::= PDU_TREE_KW.   { A = GOP_PDU_TREE; }
587 gop_tree_mode(A) ::= FRAME_TREE_KW. { A = GOP_FRAME_TREE; }
588 gop_tree_mode(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_PDU_TREE; }
589
590 true_false(A) ::= TRUE_KW. { A = TRUE; }
591 true_false(A) ::= FALSE_KW. { A = FALSE; }
592
593 pdu_name(A) ::= NAME(B). {
594         mate_cfg_pdu* c;
595         if (( c =  g_hash_table_lookup(mc->pducfgs,B) )) {
596                 A = c->name;
597         } else {
598                 configuration_error(mc,"No such Pdu: '%s'",B);
599         }
600 }
601
602
603 time_value(A) ::= FLOATING(B). {
604         A = (float) strtod(B,NULL);
605 }
606
607 time_value(A) ::= INTEGER(B). {
608         A = (float) strtod(B,NULL);
609 }
610
611 /************* GOG
612 */
613
614 gog_decl ::= GOG_KW NAME(Name) OPEN_BRACE
615     gog_key_statements(Keys)
616     extra_statement(Extra)
617     transform_list_statement(Transforms)
618     gog_expiration_statement(Expiration)
619     gog_goptree_statement(Tree)
620     show_times_statement(ShowTimes)
621     CLOSE_BRACE SEMICOLON. {
622         mate_cfg_gog* cfg = NULL;
623
624         if ( g_hash_table_lookup(mc->gogcfgs,Name) ) {
625                 configuration_error(mc,"Gog '%s' exists already ",Name);
626         }
627
628         cfg = new_gogcfg(Name);
629
630         cfg->expiration = Expiration;
631         cfg->gop_tree_mode = Tree;
632         cfg->transforms = Transforms;
633         cfg->keys = Keys;
634         cfg->show_times = ShowTimes;
635
636         merge_avpl(cfg->extra,Extra,TRUE);
637         delete_avpl(Extra,TRUE);
638 }
639
640 gog_goptree_statement(A) ::= GOP_TREE_KW gop_tree_type(B) SEMICOLON. { A = B; }
641 gog_goptree_statement(A) ::= . { A = mc->defaults.gog.gop_tree_mode; }
642
643 gog_expiration_statement(A) ::= EXPIRATION_KW time_value(B) SEMICOLON. { A = B; }
644 gog_expiration_statement(A) ::= . { A = mc->defaults.gog.expiration; }
645
646 gop_tree_type(A) ::= NULL_TREE_KW. { A = GOP_NULL_TREE; }
647 gop_tree_type(A) ::= FULL_TREE_KW. { A = GOP_FULL_TREE; }
648 gop_tree_type(A) ::= BASIC_TREE_KW. { A = GOP_BASIC_TREE; }
649
650 gog_key_statements(A) ::= gog_key_statements(B) gog_key_statement(C). {
651         loal_append(B,C);
652         A = B;
653 }
654
655 gog_key_statements(A) ::= gog_key_statement(B). {
656         A = new_loal("");
657         loal_append(A,B);
658 }
659
660
661 gog_key_statement(A) ::= MEMBER_KW gop_name(B) avpl(C) SEMICOLON. {
662         rename_avpl(C,B);
663         A = C;
664 }
665
666 gop_name(A) ::= NAME(B). {
667         mate_cfg_gop* c;
668         if (( c = g_hash_table_lookup(mc->gopcfgs,B) )) {
669                 A = c->name;
670         } else {
671                 configuration_error(mc,"No Gop called '%s' has been already declared",B);
672         }
673 }
674 /******************************************** GENERAL
675 */
676
677
678 extra_statement(A) ::= EXTRA_KW avpl(B) SEMICOLON. { A = B; }
679 extra_statement(A) ::= . { A = new_avpl(""); }
680
681 transform_list_statement(A) ::= TRANSFORM_KW transform_list(B) SEMICOLON. { A = B; }
682 transform_list_statement(A) ::= . { A = g_ptr_array_new(); }
683
684 transform_list(A) ::= transform_list(B) COMMA transform(C). {
685         A = B;
686         g_ptr_array_add(B,C);
687 }
688
689 transform_list(A) ::= transform(B). {
690         A = g_ptr_array_new();
691         g_ptr_array_add(A,B);
692 }
693
694 transform(A) ::= NAME(B). {
695         AVPL_Transf* t;
696
697         if (( t = g_hash_table_lookup(mc->transfs,B) )) {
698                 A = t;
699         } else {
700                 configuration_error(mc,"There's no such Transformation: %s",B);
701         }
702 }
703
704 avpl(A) ::= OPEN_PARENS avps(B) CLOSE_PARENS. { A = B; }
705 avpl(A) ::= OPEN_PARENS CLOSE_PARENS. { A = new_avpl(""); }
706
707 avps(A) ::= avps(B) COMMA avp(C). { A = B; if ( ! insert_avp(B,C) ) delete_avp(C); }
708 avps(A) ::= avp(B). { A = new_avpl(""); if ( ! insert_avp(A,B) ) delete_avp(B); }
709
710 avp(A) ::= NAME(B) AVP_OPERATOR(C) value(D). { A = new_avp(B,D,*C); }
711 avp(A) ::= NAME(B). { A = new_avp(B,"",'?'); }
712 avp(A) ::= NAME(B) OPEN_BRACE avp_oneoff(C) CLOSE_BRACE. { A = new_avp(B,C,'|'); }
713
714 avp_oneoff(A) ::= avp_oneoff(B) PIPE value(C). { A = g_strdup_printf("%s|%s",B,C); }
715 avp_oneoff(A) ::= value(B). { A = g_strdup(B); }
716
717 value(A) ::= QUOTED(B). { A = g_strdup(B); }
718 value(A) ::= NAME(B). { A = g_strdup(B); }
719 value(A) ::= FLOATING(B). { A = g_strdup(B); }
720 value(A) ::= INTEGER(B). { A = g_strdup(B); }
721 value(A) ::= DOTED_IP(B). { A = g_strdup(B); }
722 value(A) ::= COLONIZED(B). { A = recolonize(mc,B); }
723