npf_parse.y revision 1.28 1 /* $NetBSD: npf_parse.y,v 1.28 2013/11/18 21:39:03 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2011-2013 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, Christos Zoulas and Mindaugas Rasiukevicius.
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 ALG
90 %token ALL
91 %token ANY
92 %token APPLY
93 %token ARROWBOTH
94 %token ARROWLEFT
95 %token ARROWRIGHT
96 %token BLOCK
97 %token CURLY_CLOSE
98 %token CURLY_OPEN
99 %token CODE
100 %token COLON
101 %token COMMA
102 %token DEFAULT
103 %token TDYNAMIC
104 %token TSTATIC
105 %token EQ
106 %token TFILE
107 %token FLAGS
108 %token FROM
109 %token GROUP
110 %token HASH
111 %token ICMPTYPE
112 %token ID
113 %token IFNET
114 %token IN
115 %token INET
116 %token INET6
117 %token INTERFACE
118 %token MAP
119 %token MINUS
120 %token NAME
121 %token ON
122 %token OUT
123 %token PAR_CLOSE
124 %token PAR_OPEN
125 %token PASS
126 %token PCAP_FILTER
127 %token PORT
128 %token PROCEDURE
129 %token PROTO
130 %token FAMILY
131 %token FINAL
132 %token FORW
133 %token RETURN
134 %token RETURNICMP
135 %token RETURNRST
136 %token RULESET
137 %token SEPLINE
138 %token SLASH
139 %token STATEFUL
140 %token TABLE
141 %token TCP
142 %token TO
143 %token TREE
144 %token TYPE
145 %token <num> ICMP
146 %token <num> ICMP6
147
148 %token <num> HEX
149 %token <str> IDENTIFIER
150 %token <str> IPV4ADDR
151 %token <str> IPV6ADDR
152 %token <num> NUM
153 %token <fpnum> FPNUM
154 %token <str> STRING
155 %token <str> TABLE_ID
156 %token <str> VAR_ID
157
158 %type <str> addr, some_name, element, table_store, string
159 %type <str> proc_param_val, opt_apply, ifname, on_ifname
160 %type <num> port, opt_final, number, afamily, opt_family
161 %type <num> block_or_pass, rule_dir, group_dir, block_opts
162 %type <num> opt_stateful, icmp_type, table_type, map_sd, map_type
163 %type <var> ifnet, addr_or_ifnet, port_range, icmp_type_and_code
164 %type <var> filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
165 %type <var> procs, proc_call, proc_param_list, proc_param
166 %type <addrport> mapseg
167 %type <filtopts> filt_opts, all_or_filt_opts
168 %type <optproto> opt_proto
169 %type <rulegroup> group_opts
170
171 %union {
172 char * str;
173 unsigned long num;
174 double fpnum;
175 npfvar_t * var;
176 addr_port_t addrport;
177 filt_opts_t filtopts;
178 opt_proto_t optproto;
179 rule_group_t rulegroup;
180 }
181
182 %%
183
184 input
185 : { CHECK_PARSER_FILE } lines
186 | { CHECK_PARSER_STRING } rule
187 ;
188
189 lines
190 : line SEPLINE lines
191 | line
192 ;
193
194 line
195 : vardef
196 | table
197 | map
198 | group
199 | rproc
200 | alg
201 |
202 ;
203
204 alg
205 : ALG STRING
206 {
207 npfctl_build_alg($2);
208 }
209 ;
210
211 /*
212 * A value - an element or a list of elements.
213 * Can be assigned to a variable or used inline.
214 */
215
216 vardef
217 : VAR_ID
218 {
219 cvar = npfvar_create($1);
220 npfvar_add(cvar);
221 }
222 EQ value
223 {
224 cvar = NULL;
225 }
226 ;
227
228 value
229 : element
230 | list
231 ;
232
233 list
234 : CURLY_OPEN list_elems CURLY_CLOSE
235 ;
236
237 list_elems
238 : element COMMA list_elems
239 | element
240 ;
241
242 element
243 : IDENTIFIER
244 {
245 npfvar_t *vp = npfvar_create(".identifier");
246 npfvar_add_element(vp, NPFVAR_IDENTIFIER, $1, strlen($1) + 1);
247 npfvar_add_elements(cvar, vp);
248 }
249 | STRING
250 {
251 npfvar_t *vp = npfvar_create(".string");
252 npfvar_add_element(vp, NPFVAR_STRING, $1, strlen($1) + 1);
253 npfvar_add_elements(cvar, vp);
254 }
255 | number MINUS number
256 {
257 npfvar_t *vp = npfctl_parse_port_range($1, $3);
258 npfvar_add_elements(cvar, vp);
259 }
260 | number
261 {
262 npfvar_t *vp = npfvar_create(".num");
263 npfvar_add_element(vp, NPFVAR_NUM, &$1, sizeof($1));
264 npfvar_add_elements(cvar, vp);
265 }
266 | VAR_ID
267 {
268 npfvar_t *vp = npfvar_create(".var_id");
269 npfvar_add_element(vp, NPFVAR_VAR_ID, $1, strlen($1) + 1);
270 npfvar_add_elements(cvar, vp);
271 }
272 | ifnet
273 {
274 npfvar_add_elements(cvar, $1);
275 }
276 | addr_and_mask
277 {
278 npfvar_add_elements(cvar, $1);
279 }
280 ;
281
282 /*
283 * Table definition.
284 */
285
286 table
287 : TABLE TABLE_ID TYPE table_type table_store
288 {
289 npfctl_build_table($2, $4, $5);
290 }
291 ;
292
293 table_type
294 : HASH { $$ = NPF_TABLE_HASH; }
295 | TREE { $$ = NPF_TABLE_TREE; }
296 ;
297
298 table_store
299 : TDYNAMIC { $$ = NULL; }
300 | TFILE STRING { $$ = $2; }
301 ;
302
303 /*
304 * Map definition.
305 */
306
307 map_sd
308 : TSTATIC { $$ = NPFCTL_NAT_STATIC; }
309 | TDYNAMIC { $$ = NPFCTL_NAT_DYNAMIC; }
310 | { $$ = NPFCTL_NAT_DYNAMIC; }
311 ;
312
313 map_type
314 : ARROWBOTH { $$ = NPF_NATIN | NPF_NATOUT; }
315 | ARROWLEFT { $$ = NPF_NATIN; }
316 | ARROWRIGHT { $$ = NPF_NATOUT; }
317 ;
318
319 mapseg
320 : addr_or_ifnet port_range
321 {
322 $$.ap_netaddr = $1;
323 $$.ap_portrange = $2;
324 }
325 ;
326
327 map
328 : MAP ifname map_sd mapseg map_type mapseg PASS filt_opts
329 {
330 npfctl_build_natseg($3, $5, $2, &$4, &$6, &$8);
331 }
332 | MAP ifname map_sd mapseg map_type mapseg
333 {
334 npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
335 }
336 | MAP RULESET group_opts
337 {
338 npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifname);
339 }
340 ;
341
342 /*
343 * Rule procedure definition and its parameters.
344 */
345
346 rproc
347 : PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
348 {
349 npfctl_build_rproc($2, $4);
350 }
351 ;
352
353 procs
354 : proc_call SEPLINE procs
355 {
356 $$ = npfvar_add_elements($1, $3);
357 }
358 | proc_call { $$ = $1; }
359 ;
360
361 proc_call
362 : IDENTIFIER COLON proc_param_list
363 {
364 proc_call_t pc;
365
366 pc.pc_name = estrdup($1);
367 pc.pc_opts = $3;
368 $$ = npfvar_create(".proc_call");
369 npfvar_add_element($$, NPFVAR_PROC, &pc, sizeof(pc));
370 }
371 | { $$ = NULL; }
372 ;
373
374 proc_param_list
375 : proc_param COMMA proc_param_list
376 {
377 $$ = npfvar_add_elements($1, $3);
378 }
379 | proc_param { $$ = $1; }
380 | { $$ = NULL; }
381 ;
382
383 proc_param
384 /* Key and value pair. */
385 : some_name proc_param_val
386 {
387 proc_param_t pp;
388
389 pp.pp_param = estrdup($1);
390 pp.pp_value = $2 ? estrdup($2) : NULL;
391 $$ = npfvar_create(".proc_param");
392 npfvar_add_element($$, NPFVAR_PROC_PARAM, &pp, sizeof(pp));
393 }
394 ;
395
396 proc_param_val
397 : some_name { $$ = $1; }
398 | number { (void)asprintf(&$$, "%ld", $1); }
399 | FPNUM { (void)asprintf(&$$, "%lf", $1); }
400 | { $$ = NULL; }
401 ;
402
403 /*
404 * Group and dynamic ruleset definition.
405 */
406
407 group
408 : GROUP group_opts
409 {
410 /* Build a group. Increases the nesting level. */
411 npfctl_build_group($2.rg_name, $2.rg_attr,
412 $2.rg_ifname, $2.rg_default);
413 }
414 ruleset_block
415 {
416 /* Decrease the nesting level. */
417 npfctl_build_group_end();
418 }
419 ;
420
421 ruleset
422 : RULESET group_opts
423 {
424 /* Ruleset is a dynamic group. */
425 npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
426 $2.rg_ifname, $2.rg_default);
427 npfctl_build_group_end();
428 }
429 ;
430
431 group_dir
432 : FORW { $$ = NPF_RULE_FORW; }
433 | rule_dir
434 ;
435
436 group_opts
437 : DEFAULT
438 {
439 memset(&$$, 0, sizeof(rule_group_t));
440 $$.rg_default = true;
441 }
442 | STRING group_dir on_ifname
443 {
444 memset(&$$, 0, sizeof(rule_group_t));
445 $$.rg_name = $1;
446 $$.rg_attr = $2;
447 $$.rg_ifname = $3;
448 }
449 ;
450
451 ruleset_block
452 : CURLY_OPEN ruleset_def CURLY_CLOSE
453 ;
454
455 ruleset_def
456 : rule_group SEPLINE ruleset_def
457 | rule_group
458 ;
459
460 rule_group
461 : rule
462 | group
463 | ruleset
464 |
465 ;
466
467 /*
468 * Rule and misc.
469 */
470
471 rule
472 : block_or_pass opt_stateful rule_dir opt_final on_ifname
473 opt_family opt_proto all_or_filt_opts opt_apply
474 {
475 npfctl_build_rule($1 | $2 | $3 | $4, $5,
476 $6, &$7, &$8, NULL, $9);
477 }
478 | block_or_pass opt_stateful rule_dir opt_final on_ifname
479 PCAP_FILTER STRING opt_apply
480 {
481 npfctl_build_rule($1 | $2 | $3 | $4, $5,
482 AF_UNSPEC, NULL, NULL, $7, $8);
483 }
484 ;
485
486 block_or_pass
487 : BLOCK block_opts { $$ = $2; }
488 | PASS { $$ = NPF_RULE_PASS; }
489 ;
490
491 rule_dir
492 : IN { $$ = NPF_RULE_IN; }
493 | OUT { $$ = NPF_RULE_OUT; }
494 | { $$ = NPF_RULE_IN | NPF_RULE_OUT; }
495 ;
496
497 opt_final
498 : FINAL { $$ = NPF_RULE_FINAL; }
499 | { $$ = 0; }
500 ;
501
502 on_ifname
503 : ON ifname { $$ = $2; }
504 | { $$ = NULL; }
505 ;
506
507 afamily
508 : INET { $$ = AF_INET; }
509 | INET6 { $$ = AF_INET6; }
510 ;
511
512 opt_family
513 : FAMILY afamily { $$ = $2; }
514 | { $$ = AF_UNSPEC; }
515 ;
516
517 opt_proto
518 : PROTO TCP tcp_flags_and_mask
519 {
520 $$.op_proto = IPPROTO_TCP;
521 $$.op_opts = $3;
522 }
523 | PROTO ICMP icmp_type_and_code
524 {
525 $$.op_proto = IPPROTO_ICMP;
526 $$.op_opts = $3;
527 }
528 | PROTO ICMP6 icmp_type_and_code
529 {
530 $$.op_proto = IPPROTO_ICMPV6;
531 $$.op_opts = $3;
532 }
533 | PROTO some_name
534 {
535 $$.op_proto = npfctl_protono($2);
536 $$.op_opts = NULL;
537 }
538 | PROTO number
539 {
540 $$.op_proto = $2;
541 $$.op_opts = NULL;
542 }
543 |
544 {
545 $$.op_proto = -1;
546 $$.op_opts = NULL;
547 }
548 ;
549
550 all_or_filt_opts
551 : ALL
552 {
553 $$.fo_from.ap_netaddr = NULL;
554 $$.fo_from.ap_portrange = NULL;
555 $$.fo_to.ap_netaddr = NULL;
556 $$.fo_to.ap_portrange = NULL;
557 }
558 | filt_opts { $$ = $1; }
559 ;
560
561 opt_stateful
562 : STATEFUL { $$ = NPF_RULE_STATEFUL; }
563 | { $$ = 0; }
564 ;
565
566 opt_apply
567 : APPLY STRING { $$ = $2; }
568 | { $$ = NULL; }
569 ;
570
571 block_opts
572 : RETURNRST { $$ = NPF_RULE_RETRST; }
573 | RETURNICMP { $$ = NPF_RULE_RETICMP; }
574 | RETURN { $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
575 | { $$ = 0; }
576 ;
577
578 filt_opts
579 : FROM filt_addr port_range TO filt_addr port_range
580 {
581 $$.fo_from.ap_netaddr = $2;
582 $$.fo_from.ap_portrange = $3;
583 $$.fo_to.ap_netaddr = $5;
584 $$.fo_to.ap_portrange = $6;
585 }
586 | FROM filt_addr port_range
587 {
588 $$.fo_from.ap_netaddr = $2;
589 $$.fo_from.ap_portrange = $3;
590 $$.fo_to.ap_netaddr = NULL;
591 $$.fo_to.ap_portrange = NULL;
592 }
593 | TO filt_addr port_range
594 {
595 $$.fo_from.ap_netaddr = NULL;
596 $$.fo_from.ap_portrange = NULL;
597 $$.fo_to.ap_netaddr = $2;
598 $$.fo_to.ap_portrange = $3;
599 }
600 ;
601
602 filt_addr
603 : addr_or_ifnet { $$ = $1; }
604 | TABLE_ID { $$ = npfctl_parse_table_id($1); }
605 | ANY { $$ = NULL; }
606 ;
607
608 addr_and_mask
609 : addr SLASH number
610 {
611 $$ = npfctl_parse_fam_addr_mask($1, NULL, &$3);
612 }
613 | addr SLASH addr
614 {
615 $$ = npfctl_parse_fam_addr_mask($1, $3, NULL);
616 }
617 | addr
618 {
619 $$ = npfctl_parse_fam_addr_mask($1, NULL, NULL);
620 }
621 ;
622
623 addr_or_ifnet
624 : addr_and_mask
625 {
626 assert($1 != NULL);
627 $$ = $1;
628 }
629 | ifnet
630 {
631 ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
632 $$ = ifna->ifna_addrs;
633 }
634 | VAR_ID
635 {
636 npfvar_t *vp = npfvar_lookup($1);
637 int type = npfvar_get_type(vp, 0);
638 ifnet_addr_t *ifna;
639
640 again:
641 switch (type) {
642 case NPFVAR_IDENTIFIER:
643 case NPFVAR_STRING:
644 vp = npfctl_parse_ifnet(npfvar_expand_string(vp),
645 AF_UNSPEC);
646 type = npfvar_get_type(vp, 0);
647 goto again;
648 case NPFVAR_FAM:
649 $$ = vp;
650 break;
651 case NPFVAR_INTERFACE:
652 ifna = npfvar_get_data(vp, type, 0);
653 $$ = ifna->ifna_addrs;
654 break;
655 case -1:
656 yyerror("undefined variable '%s'", $1);
657 break;
658 default:
659 yyerror("wrong variable '%s' type '%s' for address "
660 "or interface", $1, npfvar_type(type));
661 break;
662 }
663 }
664 ;
665
666 addr
667 : IPV4ADDR { $$ = $1; }
668 | IPV6ADDR { $$ = $1; }
669 ;
670
671 port_range
672 : PORT port /* just port */
673 {
674 $$ = npfctl_parse_port_range($2, $2);
675 }
676 | PORT port MINUS port /* port from-to */
677 {
678 $$ = npfctl_parse_port_range($2, $4);
679 }
680 | PORT VAR_ID
681 {
682 $$ = npfctl_parse_port_range_variable($2);
683 }
684 |
685 {
686 $$ = NULL;
687 }
688 ;
689
690 port
691 : number { $$ = $1; }
692 | IDENTIFIER { $$ = npfctl_portno($1); }
693 | STRING { $$ = npfctl_portno($1); }
694 ;
695
696 icmp_type_and_code
697 : ICMPTYPE icmp_type
698 {
699 $$ = npfctl_parse_icmp($<num>0, $2, -1);
700 }
701 | ICMPTYPE icmp_type CODE number
702 {
703 $$ = npfctl_parse_icmp($<num>0, $2, $4);
704 }
705 | ICMPTYPE icmp_type CODE IDENTIFIER
706 {
707 $$ = npfctl_parse_icmp($<num>0, $2,
708 npfctl_icmpcode($<num>0, $2, $4));
709 }
710 | ICMPTYPE icmp_type CODE VAR_ID
711 {
712 char *s = npfvar_expand_string(npfvar_lookup($4));
713 $$ = npfctl_parse_icmp($<num>0, $2,
714 npfctl_icmpcode($<num>0, $2, s));
715 }
716 | { $$ = NULL; }
717 ;
718
719 tcp_flags_and_mask
720 : FLAGS tcp_flags SLASH tcp_flags
721 {
722 npfvar_add_elements($2, $4);
723 $$ = $2;
724 }
725 | FLAGS tcp_flags
726 {
727 char *s = npfvar_get_data($2, NPFVAR_TCPFLAG, 0);
728 npfvar_add_elements($2, npfctl_parse_tcpflag(s));
729 $$ = $2;
730 }
731 | { $$ = NULL; }
732 ;
733
734 tcp_flags
735 : IDENTIFIER { $$ = npfctl_parse_tcpflag($1); }
736 ;
737
738 icmp_type
739 : number { $$ = $1; }
740 | IDENTIFIER { $$ = npfctl_icmptype($<num>-1, $1); }
741 | VAR_ID
742 {
743 char *s = npfvar_expand_string(npfvar_lookup($1));
744 $$ = npfctl_icmptype($<num>-1, s);
745 }
746 ;
747
748 string
749 : IDENTIFIER
750 {
751 $$ = $1;
752 }
753 | VAR_ID
754 {
755 npfvar_t *vp = npfvar_lookup($1);
756 const int type = npfvar_get_type(vp, 0);
757
758 switch (type) {
759 case NPFVAR_STRING:
760 case NPFVAR_IDENTIFIER:
761 $$ = npfvar_expand_string(vp);
762 break;
763 case -1:
764 yyerror("undefined variable '%s' for interface", $1);
765 break;
766 default:
767 yyerror("wrong variable '%s' type '%s' for string",
768 $1, npfvar_type(type));
769 break;
770 }
771 }
772 ;
773
774 ifnet
775 : IFNET PAR_OPEN string PAR_CLOSE
776 {
777 $$ = npfctl_parse_ifnet($3, AF_UNSPEC);
778 }
779 | afamily PAR_OPEN string PAR_CLOSE
780 {
781 $$ = npfctl_parse_ifnet($3, $1);
782 }
783 ;
784
785 ifname
786 : some_name
787 {
788 npfctl_note_interface($1);
789 $$ = $1;
790 }
791 | ifnet
792 {
793 ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
794 npfctl_note_interface(ifna->ifna_name);
795 $$ = ifna->ifna_name;
796 }
797 | VAR_ID
798 {
799 npfvar_t *vp = npfvar_lookup($1);
800 const int type = npfvar_get_type(vp, 0);
801 ifnet_addr_t *ifna;
802
803 switch (type) {
804 case NPFVAR_STRING:
805 case NPFVAR_IDENTIFIER:
806 $$ = npfvar_expand_string(vp);
807 break;
808 case NPFVAR_INTERFACE:
809 ifna = npfvar_get_data(vp, type, 0);
810 $$ = ifna->ifna_name;
811 break;
812 case -1:
813 yyerror("undefined variable '%s' for interface", $1);
814 break;
815 default:
816 yyerror("wrong variable '%s' type '%s' for interface",
817 $1, npfvar_type(type));
818 break;
819 }
820 npfctl_note_interface($$);
821 }
822 ;
823
824 number
825 : HEX { $$ = $1; }
826 | NUM { $$ = $1; }
827 ;
828
829 some_name
830 : IDENTIFIER { $$ = $1; }
831 | STRING { $$ = $1; }
832 ;
833
834 %%
835