Home | History | Annotate | Line # | Download | only in config
gram.y revision 1.30
      1 %{
      2 /*	$NetBSD: gram.y,v 1.30 2012/03/11 02:56:25 dholland Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1992, 1993
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * This software was developed by the Computer Systems Engineering group
      9  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
     10  * contributed to Berkeley.
     11  *
     12  * All advertising materials mentioning features or use of this software
     13  * must display the following acknowledgement:
     14  *	This product includes software developed by the University of
     15  *	California, Lawrence Berkeley Laboratories.
     16  *
     17  * Redistribution and use in source and binary forms, with or without
     18  * modification, are permitted provided that the following conditions
     19  * are met:
     20  * 1. Redistributions of source code must retain the above copyright
     21  *    notice, this list of conditions and the following disclaimer.
     22  * 2. Redistributions in binary form must reproduce the above copyright
     23  *    notice, this list of conditions and the following disclaimer in the
     24  *    documentation and/or other materials provided with the distribution.
     25  * 3. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  *	from: @(#)gram.y	8.1 (Berkeley) 6/6/93
     42  */
     43 
     44 #include <sys/types.h>
     45 #include <sys/param.h>
     46 #include <ctype.h>
     47 #include <stdio.h>
     48 #include <stdlib.h>
     49 #include <string.h>
     50 #include <errno.h>
     51 #include "defs.h"
     52 #include "sem.h"
     53 
     54 #define	FORMAT(n) (((n).fmt == 8 && (n).val != 0) ? "0%llo" : \
     55     ((n).fmt == 16) ? "0x%llx" : "%lld")
     56 
     57 #define	stop(s)	cfgerror(s), exit(1)
     58 
     59 static	struct	config conf;	/* at most one active at a time */
     60 
     61 /* the following is used to recover nvlist space after errors */
     62 static	struct	nvlist *alloc[1000];
     63 static	int	adepth;
     64 #define	new0(n,s,p,i,x)	(alloc[adepth++] = newnv(n, s, p, i, x))
     65 #define	new_n(n)	new0(n, NULL, NULL, 0, NULL)
     66 #define	new_nx(n, x)	new0(n, NULL, NULL, 0, x)
     67 #define	new_ns(n, s)	new0(n, s, NULL, 0, NULL)
     68 #define	new_si(s, i)	new0(NULL, s, NULL, i, NULL)
     69 #define	new_nsi(n,s,i)	new0(n, s, NULL, i, NULL)
     70 #define	new_np(n, p)	new0(n, NULL, p, 0, NULL)
     71 #define	new_s(s)	new0(NULL, s, NULL, 0, NULL)
     72 #define	new_p(p)	new0(NULL, NULL, p, 0, NULL)
     73 #define	new_px(p, x)	new0(NULL, NULL, p, 0, x)
     74 #define	new_sx(s, x)	new0(NULL, s, NULL, 0, x)
     75 #define	new_nsx(n,s,x)	new0(n, s, NULL, 0, x)
     76 #define	new_i(i)	new0(NULL, NULL, NULL, i, NULL)
     77 
     78 #define	fx_atom(s)	new0(s, NULL, NULL, FX_ATOM, NULL)
     79 #define	fx_not(e)	new0(NULL, NULL, NULL, FX_NOT, e)
     80 #define	fx_and(e1, e2)	new0(NULL, NULL, e1, FX_AND, e2)
     81 #define	fx_or(e1, e2)	new0(NULL, NULL, e1, FX_OR, e2)
     82 
     83 static	void	cleanup(void);
     84 static	void	setmachine(const char *, const char *, struct nvlist *, int);
     85 static	void	check_maxpart(void);
     86 
     87 static	void	app(struct nvlist *, struct nvlist *);
     88 
     89 static	struct nvlist *mk_nsis(const char *, int, struct nvlist *, int);
     90 static	struct nvlist *mk_ns(const char *, struct nvlist *);
     91 
     92 %}
     93 
     94 %union {
     95 	struct	attr *attr;
     96 	struct	devbase *devb;
     97 	struct	deva *deva;
     98 	struct	nvlist *list;
     99 	const char *str;
    100 	struct	numconst num;
    101 	int64_t	val;
    102 }
    103 
    104 %token	AND AT ATTACH
    105 %token	BLOCK BUILD
    106 %token	CHAR COLONEQ COMPILE_WITH CONFIG
    107 %token	DEFFS DEFINE DEFOPT DEFPARAM DEFFLAG DEFPSEUDO DEFPSEUDODEV
    108 %token	DEVICE DEVCLASS DUMPS DEVICE_MAJOR
    109 %token	ENDFILE
    110 %token	XFILE FILE_SYSTEM FLAGS
    111 %token	IDENT IOCONF
    112 %token	LINKZERO
    113 %token	XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR
    114 %token	NEEDS_COUNT NEEDS_FLAG NO
    115 %token	XOBJECT OBSOLETE ON OPTIONS
    116 %token	PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE PSEUDO_ROOT
    117 %token	ROOT
    118 %token	SINGLE SOURCE
    119 %token	TYPE
    120 %token	VECTOR VERSION
    121 %token	WITH
    122 %token	<num> NUMBER
    123 %token	<str> PATHNAME QSTRING WORD EMPTYSTRING
    124 %token	ENDDEFS
    125 
    126 %type	<list>	fopts fexpr fatom
    127 %type	<list>	f_or_expr f_and_expr f_prefix_expr f_base_expr
    128 %type	<str>	fs_spec
    129 %type	<val>	fflgs fflag oflgs oflag
    130 %type	<str>	rule
    131 %type	<attr>	attr
    132 %type	<devb>	devbase
    133 %type	<deva>	devattach_opt
    134 %type	<list>	atlist interface_opt
    135 %type	<str>	atname
    136 %type	<list>	loclist locdef
    137 %type	<str>	locdefault
    138 %type	<list>	values locdefaults
    139 %type	<list>	attrs_opt attrs
    140 %type	<list>	locators locator
    141 %type	<list>	dev_spec
    142 %type	<str>	device_instance
    143 %type	<str>	attachment
    144 %type	<str>	value
    145 %type	<val>	major_minor npseudo
    146 %type	<num>	signed_number
    147 %type	<val>	device_flags
    148 %type	<str>	deffs
    149 %type	<list>	deffses
    150 %type	<list>	defopt
    151 %type	<list>	defopts
    152 %type	<str>	optdep
    153 %type	<list>	optdeps
    154 %type	<list>	defoptdeps
    155 %type	<str>	optfile_opt
    156 %type	<list>	subarches
    157 %type	<str>	filename stringvalue locname mkvarname
    158 %type	<val>	device_major_block device_major_char
    159 %type	<list>	devnodes devnodetype devnodeflags devnode_dims
    160 
    161 %%
    162 
    163 /*
    164  * A complete configuration consists of both the configuration part (a
    165  * kernel config such as GENERIC or SKYNET, plus also the various
    166  * std.* files), which selects the material to be in the kernel, and
    167  * also the definition part (files, files.*, etc.) that declares what
    168  * material is available to be placed in kernels.
    169  *
    170  * The two parts have almost entirely separate syntaxes. This grammar
    171  * covers both of them. When config is run on a kernel configuration
    172  * file, the std.* file for the port is included explicitly. The
    173  * files.* files are included implicitly when the std.* file declares
    174  * the machine type.
    175  *
    176  * The machine spec, which brings in the definition part, must appear
    177  * before all configuration material except for the "topthings"; these
    178  * are the "source" and "build" declarations that tell config where
    179  * things are. These are not used by default.
    180  *
    181  * A previous version of this comment contained the following text:
    182  *
    183  *       Note that we do not have sufficient keywords to enforce any
    184  *       order between elements of "topthings" without introducing
    185  *       shift/reduce conflicts.  Instead, check order requirements in
    186  *       the C code.
    187  *
    188  * As of March 2012 this comment makes no sense, as there are only two
    189  * topthings and no reason for them to be forcibly ordered.
    190  * Furthermore, the statement about conflicts is false.
    191  */
    192 
    193 /* Complete configuration. */
    194 configuration:
    195 	topthings machine_spec definition_part configuration_part
    196 ;
    197 
    198 /* Sequence of zero or more topthings. */
    199 topthings:
    200 	  /* empty */
    201 	| topthings topthing
    202 ;
    203 
    204 /* Directory specification. */
    205 topthing:
    206 	                  '\n'
    207 	| SOURCE filename '\n'		{ if (!srcdir) srcdir = $2; }
    208 	| BUILD  filename '\n'		{ if (!builddir) builddir = $2; }
    209 ;
    210 
    211 /* "machine foo" from std.whatever */
    212 machine_spec:
    213 	  XMACHINE WORD '\n'			{ setmachine($2,NULL,NULL,0); }
    214 	| XMACHINE WORD WORD '\n'		{ setmachine($2,$3,NULL,0); }
    215 	| XMACHINE WORD WORD subarches '\n'	{ setmachine($2,$3,$4,0); }
    216 	| IOCONF WORD '\n'			{ setmachine($2,NULL,NULL,1); }
    217 	| error { stop("cannot proceed without machine or ioconf specifier"); }
    218 ;
    219 
    220 /* One or more sub-arches. */
    221 subarches:
    222 	  WORD				{ $$ = new_n($1); }
    223 	| subarches WORD		{ $$ = new_nx($2, $1); }
    224 ;
    225 
    226 /************************************************************/
    227 
    228 /*
    229  * The machine definitions grammar.
    230  */
    231 
    232 /* Complete definition part: the contents of all files.* files. */
    233 definition_part:
    234 	definitions ENDDEFS		{ check_maxpart(); check_version(); }
    235 ;
    236 
    237 /* Zero or more definitions. Trap errors. */
    238 definitions:
    239 	  /* empty */
    240 	| definitions '\n'
    241 	| definitions definition '\n'	{ adepth = 0; }
    242 	| definitions error '\n'	{ cleanup(); }
    243 	| definitions ENDFILE		{ enddefs(); checkfiles(); }
    244 ;
    245 
    246 /* A single definition. */
    247 definition:
    248 	  file
    249 	| object
    250 	| device_major			{ do_devsw = 1; }
    251 	| prefix
    252 	| DEVCLASS WORD			{ (void)defattr($2, NULL, NULL, 1); }
    253 	| DEFFS deffses defoptdeps	{ deffilesystem($2, $3); }
    254 	| DEFINE WORD interface_opt attrs_opt
    255 					{ (void)defattr($2, $3, $4, 0); }
    256 	| DEFOPT optfile_opt defopts defoptdeps
    257 					{ defoption($2, $3, $4); }
    258 	| DEFFLAG optfile_opt defopts defoptdeps
    259 					{ defflag($2, $3, $4, 0); }
    260 	| OBSOLETE DEFFLAG optfile_opt defopts
    261 					{ defflag($3, $4, NULL, 1); }
    262 	| DEFPARAM optfile_opt defopts defoptdeps
    263 					{ defparam($2, $3, $4, 0); }
    264 	| OBSOLETE DEFPARAM optfile_opt defopts
    265 					{ defparam($3, $4, NULL, 1); }
    266 	| DEVICE devbase interface_opt attrs_opt
    267 					{ defdev($2, $3, $4, 0); }
    268 	| ATTACH devbase AT atlist devattach_opt attrs_opt
    269 					{ defdevattach($5, $2, $4, $6); }
    270 	| MAXPARTITIONS NUMBER		{ maxpartitions = $2.val; }
    271 	| MAXUSERS NUMBER NUMBER NUMBER
    272 				    { setdefmaxusers($2.val, $3.val, $4.val); }
    273 	| MAKEOPTIONS condmkopt_list
    274 	/* interface_opt in DEFPSEUDO is for backwards compatibility */
    275 	| DEFPSEUDO devbase interface_opt attrs_opt
    276 					{ defdev($2, $3, $4, 1); }
    277 	| DEFPSEUDODEV devbase interface_opt attrs_opt
    278 					{ defdev($2, $3, $4, 2); }
    279 	| MAJOR '{' majorlist '}'
    280 	| VERSION NUMBER		{ setversion($2.val); }
    281 ;
    282 
    283 /* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
    284 file:
    285 	XFILE filename fopts fflgs rule	{ addfile($2, $3, $4, $5); }
    286 ;
    287 
    288 /* file options: optional expression of config elements */
    289 fopts:
    290 	  /* empty */			{ $$ = NULL; }
    291 	| fexpr				{ $$ = $1; }
    292 ;
    293 
    294 /* zero or more flags for a file */
    295 fflgs:
    296 	  /* empty */			{ $$ = 0; }
    297 	| fflgs fflag			{ $$ = $1 | $2; }
    298 ;
    299 
    300 /* one flag for a file */
    301 fflag:
    302 	  NEEDS_COUNT			{ $$ = FI_NEEDSCOUNT; }
    303 	| NEEDS_FLAG			{ $$ = FI_NEEDSFLAG; }
    304 ;
    305 
    306 /* extra compile directive for a source file */
    307 rule:
    308 	  /* empty */			{ $$ = NULL; }
    309 	| COMPILE_WITH stringvalue	{ $$ = $2; }
    310 ;
    311 
    312 /* object file: object zot.o foo|zot needs-flag */
    313 object:
    314 	XOBJECT filename fopts oflgs	{ addobject($2, $3, $4); }
    315 ;
    316 
    317 /* zero or more flags for an object file */
    318 oflgs:
    319 	  /* empty */			{ $$ = 0; }
    320 	| oflgs oflag			{ $$ = $1 | $2; }
    321 ;
    322 
    323 /* a single flag for an object file */
    324 oflag:
    325 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; }
    326 ;
    327 
    328 /* device major declaration */
    329 device_major:
    330 	DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
    331 					{ adddevm($2, $3, $4, $5, $6); }
    332 ;
    333 
    334 /* char 55 */
    335 device_major_char:
    336 	  /* empty */			{ $$ = -1; }
    337 	| CHAR NUMBER			{ $$ = $2.val; }
    338 ;
    339 
    340 /* block 33 */
    341 device_major_block:
    342 	  /* empty */			{ $$ = -1; }
    343 	| BLOCK NUMBER			{ $$ = $2.val; }
    344 ;
    345 
    346 /* device node specification */
    347 devnodes:
    348 	  /* empty */			{ $$ = new_s("DEVNODE_DONTBOTHER"); }
    349 	| devnodetype ',' devnodeflags	{ $$ = nvcat($1, $3); }
    350 	| devnodetype			{ $$ = $1; }
    351 ;
    352 
    353 /* device nodes without flags */
    354 devnodetype:
    355 	  SINGLE			{ $$ = new_s("DEVNODE_SINGLE"); }
    356 	| VECTOR '=' devnode_dims  { $$ = nvcat(new_s("DEVNODE_VECTOR"), $3); }
    357 ;
    358 
    359 /* dimensions (?) */
    360 devnode_dims:
    361 	  NUMBER			{ $$ = new_i($1.val); }
    362 	| NUMBER ':' NUMBER		{
    363 		struct nvlist *__nv1, *__nv2;
    364 
    365 		__nv1 = new_i($1.val);
    366 		__nv2 = new_i($3.val);
    367 		$$ = nvcat(__nv1, __nv2);
    368 	  }
    369 ;
    370 
    371 /* flags for device nodes */
    372 devnodeflags:
    373 	LINKZERO			{ $$ = new_s("DEVNODE_FLAG_LINKZERO");}
    374 ;
    375 
    376 /* prefix delimiter */
    377 prefix:
    378 	  PREFIX filename		{ prefix_push($2); }
    379 	| PREFIX			{ prefix_pop(); }
    380 ;
    381 
    382 /* one or more file system names */
    383 deffses:
    384 	  deffs				{ $$ = new_n($1); }
    385 	| deffses deffs			{ $$ = new_nx($2, $1); }
    386 ;
    387 
    388 /* a single file system name */
    389 deffs:
    390 	WORD				{ $$ = $1; }
    391 ;
    392 
    393 /* optional locator specification */
    394 interface_opt:
    395 	  /* empty */			{ $$ = NULL; }
    396 	| '{' '}'			{ $$ = new_nx("", NULL); }
    397 	| '{' loclist '}'		{ $$ = new_nx("", $2); }
    398 ;
    399 
    400 /*
    401  * loclist order matters, must use right recursion
    402  * XXX wot?
    403  */
    404 
    405 /* list of locator definitions */
    406 loclist:
    407 	  locdef			{ $$ = $1; }
    408 	| locdef ',' loclist		{ $$ = $1; app($1, $3); }
    409 ;
    410 
    411 /*
    412  * "[ WORD locdefault ]" syntax may be unnecessary...
    413  */
    414 
    415 /* one locator definition */
    416 locdef:
    417 	  locname locdefault 		{ $$ = new_nsi($1, $2, 0); }
    418 	| locname			{ $$ = new_nsi($1, NULL, 0); }
    419 	| '[' locname locdefault ']'	{ $$ = new_nsi($2, $3, 1); }
    420 	| locname '[' NUMBER ']'	{ $$ = mk_nsis($1, $3.val, NULL, 0); }
    421 	| locname '[' NUMBER ']' locdefaults
    422 					{ $$ = mk_nsis($1, $3.val, $5, 0); }
    423 	| '[' locname '[' NUMBER ']' locdefaults ']'
    424 					{ $$ = mk_nsis($2, $4.val, $6, 1); }
    425 ;
    426 
    427 /* locator name */
    428 locname:
    429 	  WORD				{ $$ = $1; }
    430 	| QSTRING			{ $$ = $1; }
    431 ;
    432 
    433 /* locator default value */
    434 locdefault:
    435 	'=' value			{ $$ = $2; }
    436 ;
    437 
    438 /* multiple locator default values */
    439 locdefaults:
    440 	'=' '{' values '}'		{ $$ = $3; }
    441 ;
    442 
    443 /* optional attributes */
    444 attrs_opt:
    445 	  /* empty */			{ $$ = NULL; }
    446 	| ':' attrs			{ $$ = $2; }
    447 ;
    448 
    449 /* one or more attributes */
    450 attrs:
    451 	  attr				{ $$ = new_p($1); }
    452 	| attrs ',' attr		{ $$ = new_px($3, $1); }
    453 ;
    454 
    455 /* one attribute */
    456 attr:
    457 	WORD				{ $$ = getattr($1); }
    458 ;
    459 
    460 /* list of places to attach: attach blah at ... */
    461 atlist:
    462 	  atname			{ $$ = new_n($1); }
    463 	| atlist ',' atname		{ $$ = new_nx($3, $1); }
    464 ;
    465 
    466 /* a place to attach a device */
    467 atname:
    468 	  WORD				{ $$ = $1; }
    469 	| ROOT				{ $$ = NULL; }
    470 ;
    471 
    472 /* one or more defined options */
    473 defopts:
    474 	  defopt			{ $$ = $1; }
    475 	| defopts defopt		{ $$ = nvcat($2, $1); }
    476 ;
    477 
    478 /* one defined option */
    479 defopt:
    480 	  WORD				{ $$ = new_n($1); }
    481 	| WORD '=' value		{ $$ = new_ns($1, $3); }
    482 	| WORD COLONEQ value		{
    483 		struct nvlist *__nv = new_n($1);
    484 
    485 		$$ = new_nsx("", $3, __nv);
    486 	  }
    487 	| WORD '=' value COLONEQ value	{
    488 		struct nvlist *__nv = new_n($1);
    489 
    490 		$$ = new_nsx("", $5, __nv);
    491 	  }
    492 ;
    493 
    494 /* option dependencies (read as "defopt deps") which are optional */
    495 defoptdeps:
    496 	  /* empty */			{ $$ = NULL; }
    497 	| ':' optdeps			{ $$ = $2; }
    498 ;
    499 
    500 /* a list of option dependencies */
    501 optdeps:
    502 	  optdep			{ $$ = new_n($1); }
    503 	| optdeps ',' optdep		{ $$ = new_nx($3, $1); }
    504 ;
    505 
    506 /* one option dependence */
    507 optdep:
    508 	WORD				{ $$ = $1; }
    509 ;
    510 
    511 /* list of conditional makeoptions */
    512 condmkopt_list:
    513 	  condmkoption
    514 	| condmkopt_list ',' condmkoption
    515 ;
    516 
    517 /* one conditional make option */
    518 condmkoption:
    519 	fexpr mkvarname PLUSEQ value	{ appendcondmkoption($1, $2, $4); }
    520 ;
    521 
    522 /* device name */
    523 devbase:
    524 	WORD				{ $$ = getdevbase($1); }
    525 ;
    526 
    527 /* optional attachment: with foo */
    528 devattach_opt:
    529 	  /* empty */			{ $$ = NULL; }
    530 	| WITH WORD			{ $$ = getdevattach($2); }
    531 ;
    532 
    533 /* list of major numbers */
    534 /* XXX why is this right-recursive? */
    535 majorlist:
    536 	  majordef
    537 	| majorlist ',' majordef
    538 ;
    539 
    540 /* one major number */
    541 majordef:
    542 	devbase '=' NUMBER		{ setmajor($1, $3.val); }
    543 ;
    544 
    545 /************************************************************/
    546 
    547 /*
    548  * The configuration grammar.
    549  */
    550 
    551 /* Complete configuration part: all std.* files plus selected config. */
    552 configuration_part:
    553 	config_items
    554 ;
    555 
    556 /* Zero or more config items. Trap errors. */
    557 config_items:
    558 	  /* empty */
    559 	| config_items '\n'
    560 	| config_items config_item '\n'	{ adepth = 0; }
    561 	| config_items error '\n'	{ cleanup(); }
    562 ;
    563 
    564 /* One config item. */
    565 config_item:
    566 	  definition
    567 	| NO FILE_SYSTEM no_fs_list
    568 	| FILE_SYSTEM fs_list
    569 	| NO MAKEOPTIONS no_mkopt_list
    570 	| MAKEOPTIONS mkopt_list
    571 	| NO OPTIONS no_opt_list
    572 	| OPTIONS opt_list
    573 	| MAXUSERS NUMBER		{ setmaxusers($2.val); }
    574 	| IDENT stringvalue		{ setident($2); }
    575 	| CONFIG conf root_spec sysparam_list
    576 					{ addconf(&conf); }
    577 	| NO CONFIG WORD		{ delconf($3); }
    578 	| NO PSEUDO_DEVICE WORD		{ delpseudo($3); }
    579 	| PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); }
    580 	| PSEUDO_ROOT device_instance	{ addpseudoroot($2); }
    581 	| NO device_instance AT attachment
    582 					{ deldevi($2, $4); }
    583 	| NO DEVICE AT attachment	{ deldeva($4); }
    584 	| NO device_instance		{ deldev($2); }
    585 	| device_instance AT attachment locators device_flags
    586 					{ adddev($1, $3, $4, $5); }
    587 ;
    588 
    589 /* list of filesystems */
    590 fs_list:
    591 	  fsoption
    592 	| fs_list ',' fsoption
    593 ;
    594 
    595 /* one filesystem */
    596 fsoption:
    597 	WORD				{ addfsoption($1); }
    598 ;
    599 
    600 /* list of filesystems that had NO in front */
    601 no_fs_list:
    602 	  no_fsoption
    603 	| no_fs_list ',' no_fsoption
    604 ;
    605 
    606 /* one filesystem that had NO in front */
    607 no_fsoption:
    608 	WORD				{ delfsoption($1); }
    609 ;
    610 
    611 /* list of make options */
    612 /* XXX why is this right-recursive? */
    613 mkopt_list:
    614 	  mkoption
    615 	| mkopt_list ',' mkoption
    616 ;
    617 
    618 /* one make option */
    619 mkoption:
    620 	  mkvarname '=' value		{ addmkoption($1, $3); }
    621 	| mkvarname PLUSEQ value	{ appendmkoption($1, $3); }
    622 ;
    623 
    624 /* list of make options that had NO in front */
    625 no_mkopt_list:
    626 	  no_mkoption
    627 	| no_mkopt_list ',' no_mkoption
    628 ;
    629 
    630 /* one make option that had NO in front */
    631 /* XXX shouldn't this be mkvarname rather than WORD? */
    632 no_mkoption:
    633 	WORD				{ delmkoption($1); }
    634 ;
    635 
    636 /* list of options */
    637 opt_list:
    638 	  option
    639 	| opt_list ',' option
    640 ;
    641 
    642 /* one option */
    643 option:
    644 	  WORD				{ addoption($1, NULL); }
    645 	| WORD '=' value		{ addoption($1, $3); }
    646 ;
    647 
    648 /* list of options that had NO in front */
    649 no_opt_list:
    650 	  no_option
    651 	| no_opt_list ',' no_option
    652 ;
    653 
    654 /* one option that had NO in front */
    655 no_option:
    656 	WORD				{ deloption($1); }
    657 ;
    658 
    659 /* the name in "config name root on ..." */
    660 conf:
    661 	WORD				{
    662 		conf.cf_name = $1;
    663 		conf.cf_lineno = currentline();
    664 		conf.cf_fstype = NULL;
    665 		conf.cf_root = NULL;
    666 		conf.cf_dump = NULL;
    667 	}
    668 ;
    669 
    670 /* root fs specification */
    671 root_spec:
    672 	  ROOT on_opt dev_spec		{ setconf(&conf.cf_root, "root", $3); }
    673 	| ROOT on_opt dev_spec fs_spec	{ setconf(&conf.cf_root, "root", $3); }
    674 ;
    675 
    676 /* device for root fs or dump */
    677 dev_spec:
    678 	  '?'				{ $$ = new_si(intern("?"), NODEV); }
    679 	| WORD				{ $$ = new_si($1, NODEV); }
    680 	| major_minor			{ $$ = new_si(NULL, $1); }
    681 ;
    682 
    683 /* major and minor device number */
    684 major_minor:
    685 	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2.val, $4.val); }
    686 ;
    687 
    688 /* filesystem type for root fs specification */
    689 fs_spec:
    690 	  TYPE '?'		   { setfstype(&conf.cf_fstype, intern("?")); }
    691 	| TYPE WORD			{ setfstype(&conf.cf_fstype, $2); }
    692 ;
    693 
    694 /* zero or more additional system parameters */
    695 sysparam_list:
    696 	  /* empty */
    697 	| sysparam_list sysparam
    698 ;
    699 
    700 /* one additional system parameter (there's only one: dumps) */
    701 sysparam:
    702 	DUMPS on_opt dev_spec	       { setconf(&conf.cf_dump, "dumps", $3); }
    703 ;
    704 
    705 /* number of pseudo devices to configure (which is optional) */
    706 npseudo:
    707 	  /* empty */			{ $$ = 1; }
    708 	| NUMBER			{ $$ = $1.val; }
    709 ;
    710 
    711 /* name of a device to configure */
    712 device_instance:
    713 	  WORD				{ $$ = $1; }
    714 	| WORD '*'			{ $$ = starref($1); }
    715 ;
    716 
    717 /* name of a device to configure an attachment to */
    718 attachment:
    719 	  ROOT				{ $$ = NULL; }
    720 	| WORD				{ $$ = $1; }
    721 	| WORD '?'			{ $$ = wildref($1); }
    722 ;
    723 
    724 /* zero or more locators */
    725 locators:
    726 	  /* empty */			{ $$ = NULL; }
    727 	| locators locator		{ $$ = $2; app($2, $1); }
    728 ;
    729 
    730 /* one locator */
    731 locator:
    732 	  WORD '?'			{ $$ = new_ns($1, NULL); }
    733 	| WORD values			{ $$ = mk_ns($1, $2); }
    734 ;
    735 
    736 /* optional device flags */
    737 device_flags:
    738 	  /* empty */			{ $$ = 0; }
    739 	| FLAGS NUMBER			{ $$ = $2.val; }
    740 ;
    741 
    742 /************************************************************/
    743 
    744 /*
    745  * dependency logic
    746  */
    747 
    748 
    749 /*
    750  * order of options is important, must use right recursion
    751  *
    752  * dholland 20120310: wut?
    753  */
    754 
    755 /* expression of config elements */
    756 fexpr:
    757 	f_or_expr
    758 ;
    759 
    760 f_or_expr:
    761 	  f_and_expr
    762 	| f_or_expr '|' f_and_expr	{ $$ = fx_or($1, $3); }
    763 ;
    764 
    765 f_and_expr:
    766 	  f_prefix_expr
    767 	| f_and_expr '&' f_prefix_expr	{ $$ = fx_and($1, $3); }
    768 ;
    769 
    770 f_prefix_expr:
    771 	  f_base_expr
    772 /* XXX notyet - need to strengthen downstream first */
    773 /*	| '!' f_prefix_expr		{ $$ = fx_not($2); } */
    774 ;
    775 
    776 f_base_expr:
    777 	  fatom				{ $$ = $1; }
    778 	| '!' fatom			{ $$ = fx_not($2); }
    779 	| '(' fexpr ')'			{ $$ = $2; }
    780 ;
    781 
    782 /* basic element of config element expression: a config element */
    783 fatom:
    784 	WORD				{ $$ = fx_atom($1); }
    785 ;
    786 
    787 /************************************************************/
    788 
    789 /*
    790  * Various nonterminals shared between the grammars.
    791  */
    792 
    793 /* variable name for make option */
    794 mkvarname:
    795 	  QSTRING			{ $$ = $1; }
    796 	| WORD				{ $$ = $1; }
    797 ;
    798 
    799 /* optional file for an option */
    800 optfile_opt:
    801 	  /* empty */			{ $$ = NULL; }
    802 	| filename			{ $$ = $1; }
    803 ;
    804 
    805 /* filename. */
    806 filename:
    807 	  QSTRING			{ $$ = $1; }
    808 	| PATHNAME			{ $$ = $1; }
    809 ;
    810 
    811 /* constant value */
    812 value:
    813 	  QSTRING			{ $$ = $1; }
    814 	| WORD				{ $$ = $1; }
    815 	| EMPTYSTRING			{ $$ = $1; }
    816 	| signed_number			{
    817 		char bf[40];
    818 
    819 		(void)snprintf(bf, sizeof(bf), FORMAT($1), (long long)$1.val);
    820 		$$ = intern(bf);
    821 	  }
    822 ;
    823 
    824 /* constant value that is a string */
    825 stringvalue:
    826 	  QSTRING			{ $$ = $1; }
    827 	| WORD				{ $$ = $1; }
    828 ;
    829 
    830 /* comma-separated list of values */
    831 /* XXX why right-recursive? */
    832 values:
    833 	  value				{ $$ = new_s($1); }
    834 	| value ',' values		{ $$ = new_sx($1, $3); }
    835 ;
    836 
    837 /* possibly negative number */
    838 signed_number:
    839 	  NUMBER			{ $$ = $1; }
    840 	| '-' NUMBER			{ $$.fmt = $2.fmt; $$.val = -$2.val; }
    841 ;
    842 
    843 /* optional ON keyword */
    844 on_opt:
    845 	  /* empty */
    846 	| ON
    847 ;
    848 
    849 %%
    850 
    851 void
    852 yyerror(const char *s)
    853 {
    854 
    855 	cfgerror("%s", s);
    856 }
    857 
    858 /*
    859  * Cleanup procedure after syntax error: release any nvlists
    860  * allocated during parsing the current line.
    861  */
    862 static void
    863 cleanup(void)
    864 {
    865 	struct nvlist **np;
    866 	int i;
    867 
    868 	for (np = alloc, i = adepth; --i >= 0; np++)
    869 		nvfree(*np);
    870 	adepth = 0;
    871 }
    872 
    873 static void
    874 setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches,
    875 	int isioconf)
    876 {
    877 	char buf[MAXPATHLEN];
    878 	struct nvlist *nv;
    879 
    880 	if (isioconf) {
    881 		fprintf(stderr, "WARNING: ioconf is an experimental feature\n");
    882 		if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    883 			exit(1);
    884 		ioconfname = mch;
    885 		return;
    886 	}
    887 
    888 	machine = mch;
    889 	machinearch = mcharch;
    890 	machinesubarches = mchsubarches;
    891 
    892 	/*
    893 	 * Define attributes for all the given names
    894 	 */
    895 	if (defattr(machine, NULL, NULL, 0) != 0 ||
    896 	    (machinearch != NULL &&
    897 	     defattr(machinearch, NULL, NULL, 0) != 0))
    898 		exit(1);
    899 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    900 		if (defattr(nv->nv_name, NULL, NULL, 0) != 0)
    901 			exit(1);
    902 	}
    903 
    904 	/*
    905 	 * Set up the file inclusion stack.  This empty include tells
    906 	 * the parser there are no more device definitions coming.
    907 	 */
    908 	if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0)
    909 		exit(1);
    910 
    911 	/* Include arch/${MACHINE}/conf/files.${MACHINE} */
    912 	(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    913 	    machine, machine);
    914 	if (include(buf, ENDFILE, 0, 0) != 0)
    915 		exit(1);
    916 
    917 	/* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */
    918 	for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
    919 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    920 		    nv->nv_name, nv->nv_name);
    921 		if (include(buf, ENDFILE, 0, 0) != 0)
    922 			exit(1);
    923 	}
    924 
    925 	/* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */
    926 	if (machinearch != NULL)
    927 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s",
    928 		    machinearch, machinearch);
    929 	else
    930 		strlcpy(buf, _PATH_DEVNULL, sizeof(buf));
    931 	if (include(buf, ENDFILE, 0, 0) != 0)
    932 		exit(1);
    933 
    934 	/*
    935 	 * Include the global conf/files.  As the last thing
    936 	 * pushed on the stack, it will be processed first.
    937 	 */
    938 	if (include("conf/files", ENDFILE, 0, 0) != 0)
    939 		exit(1);
    940 
    941 	oktopackage = 1;
    942 }
    943 
    944 static void
    945 check_maxpart(void)
    946 {
    947 
    948 	if (maxpartitions <= 0 && ioconfname == NULL) {
    949 		stop("cannot proceed without maxpartitions specifier");
    950 	}
    951 }
    952 
    953 static void
    954 check_version(void)
    955 {
    956 	/*
    957 	 * In essence, version is 0 and is not supported anymore
    958 	 */
    959 	if (version < CONFIG_MINVERSION)
    960 		stop("your sources are out of date -- please update.");
    961 }
    962 
    963 static void
    964 app(struct nvlist *p, struct nvlist *q)
    965 {
    966 	while (p->nv_next)
    967 		p = p->nv_next;
    968 	p->nv_next = q;
    969 }
    970 
    971 static struct nvlist *
    972 mk_nsis(const char *name, int count, struct nvlist *adefs, int opt)
    973 {
    974 	struct nvlist *defs = adefs;
    975 	struct nvlist **p;
    976 	char buf[200];
    977 	int i;
    978 
    979 	if (count <= 0) {
    980 		fprintf(stderr, "config: array with <= 0 size: %s\n", name);
    981 		exit(1);
    982 	}
    983 	p = &defs;
    984 	for(i = 0; i < count; i++) {
    985 		if (*p == NULL)
    986 			*p = new_s("0");
    987 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
    988 		(*p)->nv_name = i == 0 ? name : intern(buf);
    989 		(*p)->nv_num = i > 0 || opt;
    990 		p = &(*p)->nv_next;
    991 	}
    992 	*p = 0;
    993 	return defs;
    994 }
    995 
    996 
    997 static struct nvlist *
    998 mk_ns(const char *name, struct nvlist *vals)
    999 {
   1000 	struct nvlist *p;
   1001 	char buf[200];
   1002 	int i;
   1003 
   1004 	for(i = 0, p = vals; p; i++, p = p->nv_next) {
   1005 		snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i);
   1006 		p->nv_name = i == 0 ? name : intern(buf);
   1007 	}
   1008 	return vals;
   1009 }
   1010 
   1011