npf_parse.y revision 1.20 1 /* $NetBSD: npf_parse.y,v 1.20 2013/03/11 00:09:07 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Martin Husemann and Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 %{
33
34 #include <stdio.h>
35 #include <err.h>
36 #include <vis.h>
37 #include <netdb.h>
38
39 #include "npfctl.h"
40
41 #define YYSTACKSIZE 4096
42
43 int yyparsetarget;
44 const char * yyfilename;
45
46 extern int yylineno, yycolumn;
47 extern int yylex(void);
48
49 /* Variable under construction (bottom up). */
50 static npfvar_t * cvar;
51
52 void
53 yyerror(const char *fmt, ...)
54 {
55 extern int yyleng;
56 extern char *yytext;
57
58 char *msg, *context = estrndup(yytext, yyleng);
59 bool eol = (*context == '\n');
60 va_list ap;
61
62 va_start(ap, fmt);
63 vasprintf(&msg, fmt, ap);
64 va_end(ap);
65
66 fprintf(stderr, "%s:%d:%d: %s", yyfilename,
67 yylineno - (int)eol, yycolumn, msg);
68 if (!eol) {
69 size_t len = strlen(context);
70 char *dst = ecalloc(1, len * 4 + 1);
71
72 strvisx(dst, context, len, VIS_WHITE|VIS_CSTYLE);
73 fprintf(stderr, " near '%s'", dst);
74 }
75 fprintf(stderr, "\n");
76 exit(EXIT_FAILURE);
77 }
78
79 #define CHECK_PARSER_FILE \
80 if (yyparsetarget != NPFCTL_PARSE_FILE) \
81 yyerror("rule must be in the group");
82
83 #define CHECK_PARSER_STRING \
84 if (yyparsetarget != NPFCTL_PARSE_STRING) \
85 yyerror("invalid rule syntax");
86
87 %}
88
89 %token ALL
90 %token ANY
91 %token APPLY
92 %token ARROWBOTH
93 %token ARROWLEFT
94 %token ARROWRIGHT
95 %token BLOCK
96 %token CURLY_CLOSE
97 %token CURLY_OPEN
98 %token CODE
99 %token COLON
100 %token COMMA
101 %token DEFAULT
102 %token TDYNAMIC
103 %token TSTATIC
104 %token EQ
105 %token TFILE
106 %token FLAGS
107 %token FROM
108 %token GROUP
109 %token HASH
110 %token ICMPTYPE
111 %token ID
112 %token IFNET
113 %token IN
114 %token INET
115 %token INET6
116 %token INTERFACE
117 %token MAP
118 %token MINUS
119 %token NAME
120 %token ON
121 %token OUT
122 %token PAR_CLOSE
123 %token PAR_OPEN
124 %token PASS
125 %token PORT
126 %token PROCEDURE
127 %token PROTO
128 %token FAMILY
129 %token FINAL
130 %token FORW
131 %token RETURN
132 %token RETURNICMP
133 %token RETURNRST
134 %token SEPLINE
135 %token SLASH
136 %token STATEFUL
137 %token TABLE
138 %token TCP
139 %token TO
140 %token TREE
141 %token TYPE
142 %token <num> ICMP
143 %token <num> ICMP6
144
145 %token <num> HEX
146 %token <str> IDENTIFIER
147 %token <str> IPV4ADDR
148 %token <str> IPV6ADDR
149 %token <num> NUM
150 %token <fpnum> FPNUM
151 %token <str> STRING
152 %token <str> TABLE_ID
153 %token <str> VAR_ID
154
155 %type <str> addr, some_name, list_elem, table_store, string
156 %type <str> proc_param_val, opt_apply
157 %type <num> ifindex, port, opt_final, on_ifindex
158 %type <num> afamily, opt_family
159 %type <num> block_or_pass, rule_dir, block_opts
160 %type <num> opt_stateful, icmp_type, table_type, map_sd, map_type
161 %type <var> ifnet, addr_or_ifnet, port_range, icmp_type_and_code
162 %type <var> filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
163 %type <var> procs, proc_call, proc_param_list, proc_param
164 %type <addrport> mapseg
165 %type <filtopts> filt_opts, all_or_filt_opts
166 %type <optproto> opt_proto
167 %type <rulegroup> group_attr, group_opt
168
169 %union {
170 char * str;
171 unsigned long num;
172 double fpnum;
173 npfvar_t * var;
174 addr_port_t addrport;
175 filt_opts_t filtopts;
176 opt_proto_t optproto;
177 rule_group_t rulegroup;
178 }
179
180 %%
181
182 input
183 : { CHECK_PARSER_FILE } lines
184 | { CHECK_PARSER_STRING } rule
185 ;
186
187 lines
188 : line SEPLINE lines
189 | line
190 ;
191
192 line
193 : def
194 | table
195 | map
196 | group
197 | rproc
198 |
199 ;
200
201 def
202 : VAR_ID
203 {
204 cvar = npfvar_create($1);
205 npfvar_add(cvar);
206 }
207 EQ definition
208 {
209 cvar = NULL;
210 }
211 ;
212
213 definition
214 : list_elem
215 | listdef
216 ;
217
218 listdef
219 : CURLY_OPEN list_elems CURLY_CLOSE
220 ;
221
222 list_elems
223 : list_elem COMMA list_elems
224 | list_elem
225 ;
226
227 list_elem
228 : IDENTIFIER
229 {
230 npfvar_t *vp = npfvar_create(".identifier");
231 npfvar_add_element(vp, NPFVAR_IDENTIFIER, $1, strlen($1) + 1);
232 npfvar_add_elements(cvar, vp);
233 }
234 | STRING
235 {
236 npfvar_t *vp = npfvar_create(".string");
237 npfvar_add_element(vp, NPFVAR_STRING, $1, strlen($1) + 1);
238 npfvar_add_elements(cvar, vp);
239 }
240 | NUM MINUS NUM
241 {
242 npfvar_t *vp = npfctl_parse_port_range($1, $3);
243 npfvar_add_elements(cvar, vp);
244 }
245 | NUM
246 {
247 npfvar_t *vp = npfvar_create(".num");
248 npfvar_add_element(vp, NPFVAR_NUM, &$1, sizeof($1));
249 npfvar_add_elements(cvar, vp);
250 }
251 | VAR_ID
252 {
253 npfvar_t *vp = npfvar_create(".var_id");
254 npfvar_add_element(vp, NPFVAR_VAR_ID, $1, strlen($1) + 1);
255 npfvar_add_elements(cvar, vp);
256 }
257 | ifnet
258 {
259 npfvar_add_elements(cvar, $1);
260 }
261 | addr_and_mask
262 {
263 npfvar_add_elements(cvar, $1);
264 }
265 ;
266
267 table
268 : TABLE TABLE_ID TYPE table_type table_store
269 {
270 npfctl_build_table($2, $4, $5);
271 }
272 ;
273
274 table_type
275 : HASH { $$ = NPF_TABLE_HASH; }
276 | TREE { $$ = NPF_TABLE_TREE; }
277 ;
278
279 table_store
280 : TDYNAMIC { $$ = NULL; }
281 | TFILE STRING { $$ = $2; }
282 ;
283
284 map_sd
285 : TSTATIC { $$ = NPFCTL_NAT_STATIC; }
286 | TDYNAMIC { $$ = NPFCTL_NAT_DYNAMIC; }
287 | { $$ = NPFCTL_NAT_DYNAMIC; }
288 ;
289
290 map_type
291 : ARROWBOTH { $$ = NPF_NATIN | NPF_NATOUT; }
292 | ARROWLEFT { $$ = NPF_NATIN; }
293 | ARROWRIGHT { $$ = NPF_NATOUT; }
294 ;
295
296 mapseg
297 : addr_or_ifnet port_range
298 {
299 $$.ap_netaddr = $1;
300 $$.ap_portrange = $2;
301 }
302 ;
303
304 map
305 : MAP ifindex map_sd mapseg map_type mapseg PASS filt_opts
306 {
307 npfctl_build_natseg($3, $5, $2, &$4, &$6, &$8);
308 }
309 | MAP ifindex map_sd mapseg map_type mapseg
310 {
311 npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
312 }
313 ;
314
315 rproc
316 : PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
317 {
318 npfctl_build_rproc($2, $4);
319 }
320 ;
321
322 procs
323 : proc_call SEPLINE procs
324 {
325 $$ = npfvar_add_elements($1, $3);
326 }
327 | proc_call { $$ = $1; }
328 ;
329
330 proc_call
331 : IDENTIFIER COLON proc_param_list
332 {
333 proc_call_t pc;
334
335 pc.pc_name = estrdup($1);
336 pc.pc_opts = $3;
337 $$ = npfvar_create(".proc_call");
338 npfvar_add_element($$, NPFVAR_PROC, &pc, sizeof(pc));
339 }
340 | { $$ = NULL; }
341 ;
342
343 proc_param_list
344 : proc_param COMMA proc_param_list
345 {
346 $$ = npfvar_add_elements($1, $3);
347 }
348 | proc_param { $$ = $1; }
349 | { $$ = NULL; }
350 ;
351
352 proc_param
353 /* Key and value pair. */
354 : some_name proc_param_val
355 {
356 proc_param_t pp;
357
358 pp.pp_param = estrdup($1);
359 pp.pp_value = $2 ? estrdup($2) : NULL;
360 $$ = npfvar_create(".proc_param");
361 npfvar_add_element($$, NPFVAR_PROC_PARAM, &pp, sizeof(pp));
362 }
363 ;
364
365 proc_param_val
366 : some_name { $$ = $1; }
367 | NUM { (void)asprintf(&$$, "%ld", $1); }
368 | FPNUM { (void)asprintf(&$$, "%lf", $1); }
369 | { $$ = NULL; }
370 ;
371
372 group
373 : GROUP PAR_OPEN group_attr PAR_CLOSE
374 {
375 /* Build a group. Increases the nesting level. */
376 npfctl_build_group($3.rg_name, $3.rg_attr,
377 $3.rg_ifnum, $3.rg_default);
378 }
379 ruleset_block
380 {
381 /* Decrease the nesting level. */
382 npfctl_build_group_end();
383 }
384 ;
385
386 group_attr
387 : group_opt COMMA group_attr
388 {
389 $$ = $3;
390
391 if (($1.rg_name && $$.rg_name) ||
392 ($1.rg_ifnum && $$.rg_ifnum) ||
393 ($1.rg_attr & $$.rg_attr) != 0)
394 yyerror("duplicate group option");
395
396 if ($1.rg_name) {
397 $$.rg_name = $1.rg_name;
398 }
399 if ($1.rg_attr) {
400 $$.rg_attr |= $1.rg_attr;
401 }
402 if ($1.rg_ifnum) {
403 $$.rg_ifnum = $1.rg_ifnum;
404 }
405 if ($1.rg_default) {
406 $$.rg_default = $1.rg_default;
407 }
408 }
409 | group_opt { $$ = $1; }
410 ;
411
412 group_opt
413 : DEFAULT
414 {
415 memset(&$$, 0, sizeof(rule_group_t));
416 $$.rg_default = true;
417 }
418 | NAME STRING
419 {
420 memset(&$$, 0, sizeof(rule_group_t));
421 $$.rg_name = $2;
422 }
423 | INTERFACE ifindex
424 {
425 memset(&$$, 0, sizeof(rule_group_t));
426 $$.rg_ifnum = $2;
427 }
428 | TDYNAMIC
429 {
430 memset(&$$, 0, sizeof(rule_group_t));
431 $$.rg_attr = NPF_RULE_DYNAMIC;
432 }
433 | FORW
434 {
435 memset(&$$, 0, sizeof(rule_group_t));
436 $$.rg_attr = NPF_RULE_FORW;
437 }
438 | rule_dir
439 {
440 memset(&$$, 0, sizeof(rule_group_t));
441 $$.rg_attr = $1;
442 }
443 ;
444
445 ruleset_block
446 : CURLY_OPEN ruleset CURLY_CLOSE
447 | /* Empty (for a dynamic ruleset). */
448 ;
449
450 ruleset
451 : rule_group SEPLINE ruleset
452 | rule_group
453 ;
454
455 rule_group
456 : rule
457 | group
458 |
459
460 rule
461 : block_or_pass opt_stateful rule_dir opt_final on_ifindex
462 opt_family opt_proto all_or_filt_opts opt_apply
463 {
464 npfctl_build_rule($1 | $2 | $3 | $4, $5,
465 $6, &$7, &$8, $9);
466 }
467 ;
468
469 block_or_pass
470 : BLOCK block_opts { $$ = $2; }
471 | PASS { $$ = NPF_RULE_PASS; }
472 ;
473
474 rule_dir
475 : IN { $$ = NPF_RULE_IN; }
476 | OUT { $$ = NPF_RULE_OUT; }
477 | { $$ = NPF_RULE_IN | NPF_RULE_OUT; }
478 ;
479
480 opt_final
481 : FINAL { $$ = NPF_RULE_FINAL; }
482 | { $$ = 0; }
483 ;
484
485 on_ifindex
486 : ON ifindex { $$ = $2; }
487 | { $$ = 0; }
488 ;
489
490 afamily
491 : INET { $$ = AF_INET; }
492 | INET6 { $$ = AF_INET6; }
493 ;
494
495 opt_family
496 : FAMILY afamily { $$ = $2; }
497 | { $$ = AF_UNSPEC; }
498 ;
499
500 opt_proto
501 : PROTO TCP tcp_flags_and_mask
502 {
503 $$.op_proto = IPPROTO_TCP;
504 $$.op_opts = $3;
505 }
506 | PROTO ICMP icmp_type_and_code
507 {
508 $$.op_proto = IPPROTO_ICMP;
509 $$.op_opts = $3;
510 }
511 | PROTO ICMP6 icmp_type_and_code
512 {
513 $$.op_proto = IPPROTO_ICMPV6;
514 $$.op_opts = $3;
515 }
516 | PROTO some_name
517 {
518 $$.op_proto = npfctl_protono($2);
519 $$.op_opts = NULL;
520 }
521 | PROTO NUM
522 {
523 $$.op_proto = $2;
524 $$.op_opts = NULL;
525 }
526 |
527 {
528 $$.op_proto = -1;
529 $$.op_opts = NULL;
530 }
531 ;
532
533 all_or_filt_opts
534 : ALL
535 {
536 $$.fo_from.ap_netaddr = NULL;
537 $$.fo_from.ap_portrange = NULL;
538 $$.fo_to.ap_netaddr = NULL;
539 $$.fo_to.ap_portrange = NULL;
540 }
541 | filt_opts { $$ = $1; }
542 ;
543
544 opt_stateful
545 : STATEFUL { $$ = NPF_RULE_STATEFUL; }
546 | { $$ = 0; }
547 ;
548
549 opt_apply
550 : APPLY STRING { $$ = $2; }
551 | { $$ = NULL; }
552 ;
553
554 block_opts
555 : RETURNRST { $$ = NPF_RULE_RETRST; }
556 | RETURNICMP { $$ = NPF_RULE_RETICMP; }
557 | RETURN { $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
558 | { $$ = 0; }
559 ;
560
561 filt_opts
562 : FROM filt_addr port_range TO filt_addr port_range
563 {
564 $$.fo_from.ap_netaddr = $2;
565 $$.fo_from.ap_portrange = $3;
566 $$.fo_to.ap_netaddr = $5;
567 $$.fo_to.ap_portrange = $6;
568 }
569 | FROM filt_addr port_range
570 {
571 $$.fo_from.ap_netaddr = $2;
572 $$.fo_from.ap_portrange = $3;
573 $$.fo_to.ap_netaddr = NULL;
574 $$.fo_to.ap_portrange = NULL;
575 }
576 | TO filt_addr port_range
577 {
578 $$.fo_from.ap_netaddr = NULL;
579 $$.fo_from.ap_portrange = NULL;
580 $$.fo_to.ap_netaddr = $2;
581 $$.fo_to.ap_portrange = $3;
582 }
583 ;
584
585 filt_addr
586 : addr_or_ifnet { $$ = $1; }
587 | TABLE_ID { $$ = npfctl_parse_table_id($1); }
588 | ANY { $$ = NULL; }
589 ;
590
591 addr_and_mask
592 : addr SLASH NUM
593 {
594 $$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
595 }
596 | addr SLASH HEX
597 {
598 $$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
599 }
600 | addr SLASH addr
601 {
602 $$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
603 }
604 | addr
605 {
606 $$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
607 }
608 ;
609
610 addr_or_ifnet
611 : addr_and_mask
612 {
613 assert($1 != NULL);
614 $$ = $1;
615 }
616 | ifnet
617 {
618 ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
619 $$ = ifna->ifna_addrs;
620 }
621 | VAR_ID
622 {
623 npfvar_t *vp = npfvar_lookup($1);
624 int type = npfvar_get_type(vp, 0);
625 ifnet_addr_t *ifna;
626
627 again:
628 switch (type) {
629 case NPFVAR_IDENTIFIER:
630 case NPFVAR_STRING:
631 vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
632 AF_UNSPEC);
633 type = npfvar_get_type(vp, 0);
634 goto again;
635 case NPFVAR_FAM:
636 $$ = vp;
637 break;
638 case NPFVAR_INTERFACE:
639 ifna = npfvar_get_data(vp, type, 0);
640 $$ = ifna->ifna_addrs;
641 break;
642 case -1:
643 yyerror("undefined variable '%s'", $1);
644 break;
645 default:
646 yyerror("wrong variable '%s' type '%s' for address "
647 "or interface", $1, npfvar_type(type));
648 break;
649 }
650 }
651 ;
652
653 addr
654 : IPV4ADDR { $$ = $1; }
655 | IPV6ADDR { $$ = $1; }
656 ;
657
658 port_range
659 : PORT port /* just port */
660 {
661 $$ = npfctl_parse_port_range($2, $2);
662 }
663 | PORT port MINUS port /* port from-to */
664 {
665 $$ = npfctl_parse_port_range($2, $4);
666 }
667 | PORT VAR_ID
668 {
669 $$ = npfctl_parse_port_range_variable($2);
670 }
671 |
672 {
673 $$ = NULL;
674 }
675 ;
676
677 port
678 : NUM { $$ = $1; }
679 | IDENTIFIER { $$ = npfctl_portno($1); }
680 | STRING { $$ = npfctl_portno($1); }
681 ;
682
683 icmp_type_and_code
684 : ICMPTYPE icmp_type
685 {
686 $$ = npfctl_parse_icmp($<num>0, $2, -1);
687 }
688 | ICMPTYPE icmp_type CODE NUM
689 {
690 $$ = npfctl_parse_icmp($<num>0, $2, $4);
691 }
692 | ICMPTYPE icmp_type CODE IDENTIFIER
693 {
694 $$ = npfctl_parse_icmp($<num>0, $2,
695 npfctl_icmpcode($<num>0, $2, $4));
696 }
697 | ICMPTYPE icmp_type CODE VAR_ID
698 {
699 char *s = npfvar_expand_string(npfvar_lookup($4));
700 $$ = npfctl_parse_icmp($<num>0, $2,
701 npfctl_icmpcode($<num>0, $2, s));
702 }
703 |
704 {
705 $$ = npfctl_parse_icmp($<num>0, -1, -1);
706 }
707 ;
708
709 tcp_flags_and_mask
710 : FLAGS tcp_flags SLASH tcp_flags
711 {
712 npfvar_add_elements($2, $4);
713 $$ = $2;
714 }
715 | FLAGS tcp_flags
716 {
717 char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
718 npfvar_add_elements($2, npfctl_parse_tcpflag(s));
719 $$ = $2;
720 }
721 | { $$ = NULL; }
722 ;
723
724 tcp_flags
725 : IDENTIFIER { $$ = npfctl_parse_tcpflag($1); }
726 ;
727
728 icmp_type
729 : NUM { $$ = $1; }
730 | IDENTIFIER { $$ = npfctl_icmptype($<num>-1, $1); }
731 | VAR_ID
732 {
733 char *s = npfvar_expand_string(npfvar_lookup($1));
734 $$ = npfctl_icmptype($<num>-1, s);
735 }
736 ;
737
738 string
739 : IDENTIFIER
740 {
741 $$ = $1;
742 }
743 | VAR_ID
744 {
745 npfvar_t *vp = npfvar_lookup($1);
746 const int type = npfvar_get_type(vp, 0);
747
748 switch (type) {
749 case NPFVAR_STRING:
750 case NPFVAR_IDENTIFIER:
751 $$ = npfvar_expand_string(vp);
752 break;
753 case -1:
754 yyerror("undefined variable '%s' for interface", $1);
755 break;
756 default:
757 yyerror("wrong variable '%s' type '%s' for string",
758 $1, npfvar_type(type));
759 break;
760 }
761 }
762 ;
763
764 ifnet
765 : IFNET PAR_OPEN string PAR_CLOSE
766 {
767 $$ = npfctl_parse_ifnet($3, AF_UNSPEC);
768 }
769 | afamily PAR_OPEN string PAR_CLOSE
770 {
771 $$ = npfctl_parse_ifnet($3, $1);
772 }
773 ;
774
775 ifindex
776 : some_name
777 {
778 $$ = npfctl_find_ifindex($1);
779 }
780 | ifnet
781 {
782 ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
783 $$ = ifna->ifna_index;
784 }
785 | VAR_ID
786 {
787 npfvar_t *vp = npfvar_lookup($1);
788 const int type = npfvar_get_type(vp, 0);
789 ifnet_addr_t *ifna;
790
791 switch (type) {
792 case NPFVAR_STRING:
793 case NPFVAR_IDENTIFIER:
794 $$ = npfctl_find_ifindex(npfvar_expand_string(vp));
795 break;
796 case NPFVAR_INTERFACE:
797 ifna = npfvar_get_data(vp, type, 0);
798 $$ = ifna->ifna_index;
799 break;
800 case -1:
801 yyerror("undefined variable '%s' for interface", $1);
802 break;
803 default:
804 yyerror("wrong variable '%s' type '%s' for interface",
805 $1, npfvar_type(type));
806 break;
807 }
808 }
809 ;
810
811 some_name
812 : IDENTIFIER { $$ = $1; }
813 | STRING { $$ = $1; }
814 ;
815
816 %%
817