1 /*
2  * Copyright (c) 2012 Nagy, Attila <bra@fsn.hu>
3  * Copyright (c) 2014 Balabit
4  * Copyright (c) 2013 Viktor Tusa <tusa@balabit.hu>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published
8  * by the Free Software Foundation, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * As an additional exemption you are allowed to compile & link against the
20  * OpenSSL libraries as published by the OpenSSL project. See the file
21  * COPYING for details.
22  *
23  */
24 
25 %code requires {
26 
27 #include "afstomp-parser.h"
28 
29 }
30 
31 %code {
32 
33 #include "cfg-parser.h"
34 #include "cfg-grammar-internal.h"
35 #include "plugin.h"
36 #include "value-pairs/value-pairs.h"
37 
38 }
39 
40 %define api.prefix {afstomp_}
41 %lex-param {CfgLexer *lexer}
42 %parse-param {CfgLexer *lexer}
43 %parse-param {LogDriver **instance}
44 %parse-param {gpointer arg}
45 
46 
47 
48 %require "3.7.6"
49 %locations
50 %define api.pure
51 %define api.value.type {CFG_STYPE}
52 %define api.location.type {CFG_LTYPE}
53 %define parse.error verbose
54 
55 %code {
56 
57 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
58   do {                                                                  \
59     if (N)                                                              \
60       {                                                                 \
61         (Current).level = YYRHSLOC(Rhs, 1).level;                       \
62         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;          \
63         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;        \
64         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;           \
65         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;         \
66       }                                                                 \
67     else                                                                \
68       {                                                                 \
69         (Current).level = YYRHSLOC(Rhs, 0).level;                       \
70         (Current).first_line   = (Current).last_line   =                \
71           YYRHSLOC (Rhs, 0).last_line;                                  \
72         (Current).first_column = (Current).last_column =                \
73           YYRHSLOC (Rhs, 0).last_column;                                \
74       }                                                                 \
75   } while (0)
76 
77 #define CHECK_ERROR_WITHOUT_MESSAGE(val, token) do {                    \
78     if (!(val))                                                         \
79       {                                                                 \
80         YYERROR;                                                        \
81       }                                                                 \
82   } while (0)
83 
84 #define CHECK_ERROR(val, token, errorfmt, ...) do {                     \
85     if (!(val))                                                         \
86       {                                                                 \
87         if (errorfmt)                                                   \
88           {                                                             \
89             gchar __buf[256];                                           \
90             g_snprintf(__buf, sizeof(__buf), errorfmt, ## __VA_ARGS__); \
91             yyerror(& (token), lexer, NULL, NULL, __buf);               \
92           }                                                             \
93         YYERROR;                                                        \
94       }                                                                 \
95   } while (0)
96 
97 #define CHECK_ERROR_GERROR(val, token, error, errorfmt, ...) do {       \
98     if (!(val))                                                         \
99       {                                                                 \
100         if (errorfmt)                                                   \
101           {                                                             \
102             gchar __buf[256];                                           \
103             g_snprintf(__buf, sizeof(__buf), errorfmt ", error=%s", ## __VA_ARGS__, error->message); \
104             yyerror(& (token), lexer, NULL, NULL, __buf);               \
105           }                                                             \
106         g_clear_error(&error);						\
107         YYERROR;                                                        \
108       }                                                                 \
109   } while (0)
110 
111 #define YYMAXDEPTH 20000
112 
113 
114 }
115 
116 /* plugin types, must be equal to the numerical values of the plugin type in plugin.h */
117 
118 %token LL_CONTEXT_ROOT                1
119 %token LL_CONTEXT_DESTINATION         2
120 %token LL_CONTEXT_SOURCE              3
121 %token LL_CONTEXT_PARSER              4
122 %token LL_CONTEXT_REWRITE             5
123 %token LL_CONTEXT_FILTER              6
124 %token LL_CONTEXT_LOG                 7
125 %token LL_CONTEXT_BLOCK_DEF           8
126 %token LL_CONTEXT_BLOCK_REF           9
127 %token LL_CONTEXT_BLOCK_CONTENT       10
128 %token LL_CONTEXT_BLOCK_ARG           11
129 %token LL_CONTEXT_PRAGMA              12
130 %token LL_CONTEXT_FORMAT              13
131 %token LL_CONTEXT_TEMPLATE_FUNC       14
132 %token LL_CONTEXT_INNER_DEST          15
133 %token LL_CONTEXT_INNER_SRC           16
134 %token LL_CONTEXT_CLIENT_PROTO        17
135 %token LL_CONTEXT_SERVER_PROTO        18
136 %token LL_CONTEXT_OPTIONS             19
137 %token LL_CONTEXT_CONFIG              20
138 
139 /* this is a placeholder for unit tests, must be the latest & largest */
140 %token LL_CONTEXT_MAX                 21
141 
142 
143 /* statements */
144 %token KW_SOURCE                      10000
145 %token KW_FILTER                      10001
146 %token KW_PARSER                      10002
147 %token KW_DESTINATION                 10003
148 %token KW_LOG                         10004
149 %token KW_OPTIONS                     10005
150 %token KW_INCLUDE                     10006
151 %token KW_BLOCK                       10007
152 %token KW_JUNCTION                    10008
153 %token KW_CHANNEL                     10009
154 %token KW_IF                          10010
155 %token KW_ELSE                        10011
156 %token KW_ELIF                        10012
157 
158 /* source & destination items */
159 %token KW_INTERNAL                    10020
160 %token KW_SYSLOG                      10060
161 
162 /* option items */
163 %token KW_MARK_FREQ                   10071
164 %token KW_STATS_FREQ                  10072
165 %token KW_STATS_LEVEL                 10073
166 %token KW_STATS_LIFETIME              10074
167 %token KW_FLUSH_LINES                 10075
168 %token KW_SUPPRESS                    10076
169 %token KW_FLUSH_TIMEOUT               10077
170 %token KW_LOG_MSG_SIZE                10078
171 %token KW_FILE_TEMPLATE               10079
172 %token KW_PROTO_TEMPLATE              10080
173 %token KW_MARK_MODE                   10081
174 %token KW_ENCODING                    10082
175 %token KW_TYPE                        10083
176 %token KW_STATS_MAX_DYNAMIC           10084
177 %token KW_MIN_IW_SIZE_PER_READER      10085
178 %token KW_WORKERS                     10086
179 %token KW_BATCH_LINES                 10087
180 %token KW_BATCH_TIMEOUT               10088
181 %token KW_TRIM_LARGE_MESSAGES         10089
182 
183 %token KW_CHAIN_HOSTNAMES             10090
184 %token KW_NORMALIZE_HOSTNAMES         10091
185 %token KW_KEEP_HOSTNAME               10092
186 %token KW_CHECK_HOSTNAME              10093
187 %token KW_BAD_HOSTNAME                10094
188 
189 %token KW_KEEP_TIMESTAMP              10100
190 
191 %token KW_USE_DNS                     10110
192 %token KW_USE_FQDN                    10111
193 %token KW_CUSTOM_DOMAIN               10112
194 
195 %token KW_DNS_CACHE                   10120
196 %token KW_DNS_CACHE_SIZE              10121
197 
198 %token KW_DNS_CACHE_EXPIRE            10130
199 %token KW_DNS_CACHE_EXPIRE_FAILED     10131
200 %token KW_DNS_CACHE_HOSTS             10132
201 
202 %token KW_PERSIST_ONLY                10140
203 %token KW_USE_RCPTID                  10141
204 %token KW_USE_UNIQID                  10142
205 
206 %token KW_TZ_CONVERT                  10150
207 %token KW_TS_FORMAT                   10151
208 %token KW_FRAC_DIGITS                 10152
209 
210 %token KW_LOG_FIFO_SIZE               10160
211 %token KW_LOG_FETCH_LIMIT             10162
212 %token KW_LOG_IW_SIZE                 10163
213 %token KW_LOG_PREFIX                  10164
214 %token KW_PROGRAM_OVERRIDE            10165
215 %token KW_HOST_OVERRIDE               10166
216 
217 %token KW_THROTTLE                    10170
218 %token KW_THREADED                    10171
219 %token KW_PASS_UNIX_CREDENTIALS       10231
220 
221 %token KW_PERSIST_NAME                10302
222 
223 %token KW_READ_OLD_RECORDS            10304
224 %token KW_USE_SYSLOGNG_PID            10305
225 
226 /* log statement options */
227 %token KW_FLAGS                       10190
228 
229 /* reader options */
230 %token KW_PAD_SIZE                    10200
231 %token KW_TIME_ZONE                   10201
232 %token KW_RECV_TIME_ZONE              10202
233 %token KW_SEND_TIME_ZONE              10203
234 %token KW_LOCAL_TIME_ZONE             10204
235 %token KW_FORMAT                      10205
236 
237 /* destination writer options */
238 %token KW_TRUNCATE_SIZE               10206
239 
240 /* timers */
241 %token KW_TIME_REOPEN                 10210
242 %token KW_TIME_REAP                   10211
243 %token KW_TIME_SLEEP                  10212
244 
245 /* destination options */
246 %token KW_TMPL_ESCAPE                 10220
247 
248 /* driver specific options */
249 %token KW_OPTIONAL                    10230
250 
251 /* file related options */
252 %token KW_CREATE_DIRS                 10240
253 
254 %token KW_OWNER                       10250
255 %token KW_GROUP                       10251
256 %token KW_PERM                        10252
257 
258 %token KW_DIR_OWNER                   10260
259 %token KW_DIR_GROUP                   10261
260 %token KW_DIR_PERM                    10262
261 
262 %token KW_TEMPLATE                    10270
263 %token KW_TEMPLATE_ESCAPE             10271
264 %token KW_TEMPLATE_FUNCTION           10272
265 
266 %token KW_DEFAULT_FACILITY            10300
267 %token KW_DEFAULT_SEVERITY            10301
268 
269 %token KW_PORT                        10323
270 /* misc options */
271 
272 %token KW_USE_TIME_RECVD              10340
273 
274 /* filter items*/
275 %token KW_FACILITY                    10350
276 %token KW_SEVERITY                    10351
277 %token KW_HOST                        10352
278 %token KW_MATCH                       10353
279 %token KW_MESSAGE                     10354
280 %token KW_NETMASK                     10355
281 %token KW_TAGS                        10356
282 %token KW_NETMASK6                    10357
283 
284 /* parser items */
285 
286 /* rewrite items */
287 %token KW_REWRITE                     10370
288 %token KW_CONDITION                   10371
289 %token KW_VALUE                       10372
290 
291 /* yes/no switches */
292 
293 %token KW_YES                         10380
294 %token KW_NO                          10381
295 
296 %token KW_IFDEF                       10410
297 %token KW_ENDIF                       10411
298 
299 %token LL_DOTDOT                      10420
300 %token LL_DOTDOTDOT                   10421
301 %token LL_PRAGMA                      10422
302 %token LL_EOL                         10423
303 %token LL_ERROR                       10424
304 %token LL_ARROW                       10425
305 
306 %token <cptr> LL_IDENTIFIER           10430
307 %token <num>  LL_NUMBER               10431
308 %token <fnum> LL_FLOAT                10432
309 %token <cptr> LL_STRING               10433
310 %token <token> LL_TOKEN               10434
311 %token <cptr> LL_BLOCK                10435
312 
313 %destructor { free($$); } <cptr>
314 
315 /* value pairs */
316 %token KW_VALUE_PAIRS                 10500
317 %token KW_EXCLUDE                     10502
318 %token KW_PAIR                        10503
319 %token KW_KEY                         10504
320 %token KW_SCOPE                       10505
321 %token KW_SHIFT                       10506
322 %token KW_SHIFT_LEVELS                10507
323 %token KW_REKEY                       10508
324 %token KW_ADD_PREFIX                  10509
325 %token KW_REPLACE_PREFIX              10510
326 
327 %token KW_ON_ERROR                    10511
328 
329 %token KW_RETRIES                     10512
330 
331 %token KW_FETCH_NO_DATA_DELAY         10513
332 
333 %type   <ptr> source_content
334 %type	<ptr> source_items
335 %type	<ptr> source_item
336 %type   <ptr> source_afinter
337 %type   <ptr> source_plugin
338 %type   <ptr> source_afinter_params
339 
340 %type   <ptr> dest_content
341 %type	<ptr> dest_items
342 %type	<ptr> dest_item
343 %type   <ptr> dest_plugin
344 
345 %type   <ptr> template_content
346 %type   <ptr> template_content_list
347 
348 %type   <ptr> filter_content
349 
350 %type   <ptr> parser_content
351 
352 %type   <ptr> rewrite_content
353 
354 %type	<ptr> log_items
355 %type	<ptr> log_item
356 
357 %type   <ptr> log_last_junction
358 %type   <ptr> log_junction
359 %type   <ptr> log_content
360 %type   <ptr> log_conditional
361 %type   <ptr> log_if
362 %type   <ptr> log_forks
363 %type   <ptr> log_fork
364 
365 %type	<num> log_flags
366 %type   <num> log_flags_items
367 
368 %type   <ptr> value_pair_option
369 
370 %type	<num> yesno
371 %type   <num> dnsmode
372 %type	<num> dest_writer_options_flags
373 
374 %type	<cptr> string
375 %type	<cptr> string_or_number
376 %type	<cptr> normalized_flag
377 %type   <ptr> string_list
378 %type   <ptr> string_list_build
379 %type   <num> facility_string
380 %type   <num> severity_string
381 
382 %type   <num> positive_integer
383 %type   <num> positive_integer64
384 %type   <num> nonnegative_integer
385 %type   <num> nonnegative_integer64
386 %type   <fnum> positive_float
387 %type   <fnum> nonnegative_float
388 %type	<cptr> path_no_check
389 %type	<cptr> path_secret
390 %type	<cptr> path_check
391 %type	<cptr> path
392 
393 
394 %token KW_STOMP
395 %token KW_STOMP_DESTINATION
396 %token KW_PERSISTENT
397 %token KW_ACK
398 %token KW_BODY
399 %token KW_PASSWORD
400 %token KW_USERNAME
401 
402 %%
403 
404 start
405         : LL_CONTEXT_DESTINATION KW_STOMP
406           {
407             last_driver = *instance = afstomp_dd_new(configuration);
408           }
409           '(' afstomp_options ')'		{ YYACCEPT; }
410           ;
411 
412 afstomp_options
413         : afstomp_option afstomp_options
414         |
415         ;
416 
417 afstomp_option
418         : KW_HOST '(' string ')'		{ afstomp_dd_set_host(last_driver, $3); free($3); }
419         | KW_PORT '(' positive_integer ')'		{ afstomp_dd_set_port(last_driver, $3); }
420         | KW_STOMP_DESTINATION '(' string ')'	{ afstomp_dd_set_destination(last_driver, $3); free($3); }
421         | KW_BODY '(' template_content ')'	{ afstomp_dd_set_body(last_driver, $3); }
422         | KW_PERSISTENT '(' yesno ')'		{ afstomp_dd_set_persistent(last_driver, $3); }
423         | KW_ACK '(' yesno ')'			{ afstomp_dd_set_ack(last_driver, $3); }
424         | KW_USERNAME '(' string ')'		{ afstomp_dd_set_user(last_driver, $3); free($3); }
425         | KW_PASSWORD '(' string ')'		{ afstomp_dd_set_password(last_driver, $3); free($3); }
426         | value_pair_option			{ afstomp_dd_set_value_pairs(last_driver, $1); }
427         | threaded_dest_driver_general_option
428 	| { last_template_options = afstomp_dd_get_template_options(last_driver); } template_option
429         ;
430 
431 
432 source_content
433         :
434           { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); }
435           source_items
436           { cfg_lexer_pop_context(lexer); }
437           {
438             $$ = log_expr_node_new_junction($2, &@$);
439           }
440         ;
441 
442 source_items
443         : source_item semicolons source_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
444         | log_fork semicolons source_items      { $$ = log_expr_node_append_tail($1,  $3); }
445 	|					{ $$ = NULL; }
446 	;
447 
448 source_item
449 	: source_afinter			{ $$ = $1; }
450         | source_plugin                         { $$ = $1; }
451 	;
452 
453 source_plugin
454         : LL_IDENTIFIER
455           {
456             Plugin *p;
457             gint context = LL_CONTEXT_SOURCE;
458 
459             p = cfg_find_plugin(configuration, context, $1);
460             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
461 
462             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
463             free($1);
464             if (!last_driver)
465               {
466                 YYERROR;
467               }
468             $$ = last_driver;
469           }
470         ;
471 
472 source_afinter
473 	: KW_INTERNAL '(' source_afinter_params ')'			{ $$ = $3; }
474 	;
475 
476 source_afinter_params
477         : {
478             last_driver = afinter_sd_new(configuration);
479             last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super;
480           }
481           source_afinter_options { $$ = last_driver; }
482         ;
483 
484 source_afinter_options
485         : source_afinter_option source_afinter_options
486         |
487         ;
488 
489 source_afinter_option
490         : KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; }
491         | source_option
492         ;
493 
494 
495 filter_content
496         : {
497             FilterExprNode *last_filter_expr = NULL;
498 
499 	    CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &last_filter_expr, NULL), @$);
500 
501             $$ = log_expr_node_new_pipe(log_filter_pipe_new(last_filter_expr, configuration), &@$);
502 	  }
503 	;
504 
505 parser_content
506         :
507           {
508             LogExprNode *last_parser_expr = NULL;
509 
510             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$);
511             $$ = last_parser_expr;
512           }
513         ;
514 
515 rewrite_content
516         :
517           {
518             LogExprNode *last_rewrite_expr = NULL;
519 
520             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$);
521             $$ = last_rewrite_expr;
522           }
523         ;
524 
525 dest_content
526          : { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); }
527             dest_items
528            { cfg_lexer_pop_context(lexer); }
529            {
530              $$ = log_expr_node_new_junction($2, &@$);
531            }
532          ;
533 
534 
535 dest_items
536         /* all destination drivers are added as an independent branch in a junction*/
537         : dest_item semicolons dest_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
538         | log_fork semicolons dest_items        { $$ = log_expr_node_append_tail($1,  $3); }
539 	|					{ $$ = NULL; }
540 	;
541 
542 dest_item
543         : dest_plugin                           { $$ = $1; }
544 	;
545 
546 dest_plugin
547         : LL_IDENTIFIER
548           {
549             Plugin *p;
550             gint context = LL_CONTEXT_DESTINATION;
551 
552             p = cfg_find_plugin(configuration, context, $1);
553             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
554 
555             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
556             free($1);
557             if (!last_driver)
558               {
559                 YYERROR;
560               }
561             $$ = last_driver;
562           }
563         ;
564 
565 log_items
566 	: log_item semicolons log_items		{ log_expr_node_append_tail($1, $3); $$ = $1; }
567 	|					{ $$ = NULL; }
568 	;
569 
570 log_item
571         : KW_SOURCE '(' string ')'		{ $$ = log_expr_node_new_source_reference($3, &@$); free($3); }
572         | KW_SOURCE '{' source_content '}'      { $$ = log_expr_node_new_source(NULL, $3, &@$); }
573         | KW_FILTER '(' string ')'		{ $$ = log_expr_node_new_filter_reference($3, &@$); free($3); }
574         | KW_FILTER '{' filter_content '}'      { $$ = log_expr_node_new_filter(NULL, $3, &@$); }
575         | KW_PARSER '(' string ')'              { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); }
576         | KW_PARSER '{' parser_content '}'      { $$ = log_expr_node_new_parser(NULL, $3, &@$); }
577         | KW_REWRITE '(' string ')'             { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); }
578         | KW_REWRITE '{' rewrite_content '}'    { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); }
579         | KW_DESTINATION '(' string ')'		{ $$ = log_expr_node_new_destination_reference($3, &@$); free($3); }
580         | KW_DESTINATION '{' dest_content '}'   { $$ = log_expr_node_new_destination(NULL, $3, &@$); }
581         | log_conditional			{ $$ = $1; }
582         | log_junction                          { $$ = $1; }
583 	;
584 
585 log_junction
586         : KW_JUNCTION '{' log_forks '}'         { $$ = log_expr_node_new_junction($3, &@$); }
587         ;
588 
589 log_last_junction
590 
591         /* this rule matches the last set of embedded log {}
592          * statements at the end of the log {} block.
593          * It is the final junction and was the only form of creating
594          * a processing tree before syslog-ng 3.4.
595          *
596          * We emulate if the user was writing junction {} explicitly.
597          */
598         : log_forks                             { $$ = $1 ? log_expr_node_new_junction($1, &@1) :  NULL; }
599         ;
600 
601 
602 log_forks
603         : log_fork semicolons log_forks		{ log_expr_node_append_tail($1, $3); $$ = $1; }
604         |                                       { $$ = NULL; }
605         ;
606 
607 log_fork
608         : KW_LOG '{' log_content '}'            { $$ = $3; }
609         | KW_CHANNEL '{' log_content '}'        { $$ = $3; }
610         ;
611 
612 log_conditional
613         : log_if				{ $$ = $1; }
614         | log_if KW_ELSE '{' log_content '}'
615           {
616             log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4);
617             $$ = $1;
618           }
619         ;
620 
621 log_if
622         : KW_IF '(' filter_content ')' '{' log_content '}'
623           {
624             $$ = log_expr_node_new_conditional_with_filter($3, $6, &@$);
625           }
626         | KW_IF '{' log_content '}'
627           {
628             $$ = log_expr_node_new_conditional_with_block($3, &@$);
629           }
630         | log_if KW_ELIF '(' filter_content ')' '{' log_content '}'
631           {
632             LogExprNode *false_branch;
633 
634             false_branch = log_expr_node_new_conditional_with_filter($4, $7, &@$);
635             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
636             $$ = $1;
637           }
638         | log_if KW_ELIF '{' log_content '}'
639           {
640             LogExprNode *false_branch;
641 
642             false_branch = log_expr_node_new_conditional_with_block($4, &@$);
643             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
644             $$ = $1;
645           }
646         ;
647 
648 log_content
649         : log_items log_last_junction log_flags                { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); }
650         ;
651 
652 log_flags
653 	: KW_FLAGS '(' log_flags_items ')' semicolons	{ $$ = $3; }
654 	|					{ $$ = 0; }
655 	;
656 
657 log_flags_items
658 	: normalized_flag log_flags_items	{ $$ = log_expr_node_lookup_flag($1) | $2; free($1); }
659 	|					{ $$ = 0; }
660 	;
661 
662 
663 template_content_inner
664         : string
665         {
666           GError *error = NULL;
667 
668           CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template");
669           free($1);
670         }
671         | LL_IDENTIFIER '(' string ')'
672         {
673           GError *error = NULL;
674 
675           CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template");
676           free($3);
677 
678           CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1);
679           free($1);
680         }
681         ;
682 
683 template_content
684         : { last_template = log_template_new(configuration, NULL); } template_content_inner	{ $$ = last_template; }
685         ;
686 
687 template_content_list
688 	: template_content template_content_list { $$ = g_list_prepend($2, $1); }
689 	| { $$ = NULL; }
690 	;
691 
692 
693 
694 string
695 	: LL_IDENTIFIER
696 	| LL_STRING
697 	;
698 
699 yesno
700 	: KW_YES				{ $$ = 1; }
701 	| KW_NO					{ $$ = 0; }
702 	| LL_NUMBER				{ $$ = $1; }
703 	;
704 
705 dnsmode
706 	: yesno					{ $$ = $1; }
707 	| KW_PERSIST_ONLY                       { $$ = 2; }
708 	;
709 
710 nonnegative_integer64
711         : LL_NUMBER
712           {
713             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
714           }
715         ;
716 
717 nonnegative_integer
718         : nonnegative_integer64
719           {
720             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
721           }
722         ;
723 
724 positive_integer64
725         : LL_NUMBER
726           {
727             CHECK_ERROR(($1 > 0), @1, "Must be positive");
728           }
729         ;
730 
731 positive_integer
732         : positive_integer64
733           {
734             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
735           }
736         ;
737 
738 nonnegative_float
739         : LL_FLOAT
740           {
741             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
742           }
743         | nonnegative_integer
744           {
745             $$ = (double) $1;
746           }
747         ;
748 
749 positive_float
750         : LL_FLOAT
751           {
752             CHECK_ERROR(($1 > 0), @1, "Must be positive");
753           }
754         | positive_integer
755           {
756             $$ = (double) $1;
757           }
758         ;
759 
760 string_or_number
761         : string                                { $$ = $1; }
762         | LL_NUMBER                             { $$ = strdup(lexer->token_text->str); }
763         | LL_FLOAT                              { $$ = strdup(lexer->token_text->str); }
764         ;
765 
766 path
767 	: string
768 	  {
769             struct stat buffer;
770             int ret = stat($1, &buffer);
771             CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno));
772             $$ = $1;
773 	  }
774 	;
775 
776 path_check
777     : path { cfg_path_track_file(configuration, $1, "path_check"); }
778     ;
779 
780 path_secret
781     : path { cfg_path_track_file(configuration, $1, "path_secret"); }
782     ;
783 
784 path_no_check
785     : string { cfg_path_track_file(configuration, $1, "path_no_check"); }
786     ;
787 
788 normalized_flag
789         : string                                { $$ = normalize_flag($1); free($1); }
790         ;
791 
792 string_list
793         : string_list_build                     { $$ = $1; }
794         ;
795 
796 string_list_build
797         : string string_list_build		{ $$ = g_list_prepend($2, g_strdup($1)); free($1); }
798         |					{ $$ = NULL; }
799         ;
800 
801 semicolons
802         : ';'
803         | ';' semicolons
804         ;
805 
806 severity_string
807         : string
808 	  {
809 	    /* return the numeric value of the "level" */
810 	    int n = syslog_name_lookup_severity_by_name($1);
811 	    CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1);
812 	    free($1);
813             $$ = n;
814 	  }
815         ;
816 
817 facility_string
818         : string
819           {
820             /* return the numeric value of facility */
821 	    int n = syslog_name_lookup_facility_by_name($1);
822 	    CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1);
823 	    free($1);
824 	    $$ = n;
825 	  }
826         | KW_SYSLOG 				{ $$ = LOG_SYSLOG; }
827         ;
828 
829 parser_opt
830         : KW_TEMPLATE '(' string ')'            {
831                                                   LogTemplate *template;
832                                                   GError *error = NULL;
833 
834                                                   template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
835                                                   CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template");
836                                                   log_parser_set_template(last_parser, template);
837                                                   free($3);
838                                                 }
839         ;
840 
841 driver_option
842         : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); }
843         ;
844 
845 inner_source
846         : LL_IDENTIFIER
847           {
848             Plugin *p;
849             gint context = LL_CONTEXT_INNER_SRC;
850             gpointer value;
851 
852             p = cfg_find_plugin(configuration, context, $1);
853             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
854 
855             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
856 
857             free($1);
858             if (!value)
859               {
860                 YYERROR;
861               }
862             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
863               {
864                 log_driver_plugin_free(value);
865                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
866               }
867           }
868         ;
869 
870 /* All source drivers should incorporate this rule, implies driver_option */
871 source_driver_option
872         : inner_source
873         | driver_option
874         ;
875 
876 inner_dest
877         : LL_IDENTIFIER
878           {
879             Plugin *p;
880             gint context = LL_CONTEXT_INNER_DEST;
881             gpointer value;
882 
883             p = cfg_find_plugin(configuration, context, $1);
884             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
885 
886             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
887 
888             free($1);
889             if (!value)
890               {
891                 YYERROR;
892               }
893             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
894               {
895                 log_driver_plugin_free(value);
896                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
897               }
898           }
899         ;
900 
901 /* implies driver_option */
902 dest_driver_option
903         /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */
904 
905 	: KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((LogDestDriver *) last_driver)->log_fifo_size = $3; }
906 	| KW_THROTTLE '(' nonnegative_integer ')'         { ((LogDestDriver *) last_driver)->throttle = $3; }
907         | inner_dest
908         | driver_option
909         ;
910 
911 threaded_dest_driver_batch_option
912         : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); }
913         | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); }
914         ;
915 
916 threaded_dest_driver_workers_option
917         : KW_WORKERS '(' positive_integer ')'  { log_threaded_dest_driver_set_num_workers(last_driver, $3); }
918         ;
919 
920 /* implies dest_driver_option */
921 threaded_dest_driver_general_option
922 	: KW_RETRIES '(' positive_integer ')'
923         {
924           log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3);
925         }
926         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); }
927         | dest_driver_option
928         ;
929 
930 /* implies source_driver_option and source_option */
931 threaded_source_driver_option
932 	: KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); }
933         | KW_FLAGS '(' threaded_source_driver_option_flags ')'
934         | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option
935         | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option
936         | source_driver_option
937         ;
938 
939 threaded_fetcher_driver_option
940         : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); }
941         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); }
942         ;
943 
944 threaded_source_driver_option_flags
945 	: string threaded_source_driver_option_flags
946         {
947           CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1);
948           free($1);
949         }
950         |
951         ;
952 
953 /* LogSource related options */
954 source_option
955         /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */
956 	: KW_LOG_IW_SIZE '(' positive_integer ')'	{ last_source_options->init_window_size = $3; }
957 	| KW_CHAIN_HOSTNAMES '(' yesno ')'	{ last_source_options->chain_hostnames = $3; }
958 	| KW_KEEP_HOSTNAME '(' yesno ')'	{ last_source_options->keep_hostname = $3; }
959 	| KW_PROGRAM_OVERRIDE '(' string ')'	{ last_source_options->program_override = g_strdup($3); free($3); }
960 	| KW_HOST_OVERRIDE '(' string ')'	{ last_source_options->host_override = g_strdup($3); free($3); }
961 	| KW_LOG_PREFIX '(' string ')'	        { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); }
962 	| KW_KEEP_TIMESTAMP '(' yesno ')'	{ last_source_options->keep_timestamp = $3; }
963 	| KW_READ_OLD_RECORDS '(' yesno ')'	{ last_source_options->read_old_records = $3; }
964 	| KW_USE_SYSLOGNG_PID '(' yesno ')'	{ last_source_options->use_syslogng_pid = $3; }
965         | KW_TAGS '(' string_list ')'		{ log_source_options_set_tags(last_source_options, $3); }
966         | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option
967         ;
968 
969 /* LogReader related options, implies source_option */
970 source_reader_option
971         /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */
972 
973 	: KW_CHECK_HOSTNAME '(' yesno ')'	{ last_reader_options->check_hostname = $3; }
974 	| KW_FLAGS '(' source_reader_option_flags ')'
975 	| KW_LOG_FETCH_LIMIT '(' positive_integer ')'	{ last_reader_options->fetch_limit = $3; }
976         | KW_FORMAT '(' string ')'              { last_reader_options->parse_options.format = g_strdup($3); free($3); }
977         | { last_source_options = &last_reader_options->super; } source_option
978         | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option
979         | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option
980 	;
981 
982 source_reader_option_flags
983         : string source_reader_option_flags     { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); }
984         | KW_CHECK_HOSTNAME source_reader_option_flags     { log_reader_options_process_flag(last_reader_options, "check-hostname"); }
985 	|
986 	;
987 
988 /* LogProtoSource related options */
989 source_proto_option
990         : KW_ENCODING '(' string ')'
991           {
992             CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3),
993                         @3,
994                         "unknown encoding \"%s\"", $3);
995             free($3);
996           }
997         | KW_LOG_MSG_SIZE '(' positive_integer ')'      { last_proto_server_options->max_msg_size = $3; }
998         | KW_TRIM_LARGE_MESSAGES '(' yesno ')'          { last_proto_server_options->trim_large_messages = $3; }
999         ;
1000 
1001 host_resolve_option
1002         : KW_USE_FQDN '(' yesno ')'             { last_host_resolve_options->use_fqdn = $3; }
1003         | KW_USE_DNS '(' dnsmode ')'            { last_host_resolve_options->use_dns = $3; }
1004 	| KW_DNS_CACHE '(' yesno ')' 		{ last_host_resolve_options->use_dns_cache = $3; }
1005 	| KW_NORMALIZE_HOSTNAMES '(' yesno ')'	{ last_host_resolve_options->normalize_hostnames = $3; }
1006 	;
1007 
1008 msg_format_option
1009 	: KW_TIME_ZONE '(' string ')'		{ last_msg_format_options->recv_time_zone = g_strdup($3); free($3); }
1010 	| KW_DEFAULT_SEVERITY '(' severity_string ')'
1011 	  {
1012 	    if (last_msg_format_options->default_pri == 0xFFFF)
1013 	      last_msg_format_options->default_pri = LOG_USER;
1014 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~LOG_PRIMASK) | $3;
1015           }
1016 	| KW_DEFAULT_FACILITY '(' facility_string ')'
1017 	  {
1018 	    if (last_msg_format_options->default_pri == 0xFFFF)
1019 	      last_msg_format_options->default_pri = LOG_NOTICE;
1020 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & LOG_PRIMASK) | $3;
1021           }
1022         ;
1023 
1024 dest_writer_options
1025 	: dest_writer_option dest_writer_options
1026 	|
1027 	;
1028 
1029 dest_writer_option
1030         /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */
1031 
1032 	: KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; }
1033 	| KW_FLUSH_LINES '(' nonnegative_integer ')'		{ last_writer_options->flush_lines = $3; }
1034 	| KW_FLUSH_TIMEOUT '(' positive_integer ')'	{ }
1035         | KW_SUPPRESS '(' nonnegative_integer ')'            { last_writer_options->suppress = $3; }
1036 	| KW_TEMPLATE '(' string ')'       	{
1037                                                   GError *error = NULL;
1038 
1039                                                   last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
1040                                                   CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template");
1041 	                                          free($3);
1042 	                                        }
1043 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ log_writer_options_set_template_escape(last_writer_options, $3); }
1044 	| KW_PAD_SIZE '(' nonnegative_integer ')'         { last_writer_options->padding = $3; }
1045 	| KW_TRUNCATE_SIZE '(' nonnegative_integer ')'         { last_writer_options->truncate_size = $3; }
1046 	| KW_MARK_FREQ '(' nonnegative_integer ')'        { last_writer_options->mark_freq = $3; }
1047         | KW_MARK_MODE '(' KW_INTERNAL ')'      { log_writer_options_set_mark_mode(last_writer_options, "internal"); }
1048 	| KW_MARK_MODE '(' string ')'
1049 	  {
1050 	    CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3);
1051             log_writer_options_set_mark_mode(last_writer_options, $3);
1052             free($3);
1053           }
1054 	| KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; }
1055         | { last_template_options = &last_writer_options->template_options; } template_option
1056 	;
1057 
1058 dest_writer_options_flags
1059 	: normalized_flag dest_writer_options_flags   { $$ = log_writer_options_lookup_flag($1) | $2; free($1); }
1060 	|					      { $$ = 0; }
1061 	;
1062 
1063 file_perm_option
1064 	: KW_OWNER '(' string_or_number ')'	{ file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); }
1065 	| KW_OWNER '(' ')'	                { file_perm_options_dont_change_file_uid(last_file_perm_options); }
1066 	| KW_GROUP '(' string_or_number ')'	{ file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); }
1067 	| KW_GROUP '(' ')'	                { file_perm_options_dont_change_file_gid(last_file_perm_options); }
1068 	| KW_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_file_perm(last_file_perm_options, $3); }
1069 	| KW_PERM '(' ')'		        { file_perm_options_dont_change_file_perm(last_file_perm_options); }
1070         | KW_DIR_OWNER '(' string_or_number ')'	{ file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); }
1071 	| KW_DIR_OWNER '(' ')'	                { file_perm_options_dont_change_dir_uid(last_file_perm_options); }
1072 	| KW_DIR_GROUP '(' string_or_number ')'	{ file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); }
1073 	| KW_DIR_GROUP '(' ')'	                { file_perm_options_dont_change_dir_gid(last_file_perm_options); }
1074 	| KW_DIR_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_dir_perm(last_file_perm_options, $3); }
1075 	| KW_DIR_PERM '(' ')'		        { file_perm_options_dont_change_dir_perm(last_file_perm_options); }
1076         ;
1077 
1078 template_option
1079 	: KW_TS_FORMAT '(' string ')'		{ last_template_options->ts_format = cfg_ts_format_value($3); free($3); }
1080 	| KW_FRAC_DIGITS '(' nonnegative_integer ')'	{ last_template_options->frac_digits = $3; }
1081 	| KW_TIME_ZONE '(' string ')'		{ last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1082 	| KW_SEND_TIME_ZONE '(' string ')'      { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1083 	| KW_LOCAL_TIME_ZONE '(' string ')'     { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); }
1084 	| KW_ON_ERROR '(' string ')'
1085         {
1086           gint on_error;
1087 
1088           CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3);
1089           free($3);
1090 
1091           log_template_options_set_on_error(last_template_options, on_error);
1092         }
1093 	;
1094 
1095 matcher_option
1096         : KW_TYPE '(' string ')'		{ CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); }
1097         | KW_FLAGS '(' matcher_flags ')'
1098         ;
1099 
1100 matcher_flags
1101         : string matcher_flags			{ CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); }
1102         |
1103         ;
1104 
1105 value_pair_option
1106 	: KW_VALUE_PAIRS
1107           {
1108             last_value_pairs = value_pairs_new();
1109           }
1110           '(' vp_options ')'
1111           { $$ = last_value_pairs; }
1112 	;
1113 
1114 vp_options
1115 	: vp_option vp_options
1116 	|
1117 	;
1118 
1119 vp_option
1120         : KW_PAIR '(' string ':' template_content ')'
1121           {
1122             value_pairs_add_pair(last_value_pairs, $3, $5);
1123             free($3);
1124           }
1125         | KW_PAIR '(' string template_content ')'
1126           {
1127             value_pairs_add_pair(last_value_pairs, $3, $4);
1128             free($3);
1129           }
1130         | KW_KEY '(' string KW_REKEY '('
1131           {
1132             last_vp_transset = value_pairs_transform_set_new($3);
1133             value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE);
1134             free($3);
1135           }
1136           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')'
1137 	| KW_KEY '(' string_list ')'		         { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); }
1138         | KW_REKEY '(' string
1139           {
1140             last_vp_transset = value_pairs_transform_set_new($3);
1141             free($3);
1142           }
1143           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); }
1144         | KW_EXCLUDE '(' string_list ')'                 { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); }
1145 	| KW_SCOPE '(' vp_scope_list ')'
1146 	;
1147 
1148 vp_scope_list
1149 	: string vp_scope_list                           { value_pairs_add_scope(last_value_pairs, $1); free($1); }
1150 	|
1151 	;
1152 
1153 vp_rekey_options
1154 	: vp_rekey_option vp_rekey_options
1155         |
1156 	;
1157 
1158 vp_rekey_option
1159 	: KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); }
1160 	| KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); }
1161 	| KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); }
1162 	| KW_REPLACE_PREFIX '(' string string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_replace_prefix($3, $4)); free($3); free($4); }
1163 	;
1164 
1165 rewrite_expr_opt
1166         : KW_VALUE '(' string ')'
1167           {
1168             const gchar *p = $3;
1169             if (p[0] == '$')
1170               {
1171                 msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates",
1172                             evt_tag_str("value", $3),
1173                             cfg_lexer_format_location_tag(lexer, &@3));
1174                 p++;
1175               }
1176             last_rewrite->value_handle = log_msg_get_value_handle(p);
1177             CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p);
1178 	    CHECK_ERROR(log_msg_is_value_name_valid(p), @3, "%s is not a valid name for a name-value pair, perhaps a misspelled .SDATA reference?", p);
1179             free($3);
1180           }
1181         | rewrite_condition_opt
1182         ;
1183 
1184 rewrite_condition_opt
1185         : KW_CONDITION '('
1186           {
1187             FilterExprNode *filter_expr;
1188 
1189             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1);
1190             log_rewrite_set_condition(last_rewrite, filter_expr);
1191           } ')'
1192         ;
1193 
1194 
1195 
1196 %%
1197