1/*	$NetBSD: npf_parse.y,v 1.3.2.11 2013/02/11 21:49:47 riz 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
43int			yyparsetarget;
44const char *		yyfilename;
45
46extern int		yylineno, yycolumn;
47extern int		yylex(void);
48
49/* Variable under construction (bottom up). */
50static npfvar_t *	cvar;
51
52void
53yyerror(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
182input
183	: { CHECK_PARSER_FILE	} lines
184	| { CHECK_PARSER_STRING	} rule
185	;
186
187lines
188	: line SEPLINE lines
189	| line
190	;
191
192line
193	: def
194	| table
195	| map
196	| group
197	| rproc
198	|
199	;
200
201def
202	: VAR_ID
203	{
204		cvar = npfvar_create($1);
205		npfvar_add(cvar);
206	}
207	  EQ definition
208	{
209		cvar = NULL;
210	}
211	;
212
213definition
214	: list_elem
215	| listdef
216	;
217
218listdef
219	: CURLY_OPEN list_elems CURLY_CLOSE
220	;
221
222list_elems
223	: list_elem COMMA list_elems
224	| list_elem
225	;
226
227list_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
267table
268	: TABLE TABLE_ID TYPE table_type table_store
269	{
270		npfctl_build_table($2, $4, $5);
271	}
272	;
273
274table_type
275	: HASH		{ $$ = NPF_TABLE_HASH; }
276	| TREE		{ $$ = NPF_TABLE_TREE; }
277	;
278
279table_store
280	: TDYNAMIC	{ $$ = NULL; }
281	| TFILE STRING	{ $$ = $2; }
282	;
283
284map_sd
285	: TSTATIC	{ $$ = NPFCTL_NAT_STATIC; }
286	| TDYNAMIC	{ $$ = NPFCTL_NAT_DYNAMIC; }
287	|		{ $$ = NPFCTL_NAT_DYNAMIC; }
288	;
289
290map_type
291	: ARROWBOTH	{ $$ = NPF_NATIN | NPF_NATOUT; }
292	| ARROWLEFT	{ $$ = NPF_NATIN; }
293	| ARROWRIGHT	{ $$ = NPF_NATOUT; }
294	;
295
296mapseg
297	: addr_or_ifnet port_range
298	{
299		$$.ap_netaddr = $1;
300		$$.ap_portrange = $2;
301	}
302	;
303
304map
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
315rproc
316	: PROCEDURE STRING CURLY_OPEN procs CURLY_CLOSE
317	{
318		npfctl_build_rproc($2, $4);
319	}
320	;
321
322procs
323	: proc_call SEPLINE procs
324	{
325		$$ = npfvar_add_elements($1, $3);
326	}
327	| proc_call	{ $$ = $1; }
328	;
329
330proc_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
343proc_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
352proc_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
365proc_param_val
366	: some_name	{ $$ = $1; }
367	| NUM		{ (void)asprintf(&$$, "%ld", $1); }
368	| FPNUM		{ (void)asprintf(&$$, "%lf", $1); }
369	|		{ $$ = NULL; }
370	;
371
372group
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
386group_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
412group_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
445ruleset_block
446	: CURLY_OPEN ruleset CURLY_CLOSE
447	| /* Empty (for a dynamic ruleset). */
448	;
449
450ruleset
451	: rule_group SEPLINE ruleset
452	| rule_group
453	;
454
455rule_group
456	: rule
457	| group
458	|
459
460rule
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
469block_or_pass
470	: BLOCK block_opts	{ $$ = $2; }
471	| PASS			{ $$ = NPF_RULE_PASS; }
472	;
473
474rule_dir
475	: IN			{ $$ = NPF_RULE_IN; }
476	| OUT			{ $$ = NPF_RULE_OUT; }
477	|			{ $$ = NPF_RULE_IN | NPF_RULE_OUT; }
478	;
479
480opt_final
481	: FINAL			{ $$ = NPF_RULE_FINAL; }
482	|			{ $$ = 0; }
483	;
484
485on_ifindex
486	: ON ifindex		{ $$ = $2; }
487	|			{ $$ = 0; }
488	;
489
490afamily
491	: INET			{ $$ = AF_INET; }
492	| INET6			{ $$ = AF_INET6; }
493	;
494
495opt_family
496	: FAMILY afamily	{ $$ = $2; }
497	|			{ $$ = AF_UNSPEC; }
498	;
499
500opt_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
533all_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
544opt_stateful
545	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
546	|		{ $$ = 0; }
547	;
548
549opt_apply
550	: APPLY STRING	{ $$ = $2; }
551	|		{ $$ = NULL; }
552	;
553
554block_opts
555	: RETURNRST	{ $$ = NPF_RULE_RETRST; }
556	| RETURNICMP	{ $$ = NPF_RULE_RETICMP; }
557	| RETURN	{ $$ = NPF_RULE_RETRST | NPF_RULE_RETICMP; }
558	|		{ $$ = 0; }
559	;
560
561filt_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
585filt_addr
586	: addr_or_ifnet		{ $$ = $1; }
587	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
588	| ANY			{ $$ = NULL; }
589	;
590
591addr_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
610addr_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
627again:
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
653addr
654	: IPV4ADDR	{ $$ = $1; }
655	| IPV6ADDR	{ $$ = $1; }
656	;
657
658port_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
677port
678	: NUM		{ $$ = $1; }
679	| IDENTIFIER	{ $$ = npfctl_portno($1); }
680	| STRING	{ $$ = npfctl_portno($1); }
681	;
682
683icmp_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
709tcp_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
724tcp_flags
725	: IDENTIFIER	{ $$ = npfctl_parse_tcpflag($1); }
726	;
727
728icmp_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
738string
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
764ifnet
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
775ifindex
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
811some_name
812	: IDENTIFIER	{ $$ = $1; }
813	| STRING	{ $$ = $1; }
814	;
815
816%%
817